Otwarta metodologia: prognoza goli i tablica draftowa „Piłkarzyki" 2026/27

Wersja: 1.0 (2026-07-27) · Autor: Michał Pozoga · Licencja: CC BY 4.0 Kanoniczny adres tego pliku: https://michalpozoga.pl/metodologia-pilkarzyki-26-27.md Wersja HTML: https://michalpozoga.pl/metodologia-pilkarzyki-26-27/

Ten dokument opisuje kompletną metodologię prognozowania goli piłkarzy na sezon i budowy tablicy draftowej do gry fantasy „Piłkarzyki". Jest napisany tak, żeby człowiek albo model językowy (LLM) mógł odtworzyć podejście od zera we własnej lidze fantasy — z wzorami, wartościami parametrów, protokołem walidacji i listą pułapek, na których ta metodologia się sparzyła, zanim je naprawiła. Nie opisuje prywatnego kodu — opisuje metodę. Możesz z niej korzystać, cytować i budować na niej dalej, z podaniem źródła (licencja CC BY 4.0 na końcu).

Uwaga o stanie wdrożenia: publiczna tablica na tej stronie może być o krok za tym dokumentem — dokument opisuje metodologię po sprincie z 2026-07-27 (sekcje 3.4, 5, 11.4), a przeliczenie produkcyjne następuje razem z odświeżeniem researchu przed draftem. Numer wydania prognozy („forecast_id") na tablicy jednoznacznie identyfikuje, co dokładnie jest opublikowane.


0. Jak korzystać z tego dokumentu (instrukcja dla LLM)

  1. Jeśli budujesz podobny model: czytaj sekcje 1–10 po kolei; sekcja 13 to skrócona checklista przenośności.
  2. Jeśli oceniasz cudzy model fantasy: zacznij od sekcji 11 (walidacja) i 12 (pułapki) — to tam są rzeczy, które najczęściej są zrobione źle.
  3. Wszystkie liczby w tym dokumencie to konkretne, aktualne wartości produkcyjne, nie przykłady. Gdy zmienimy parametr, zmieni się wersja dokumentu.
  4. Kluczowa zasada projektu: liczą się wyłącznie gole ligowe. Nie asysty, nie oceny, nie „eye test". Każda decyzja modelu ma maksymalizować trafność prognozy goli, a każda decyzja draftowa — gole ponad poziom zastępnika.

1. Problem i funkcja celu

„Piłkarzyki" to liga fantasy: 36 menedżerów draftuje po 9 zawodników (domyślnie 6 napastników „N" i 3 pomocników „P"; wariant 7N/2P dozwolony) w drafcie wężowym. Punktują wyłącznie gole w meczach ligowych rozgrywek ze „strefy punktowanej" (14 lig, sekcja 5). W każdej kolejce menedżer wystawia trójkę z ograniczeniami (m.in. maks. 1 zawodnik z danej ligi w trójce), ale decyzją projektową model optymalizuje wyłącznie draft — sumę goli w sezonie — a nie tygodniowe wystawienia.

Funkcja celu prognozy: dla każdego zawodnika rozkład liczby goli ligowych w sezonie 2026/27. Funkcja celu draftu: gole ponad poziom zastępnika (sekcja 10), nie surowa prognoza.

2. Dane wejściowe

3. Warstwa cech

3.1 Okno i wagi świeżości

Maksymalnie 4 ostatnie sezony, wagi świeżości 0,50 / 0,30 / 0,15 / 0,05 kotwiczone do kalendarza, nie do pozycji na liście: jeśli zawodnikowi brakuje sezonu (kontuzja, luka w danych), starszy sezon NIE awansuje na wyższą wagę. To ochrona przed survivor biasem scrape'ów typu „top-50 ligi": słaby sezon częściej znika z danych, a dziura po najgorszym sezonie nie może ZAWYŻAĆ prognozy.

3.2 Sezon częściowy

Sezon w trakcie (przy scrape'ie śródsezonowym) jest proratowany do pełnego wymiaru (współczynnik ≤1,55), a jego waga jest tłumiona, gdy ekspozycja minutowa < 60% możliwej: waga × max(ekspozycja/0,6; 0,33). Zdrowy gracz w połowie sezonu ma ekspozycję ~1,0 i nie jest karany.

3.3 Stawki są nieobciążone; świeżość obniża WIARYGODNOŚĆ, nie wartość

Cechy tempa (gole/90, npxG/90 itd.) to ważone średnie z sezonów, w których zawodnik zagrał ≥300 minut (waga próby dodatkowo ∝ min(minuty/900; 1)). Nieaktualna historia nie zaniża samej stawki. Zamiast tego maleje jej wiarygodność: minuty_wiarygodności = minuty_kariery_nondonor × (waga_kalendarzowa_najnowszego_sezonu / 0,50). Zawodnik bez ostatniego sezonu ma stawkę prawdziwą, ale próbę liczoną ×0,6 (bez dwóch sezonów ×0,3 itd.) — więc regresuje ku kotwicy (sekcja 4), a nie ku zeru.

*Dlaczego to ważne:* wcześniejsza wersja mnożyła stawkę przez współczynnik świeżości — wracający po roku przerwy napastnik z prawdziwym 0,5 gola/90 wchodził do modelu jako 0,3. To podwójna kara (research i tak tnie mu minuty) i systematyczne zaniżanie dokładnie tych graczy, którzy bywają okazjami.

3.4 Starty

Udział startów liczony tylko z sezonów, w których dane o startach istnieją; osobna flaga starty_dostępne steruje wzorem minut (sekcja 6).

4. Rdzeń prognozy stawki („gole-first")

Stawka goli z gry na 90 minut:

kotwica  = pokrycie_xG × npxG90_prognozowane + (1 − pokrycie_xG) × prior_golowy_pozycji
stawka   = (obserwowane_npg90 × M_wiar + kotwica × K) / (M_wiar + K)
stawka  *= mnożnik_siły_ligi (sekcja 5)
stawka  *= mnożnik_wieku (płaski do 33 lat, potem −5%/rok, podłoga 0,55)

5. Siły lig — mierzone, nie „z reputacji"

Strefa punktowana i aktualne siły (PL = punkt odniesienia; mniejsza liczba = łatwiej strzelać; liczba kolejek w nawiasie):

Premier League 0.975 (38)   LaLiga 0.83 (38)      Serie A 0.90 (38)
Bundesliga 0.77 (34)        Ligue 1 0.77 (34)     Eredivisie 0.60 (34)
Liga Portugal 0.64 (34)     Jupiler 0.66 (30)     Süper Lig 0.61 (38)
Scottish Prem 0.52 (38)     Ekstraklasa 0.51 (34) Austria 0.50 (32)
Swiss SL 0.55 (36)          Grecja 0.61 (30)
donorskie: Championship 0.70, Brasileirão 0.66, Saudi 0.55, MLS 0.50,
J1 0.48, Katar 0.42, Chiny 0.40

Jak są estymowane (2026-07-27): z par kolejnych sezonów tych samych zawodników. Model warunkowy dwumianowy: dla pary sezonów o golach z gry (g_A, g_B) i minutach (m_A, m_B), g_B | g_A+g_B ~ Binomial(g_A+g_B, p), gdzie logit p = log(m_B/m_A) + dryf + (s_A − s_B), s to log-trudność ligi (PL = 0). Trzy kluczowe zabezpieczenia:

  1. Stayerzy (ta sama liga w obu sezonach) kotwiczą dryf — przeciętny zawodnik traci ~3,7% tempa rok do roku (regresja do średniej + wiek). Bez tego dryf wpada do efektów lig.
  2. Informacja ∝ liczba goli — pary bez goli (defensywni pomocnicy) nie wnoszą fałszywego sygnału; nie trzeba arbitralnych wygładzeń.
  3. Shrinkage do poprzednich wartości (prior wart ~12 „standardowych" par) — ligi z małą liczbą transferów nie skaczą po szumie.

Zastosowanie w modelu: mnożnik przejścia (siła_źródłowa / siła_docelowa)^γ, γ = 0,40, obcięcie [0,70; 1,30]. Zawodnik pozostający w lidze ⇒ mnożnik 1,0 (model NIE normalizuje wszystkich „do PL" — to była wcześniejsza pomyłka, karała graczy małych lig, którzy nigdzie się nie ruszali).

Dlaczego γ=0,40, skoro pomiar pełnego efektu daje ~0,66: bo pełny efekt empiryczny zawiera selekcję kierunkową — schodzący w dół drabinki to nieprzypadkowa próba (starzejący się), a globalny dryf tego nie opisuje. Backtest: γ=0,65 symetrycznie przeszacowuje schodzących (bias segmentu zmieniających ligę +0,48), γ kierunkowa nie daje nic. Przyjęto γ=0,40 + korekty samych sił o pół rezyduum pomiaru (Serie A i Grecja W GÓRĘ — są trudniejsze, niż sugerowała reputacja; Eredivisie/LaLiga/Bundesliga w dół).

6. Prognoza minut

baza      = 0,65 × udział_minut_ważony + 0,20 × udział_ostatniego_sezonu
            (+ 0,15 × udział_startów, jeśli dane o startach istnieją;
             bez nich pierwsze dwa składniki dzielone przez 0,85)
model     = regresja grzbietowa (α=8) na logit udziału minut, wszystkie cechy
udział    = 0,55 × model + 0,45 × baza
podłoga   : stabilny filar (≥3 sezony po 1800+ min, ≥6000 min kariery,
            ≥2200 min ważonych, bez świeżego transferu) ⇒ udział ≥ 0,92 × baza
minuty    = udział × kolejki_ligi × 90

Niepewność minut rośnie ze zmiennością historii, transferem i wiekiem (≥32 lub ≤21). Świadome ograniczenie: model minut NIE zna składu konkurencji, zmian trenera ani historii kontuzji — te fakty wnosi warstwa researchu (sekcja 9). Próby „dokręcenia" punktowej prognozy minut heurystykami pogarszały backtest — minuty są blisko optimum osiągalnego bez danych kadrowych i racjonalnie hedgują ryzyko.

7. Rzuty karne

karne_zespołu  : mediana goli z karnych na klubo-sezon w lidze ÷ 0,77 ⇒ kotwica
                 ligowa (shrinkage do globalnej, K=20 klubo-sezonów);
                 zespół: shrinkage własnej historii do kotwicy (K=42/34 meczów),
                 obcięcie [0,5; 7,5]
P(rola)        : 0,72 pierwszy wykonawca / 0,32 drugi / 0,22 ofensywny z ≥4
                 próbami w karierze / 0,07 ofensywny grający ≥60% minut / 0,02;
                 blend 0,65×status + 0,35×udział z zeszłego sezonu; po
                 transferze status zerowany i ×0,75
konwersja      : (trafione + 0,77×12) / (próby + 12)
gole_z_karnych = karne_zespołu × P(rola) × udział_minut × konwersja

Karne są osobnym procesem w symulacji (sekcja 8) i osobną ścieżką korekty w researchu. Na tablicy gracz, u którego karne ≥ 50% prognozy, ma jawne ostrzeżenie (utrata roli przy jedenastkach zabiera większość wartości).

8. Symulacja Monte Carlo

20 000 symulacji sezonu na gracza, stały seed (pełna odtwarzalność). W każdej symulacji, niezależnie per gracz:

  1. Minuty: rozkład normalny obcięty do [0; maks.], σ = √(0,18² + (niepewność/maks.)²), cap 0,45; średnia po obcięciu = prognoza.
  2. Stawka: lognormalna sparametryzowana na ŚREDNIĄ (nie medianę!), σ = 0,36 + 0,25 × niepewność stawki, obcięta [0,10; 0,75].
  3. Gole z gry: ujemny dwumianowy o średniej stawka×minuty/90, naddyspersja 1,95 (Poisson jest za wąski dla goli sezonowych).
  4. Karne: zespół ~ Poisson(karne_zespołu); rola ~ Bernoulli(P(roli)); próby gracza ~ Binomial(karne_zespołu, udział_minut); gole ~ Binomial(próby, konwersja obcięta [0,55; 0,92]).

Z rozkładu raportujemy: średnią, medianę, percentyle 10/25/75/90, P(5+/10+/15+/20+ goli), ryzyko niewypału, wiarygodność. Uwaga interpretacyjna: rozkład goli jest prawostronnie skośny, więc mediana < średnia — ranking po średniej premiuje wysokie sufity, po medianie pewny dorobek. Publikujemy oba.

9. Warstwa researchu — fakty, nie opinie

Model statystyczny nie wie o transferach sprzed tygodnia, hierarchii karnych po odejściu gwiazdy ani rehabilitacjach. Tę wiedzę wnosi ręczny research (u nas: ~324–530 zawodników, każdy z ≥2 datowanymi źródłami z ≥2 domen). Zasada nadrzędna: research koryguje wyłącznie FAKTY — minuty, karne, klub/ligę, status zdrowotny, pozycję — nigdy „formę", „hype" ani opisowe mnożniki. Reguły przeliczania:

10. Wartość draftowa

11. Walidacja i uczciwość

11.1 Protokół

11.2 Aktualne wyniki (po zmianach z 2026-07-27)

11.3 Zamrożenie i rozliczenie

Przed pierwszą kolejką prognoza jest zamrażana: zapisujemy dokładne wiersze rankingu, sumy kontrolne danych, kodu i konfiguracji oraz deterministyczny identyfikator wydania. Po sezonie DOKŁADNIE ten ranking jest rozliczany na finalnych golach (gracz, który odszedł/skończył karierę, zostaje w kohorcie z 0 goli — ryzyko statusu jest częścią produktu). Kryteria i kohorta nie mogą być zmienione po poznaniu wyników; wynik publikujemy także wtedy, gdy model przegra z baselinem.

11.4 Kalibracja — kiedy jej NIE robić

Liniowa kalibracja actual ≈ a + b×pred dopasowana na starych foldach pogarszała świeższy holdout (bias foldów nie przenosił się między sezonami; dopasowanie degenerowało na klipach). Wniosek ogólny: zanim zaaplikujesz kalibrację, sprawdź, czy bias jest STABILNY między sezonami. U nas nie był — kalibracja jest wyłączona decyzją, z zapisanym uzasadnieniem.

12. Pułapki, na których się sparzyliśmy (czytaj przed budową własnego modelu)

  1. Survivor bias scrape'ów „top-N ligi": słaby sezon wypada z danych; jeśli wagi świeżości zipujesz po liście zamiast po kalendarzu, dziura po najgorszym sezonie ZAWYŻA prognozę.
  2. Sumowanie źródeł danych: dwa źródła opisujące ten sam okres to nie dwa okresy. Warianty nazw klubów („Bayern Munich" vs „FC Bayern München") potrafią podwoić gole połowie ligi. MAX per źródło, suma tylko po transferach, bezpiecznik limitu minut.
  3. Deflacja za nieświeżość: obniżanie STAWKI za brak świeżego sezonu podwójnie karze wracających z kontuzji. Świeżość ma obniżać wiarygodność (wagę próby w shrinkage), nie wartość.
  4. Martwe składniki wzorów: składnik oparty na polu z 4% pokryciem (starty) po cichu ścina prognozę wszystkim pozostałym. Audytuj pokrycie każdego pola, zanim wstawisz je do wzoru; renormalizuj wagi przy braku.
  5. xG tam, gdzie go nie ma: kotwiczenie do npxG w lidze bez danych xG daje artefakt ~0 i zabija całą ligę. Kotwica musi być mieszana proporcjonalnie do POKRYCIA, z priorem golowym jako drugą nogą.
  6. Naiwna „retencja stawki" moverów jest skażona selekcją — i to dwukrotnie: (a) małe ligi trzymają w scrape'ach tylko czołówkę, więc „utrzymanie stawki" jest tam sztucznie wysokie; (b) schodzący w dół drabinki to starzejący się gracze — pełny zmierzony efekt ligi przeszacowuje ich premię. Lecz: model warunkowy ze stayerami jako kotwicą dryfu + wdrażanie części efektu + walidacja segmentem zmieniających ligę.
  7. Kalibracja między sezonami: patrz 11.4.
  8. Imiennicy: dopasowanie po nazwisku myli ludzi (dwóch „Beto"). Tylko stabilne ID + weryfikacja tożsamości przy krótkich nazwach.
  9. Karne bez danych o próbach: poza Wielką Piątką pole „próby karnych" bywa puste — bez imputacji z goli model odbiera rolę wykonawcy najlepszym strzelcom małych lig (a karne to bywa 30–50% ich wartości).
  10. Ranking po średniej vs po medianie: średnia premiuje grube prawe ogony (gracz „14 albo 40 goli" wskoczy za wysoko). Publikuj oba porządki i nazwij je wprost; nie mieszaj jednostek w jednym rankingu.
  11. Częściowy sezon jako ground truth: nigdy. Prorate do prognoz, ale rozliczaj wyłącznie pełne sezony.
  12. Plotka transferowa jako fakt: status „zaawansowane rozmowy" to nie transfer. Fakty wchodzą do modelu dopiero z potwierdzeniem; niepewność wyrażaj prawdopodobieństwem pozostania w strefie, nie podmianą klubu.

13. Przenośność — przepis dla innej ligi fantasy (checklista)

  1. Zdefiniuj funkcję celu dokładnie (co punktuje? tylko liga? jakie pozycje?).
  2. Zbuduj bazę zawodnik-sezon z 4+ sezonów; audytuj POKRYCIE każdego pola per liga, zanim czegokolwiek użyjesz.
  3. Stawka: shrinkage obserwowanego tempa do kotwicy (xG × pokrycie + prior pozycji × resztę); wiarygodność = minuty × świeżość kalendarzowa.
  4. Minuty osobno (regresja + prosta baza + podłoga dla filarów); nie udawaj, że znasz kadry — zostaw to warstwie faktów.
  5. Siły lig policz z moverów modelem warunkowym (sekcja 5); wdrażaj konserwatywnie (część efektu), waliduj segmentem zmieniających ligę.
  6. Symuluj (lognormal × ujemny dwumianowy + karne osobno), publikuj rozkład, nie punkt.
  7. Wartość = prognoza − zastępnik przy realnym popycie pozycyjnym twojej ligi.
  8. Warstwa faktów (transfery/kontuzje/karne) z datowanymi źródłami i bramką świeżości; fakty korygują minuty i karne, nie „formę".
  9. Waliduj temporalnie z jawnym holdoutem; zamroź prognozę przed sezonem; rozlicz się publicznie po sezonie.
  10. Prowadź listę własnych pułapek. Ta lista (sekcja 12) jest ważniejsza niż niejeden parametr.

14. Słownik

Strefa — ligi, za które gra przyznaje punkty. Donor — liga poza strefą, używana tylko jako historia. Stawka — gole z gry na 90 minut. Kotwica — wartość, ku której regresuje stawka przy małej próbie. Shrinkage / ściąganie — średnia ważona obserwacji i kotwicy z wagą zależną od wielkości próby. Zastępnik (replacement) — pierwszy niewybrany gracz pozycji przy pełnym popycie draftu. VORP / przewaga nad zastępnikiem — prognoza minus poziom zastępnika. EV — średnia z symulacji. P50 — mediana. Fail-closed — przy braku spełnienia warunków system odmawia publikacji, zamiast publikować po cichu gorsze dane. Forecast_id — deterministyczny identyfikator wydania prognozy (hash wierszy + kodu).


Licencja i cytowanie

Tekst metodologii: Creative Commons Uznanie autorstwa 4.0 (CC BY 4.0). Możesz kopiować, adaptować i używać komercyjnie, podając autora i źródło:

Michał Pozoga, „Otwarta metodologia: prognoza goli i tablica draftowa Piłkarzyki 2026/27", michalpozoga.pl/metodologia-pilkarzyki-26-27/ (CC BY 4.0)

Wersja kanoniczna: plik Markdown pod adresem https://michalpozoga.pl/metodologia-pilkarzyki-26-27.md. Historia zmian: v1.0 (2026-07-27) — pierwsza publikacja.

English abstract

Open methodology (CC BY 4.0) for forecasting season goal totals and building a fantasy-draft board („Piłkarzyki", a 36-manager, goals-only Polish fantasy league spanning 14 European leagues). Core: an empirical-Bayes „goals-first" rate model — observed non-penalty goals/90 shrunk (K=4000 credibility minutes, freshness discounts credibility rather than the rate itself) toward an anchor that mixes predicted npxG/90 with a positional goals prior in proportion to xG data coverage; league-transition multipliers estimated from within-player season pairs via a conditional-binomial model with stayers anchoring year-over-year drift; separate minutes and penalty models; 20 000 Monte-Carlo simulations (lognormal rate × negative-binomial goals, penalties as a separate process); value = expected goals above a positional replacement level (216 F / 108 M demand); a fact-only manual research layer with a 14-day freshness fail-closed gate; strictly temporal validation with a declared holdout, a pre-season frozen forecast (hashed rows/code/config) and a public post-season settlement. Section 12 lists the pitfalls we actually hit — survivorship in top-N scrapes, cross-source double counting, staleness deflation, dead formula components, xG-anchor artifacts in uncovered leagues, selection-contaminated mover retention, non-transferable calibration. The Polish text is canonical.