Metodyka

Skąd bierzemy dane, co z nimi robimy i czego nie wiemy. Źródła, ograniczenia i cały pipeline krok po kroku.

Żabkozbiór to niezależny projekt fanowski/analityczny oparty na danych publicznych. Nie jest powiązany z Żabka Polska sp. z o.o. ani Żabka Group. Nazwa "Żabka" i powiązane znaki towarowe należą do ich właścicieli.

Źródła danych

Żabka – główne źródło

Lokalizacje sklepów pochodzą z publicznego pliku JSON na Żabka.pl - to ten sam plik, z którego korzysta sklepowa wyszukiwarka na ich stronie. Plik ma około 13 200 sklepów, każdy ze współrzędnymi GPS, adresem, godzinami otwarcia i flagami (piec Merrychef, otwarte w niedzielę, 24/7). Z pliku wyrzucamy dane osobowe dyrektorów, stałe pola (kraj, aktywność) i marketingowe URLe. Zostają same dane analityczne.

Podział administracyjny i mapowanie

Strukturę podziału terytorialnego Polski (trzy poziomy: województwa, powiaty i gminy) budujemy bezpośrednio z oficjalnych rejestrów GUS BDL oraz TERYT jako pierwszy krok procesu ETL. Sklepy oraz paczkomaty przypisujemy do tej hierarchii relacyjnie na podstawie ich nazw miejscowości, z wykorzystaniem oficjalnej Uniwersalnej Usługi Geokodowania GUGiK do jednoznacznego rozstrzygania przynależności mniejszych miejscowości i wsi, wraz z zapasowym dopasowaniem przestrzennym. Eliminuje to potrzebę stosowania uproszczonych plików GeoJSON i powolnych testów punkt-w-poligon.

Gospodarka – GUS BDL

Zarobki, bezrobocie i populacja na poziomie powiatów pochodzą z Banku Danych Lokalnych (zmienne 64428, 60270, 72305). Pobieramy je raz w roku. Nazwy powiatów trzeba normalizować – GUS lubi dodawać prefiksy (Powiat m.), przyrostki czasowe (od 2023) i zmieniać nazwy (jeleniogórski staje się karkonoski w 2021). Wszystko to czyścimy przed zmatchowaniem. Dokładność: dane pochodzą z roku, w którym GUS je opublikował, nie z bieżącego miesiąca.

Parki narodowe i krajobrazowe – GDOŚ

Granice parków i ich otulin pobieramy z WFS GDOŚ (warstwy ParkiNarodowe + ParkiKrajobrazowe). Mamy 259 obiektów: 0 parków narodowych z otulinami i 0 krajobrazowych. Każdy sklep sprawdzamy point-in-poligon. Jeśli trafił do parku lub otuliny, dostaje flagę.

Wysokość terenu – GUGiK NMT

Wysokość n.p.m. z Numerycznego Modelu Terenu GUGiK (GetHByXY, współrzędne PL-1992). Wyniki trafiają do lokalnego cache (elevation_cache.json) - ponowne odpalenie ETL nie odpytuje punktów, które już mamy. Uwaga: serwis GUGiK przyjmuje tylko współrzędne PL-1992, nie WGS84, więc w ETL jest konwersja własnym kodem (bez pyproj).

Paczkomaty InPost

Punkty paczkowe z publicznego API InPost ShipX (typ parcel_locker). Każdy paczkomat przypisujemy do podziału administracyjnego za pomocą tego samego geokodera GUGiK i relacyjnego dopasowania, co sklepy. To jest jednorazowe pobranie - sieć paczkomatów rośnie wolno, mamy około 31 950 punktów. Porównanie Żabek vs paczkomaty - z podziałem na województwa, powiaty i gminy - jest na dashboardzie.

Płazy – GBIF

Obserwacje płazów z Global Biodiversity Information Facility (klasa Amphibia, taxonKey=131) w Polsce. Mamy około 36 571 rekordów ze współrzędnymi. Za pomocą BallTree (haversine) zliczamy obserwacje w promieniu 5 km od każdego sklepu. Najbardziej żabia Żabka ma 2027 obserwacji - i to w Ursynowie, nie w żadnym parku narodowym.

Sąsiedztwo – obliczenia lokalne

Odległość do najbliższej innej Żabki obliczamy lokalnie przez BallTree (haversine, k=2). Najbardziej odosobniony sklep ma 27,3 km do najbliższego sąsiada (Michałowo, podlaskie). Punkt najdalszy od jakiejkolwiek Żabki - pusta przestrzeń w Bieszczady - to około 46,52 km. Czysta geometria na wczytanych już danych.

Pipeline ETL

Mamy codzienny proces ETL, który pobiera dane, czyści, wzbogaca i zapisuje do bazy. Wygląda tak:

  1. Pobranie. Pobieramy publiczny plik JSON z lokalizacjami sklepów. Jeśli API niedostępne, bierzemy z lokalnego pliku fallback z data/input/.
  2. Oczyszczenie. Deduplikacja po storeId, normalizacja nazw miast, usuwanie <br> i kodów pocztowych z ulic, wyrzucenie danych osobowych i stałych pól.
  3. Wzbogacenie. Każde źródło niezależnie: regiony, sąsiedztwo, płazy, parki, elewacja, GUS, paczkomaty. Błąd jednego źródła nie przerywa potoku - kolumna dostaje NULL i ETL idzie dalej. Każde zapytanie sieciowe ma retry 3 próby z odstępem 60s.
  4. Diff. Porównujemy z poprzednim snapshotem: nowe store_id to sklep otwarty, zniknięte - zamknięty. Wynik zapisujemy jako historia zmian bezpośrednio w tabeli lokalizacji za pomocą pola deleted_at.
  5. Zapis do bazy. Zapis do DuckDB. Nowe kolumny dodajemy przez ALTER TABLE ADD COLUMN IF NOT EXISTS.
  6. Czyszczenie cache. Po sukcesie ETL czyścimy cache Redis. Backend odbudowuje odpowiedzi na nowym stanie. Redis jest opcjonalny - jak niedostępny (np na srodowisku lokalnym), backend działa bez niego.

Czego nie gwarantujemy

Ograniczenia danych

  • Około 204 sklepów nie ma daty otwarcia w źródłach – nie pojawiają się na wykresie historii wzrostu.
  • Populacje powiatów to dane roczne z GUS, nie bieżące szacunki.
  • Sklepy na granicach uproszczonych poligonów mogą trafić do sąsiedniego województwa (dotyczy około 3 punktów).
  • Godziny otwarcia pochodzą ze źródła Żabki, nie z weryfikacji terenowej.
  • Dane dot. lokalizacji Żabek obejmują jedynie aktualnie aktywne sklepy. Nie mamy więc danych historycznych - najstarsza Żabka niekoniecznie musi być najstarsza w ogóle, bo jest najstarsza z aktywnych.
  • Obserwacje GBIF zależą od aktywności obserwatorów – mniej zamieszkałe regiony mają mniej rekordów nie dlatego, że jest mniej płazów, tylko dlatego, że mniej osób tam patrzy.
  • Brakujące źródło wzbogacenia zostawia kolumnę NULL – tabela jest spójna, ale niekompletna.
  • Soft delete: sklepy, które zniknęły ze źródła, dostają deleted_at w bazie. Zapytania domyślnie filtrują deleted_at IS NULL, więc zamknięte sklepy nie psują statystyk.