Facebook Prophet

Prognozowanie Szeregów Czasowych w Pythonie

Przewodnik oparty na oficjalnej dokumentacji Facebook Prophet

Historia Facebook Prophet

2017 - Facebook opublikował Prophet jako projekt open-source

Autorzy: Sean J. Taylor i Benjamin Letham z zespołu Core Data Science w Facebooku

Cel stworzenia:

  • Demokratyzacja prognozowania - narzędzie dla analityków bez głębokiej wiedzy statystycznej
  • Obsługa tysięcy prognoz dziennie w Facebooku
  • Automatyzacja rutynowych zadań prognostycznych

Publikacja naukowa:

"Forecasting at Scale" (2017) - opisuje architekturę i zastosowania Prophet w środowisku produkcyjnym

Dlaczego Facebook Stworzył Prophet?

Problemy tradycyjnych metod prognozowania:

  • ARIMA - wymaga dużej wiedzy statystycznej, trudne w dostrajaniu
  • Eksponencjalne wygładzanie - słabo radzi sobie z wieloma sezonowościami
  • Machine Learning - potrzebuje dużo danych, trudne w interpretacji

Wyzwania w Facebooku:

  • Tysiące różnych szeregów czasowych do prognozowania
  • Analitycy biznesowi (nie-statystycy) potrzebują szybkich prognoz
  • Dane z outliers, brakującymi wartościami, świętami
  • Potrzeba szybkich iteracji i dostrajania

Rozwiązanie Prophet: Intuicyjna biblioteka z sensownymi domyślnymi ustawieniami, łatwa w użyciu i interpretacji

Założenia Modelu Prophet

Prophet opiera się na modelu addytywnym:

y(t) = g(t) + s(t) + h(t) + εₜ

Gdzie:

  • g(t) - funkcja trendu (wzrost w czasie)
  • s(t) - sezonowość (periodyczne wzorce)
  • h(t) - efekty świąt i wydarzeń
  • εₜ - składnik błędu (szum)

Kluczowe założenia:

  • Szereg czasowy ma wyraźny trend (liniowy lub logistyczny)
  • Występuje sezonowość (dzienna, tygodniowa, roczna)
  • Święta i wydarzenia mają przewidywalny wpływ
  • Zmiany trendu (changepoints) występują regularnie

Komponenty Modelu - Trend g(t)

Trend opisuje długoterminowy wzrost lub spadek wartości.

Dwa typy trendu:

  • Liniowy (domyślny): g(t) = (k + a(t)ᵀδ)t + (m + a(t)ᵀγ)
    • k - tempo wzrostu
    • δ - zmiany tempa wzrostu w changepoints
    • m - offset (wartość początkowa)
  • Logistyczny (saturating): g(t) = C / (1 + exp(-(k + a(t)ᵀδ)(t - (m + a(t)ᵀγ))))
    • C - maksymalna wartość (capacity)
    • Używany gdy wzrost ma górny lub dolny limit

Changepoints: Punkty, w których trend może się zmieniać automatycznie wykrywane przez model

Komponenty Modelu - Sezonowość s(t)

Sezonowość to periodyczne wzorce powtarzające się w czasie.

Prophet używa szeregów Fouriera:

s(t) = Σ [aₙ·cos(2πnt/P) + bₙ·sin(2πnt/P)]

Gdzie:

  • P - okres sezonowości (365.25 dla rocznej, 7 dla tygodniowej)
  • n - order Fouriera (kontroluje złożoność wzorca)

Domyślne sezonowości:

  • Yearly (roczna) - period=365.25 dni, fourier_order=10
  • Weekly (tygodniowa) - period=7 dni, fourier_order=3
  • Daily (dzienna) - period=24 godz, fourier_order=4 (tylko dla danych godzinowych)

Możliwość dodania niestandardowych sezonowości (miesięczna, kwartalna, etc.)

Komponenty Modelu - Święta h(t)

Święta i wydarzenia to nieregularne zdarzenia wpływające na szereg czasowy.

Model świąt:

h(t) = Σ κᵢ · 1{t ∈ Dᵢ}

Gdzie:

  • κᵢ - wpływ i-tego święta (estymowany przez model)
  • Dᵢ - zbiór dat dla i-tego święta (włącznie z oknem przed/po)
  • 1{·} - funkcja wskaźnikowa (1 jeśli prawda, 0 jeśli fałsz)

Elastyczność:

  • Możliwość definiowania niestandardowych świąt
  • Okna czasowe (np. 2 dni przed i po Black Friday)
  • Wbudowane święta dla 95+ krajów
  • Różne święta mogą mieć różny wpływ

Zalety Facebook Prophet

1. Łatwość użycia:

  • Intuicyjne API - fit() i predict()
  • Minimalna konfiguracja - sensowne wartości domyślne
  • Nie wymaga wiedzy o ARIMA, stacjonarności, etc.

2. Elastyczność:

  • Łatwe dodawanie niestandardowych sezonowości
  • Wbudowane święta dla wielu krajów
  • Obsługa dodatkowych regressorów

3. Odporność:

  • Radzi sobie z brakującymi danymi
  • Automatycznie wykrywa outliers
  • Obsługuje zmiany trendu (changepoints)

4. Interpretowalność:

  • Wizualizacja komponentów (trend, sezonowość, święta)
  • Łatwo zrozumieć wpływ każdego komponentu
  • Przedziały ufności dla prognoz

Wady i Ograniczenia Prophet

1. Nie dla wszystkich szeregów czasowych:

  • Wymaga minimum kilku miesięcy danych historycznych
  • Słabo radzi sobie z nieregularnymi wzorcami
  • Nie dla szeregów bez wyraźnego trendu lub sezonowości

2. Ograniczenia modelu:

  • Zakłada addytywność komponentów (chyba że multiplicative)
  • Nie uwzględnia auto-korelacji w residuach
  • Nie modeluje zależności między szeregami (VAR, VECM)

3. Wydajność:

  • Wolniejszy niż ARIMA dla krótkich szeregów
  • Wymaga Stan (może sprawiać problemy przy instalacji)

4. Prognozy długoterminowe:

  • Niepewność rośnie szybko dla długich horyzontów
  • Zakłada kontynuację obecnych wzorców

Plan Prezentacji

  1. Historia i założenia modelu ✓
  2. Instalacja i konfiguracja
  3. Quick Start - pierwszy model
  4. Python API - podstawowe funkcje
  5. Saturating Forecasts - prognozy z ograniczeniami
  6. Trend Changepoints - punkty zmiany trendu
  7. Seasonality - sezonowość
  8. Holiday Effects - efekty świąt
  9. Country Holidays - wbudowane święta krajowe
  10. Regressors - dodatkowe zmienne
  11. Cross-Validation i Performance Metrics
  12. Parallelizing Cross Validation
  13. Hyperparameter Tuning (Grid Search, Random Search)
  14. Outliers - wykrywanie i obsługa
  15. Handling Shocks - modelowanie wstrząsów

Czym jest Facebook Prophet?

Prophet to biblioteka open-source stworzona przez Facebook (Meta) do prognozowania szeregów czasowych.

Kluczowe cechy:

  • Intuicyjny - łatwy w użyciu, minimalny kod
  • Automatyczny - wykrywa sezonowość i trendy
  • Odporny na braki - radzi sobie z brakującymi danymi
  • Efekty świąt - wbudowane święta dla wielu krajów
  • Interpretowalny - wizualizacja komponentów
  • Szybki - działa na CPU, nie wymaga GPU

Kiedy Używać Prophet?

Prophet sprawdza się najlepiej gdy:

  • Masz dane historyczne (minimum kilka miesięcy)
  • Dane mają silną sezonowość (dzienną, tygodniową, roczną)
  • Występują święta i wydarzenia specjalne
  • Występują trendy zmieniające się w czasie
  • Dane mają wartości odstające (outliers)
  • Potrzebujesz szybkich prognoz bez głębokiej wiedzy o time series

Typowe zastosowania:

  • Prognozowanie sprzedaży i przychodów
  • Przewidywanie ruchu na stronie internetowej
  • Analiza zapotrzebowania na produkty
  • Prognozowanie zużycia energii
  • Planowanie zasobów

Instalacja

Instalacja Prophet w Pythonie

# Metoda 1: pip (zalecana)
pip install prophet

# Metoda 2: conda (jeśli używasz Anacondy)
conda install -c conda-forge prophet

# Prophet wymaga dodatkowych zależności:
# - pystan (silnik Stan dla modelowania bayesowskiego)
# - numpy, pandas, matplotlib

# Sprawdź instalację
python -c "import prophet; print(prophet.__version__)"

# Jeśli występują problemy z instalacją:
# Windows: zainstaluj Microsoft C++ Build Tools
# Linux: sudo apt-get install python3-dev
# macOS: brew install gcc

# Opcjonalnie: plotly dla interaktywnych wykresów
pip install plotly

Import Podstawowych Bibliotek

# Podstawowe importy
import pandas as pd
import numpy as np
from prophet import Prophet
import matplotlib.pyplot as plt

# Dla interaktywnych wykresów (opcjonalnie)
from prophet.plot import plot_plotly, plot_components_plotly
import plotly.offline as py

# Wyłącz ostrzeżenia (opcjonalnie)
import warnings
warnings.filterwarnings('ignore')

# Ustawienia pandas
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', 100)

print("Prophet zainstalowany pomyślnie!")

Quick Start

Przygotowanie Danych

Prophet wymaga DataFrame z dwoma kolumnami:

  • ds - data (datetime)
  • y - wartość do prognozowania

import pandas as pd

# Przykładowe dane - dzienne sprzedaże
data = {
    'ds': pd.date_range(start='2020-01-01', periods=365, freq='D'),
    'y': np.random.randn(365).cumsum() + 100
}
df = pd.DataFrame(data)

print(df.head())
#           ds           y
# 0 2020-01-01  100.496714
# 1 2020-01-02   99.358760
# 2 2020-01-03  100.758990

# WAŻNE: kolumny MUSZĄ nazywać się 'ds' i 'y'!

Pierwszy Model Prophet

from prophet import Prophet

# 1. Utwórz model
model = Prophet()

# 2. Dopasuj model do danych (trening)
model.fit(df)

# 3. Utwórz DataFrame z przyszłymi datami
# periods=365 - przewiduj 365 dni w przyszłość
future = model.make_future_dataframe(periods=365)
print(f"Rozmiar future: {len(future)} dni")

# 4. Wykonaj prognozę
forecast = model.predict(future)

Wyniki Prognozy

# 5. Zobacz wyniki
print(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail())

#            ds        yhat  yhat_lower  yhat_upper
# 725 2021-12-27  102.456789   95.123456  109.789012
# 726 2021-12-28  103.234567   95.901234  110.567890

# yhat - prognoza (wartość przewidywana)
# yhat_lower - dolna granica (95% CI)
# yhat_upper - górna granica (95% CI)

Wizualizacja Prognozy

# Wykres główny - prognoza z przedziałem ufności
fig1 = model.plot(forecast)
plt.title('Prognoza Prophet')
plt.xlabel('Data')
plt.ylabel('Wartość')
plt.show()

# Wykres komponentów - trend, sezonowość
fig2 = model.plot_components(forecast)
plt.show()

# Komponenty pokazują:
# - trend: ogólny kierunek zmian
# - weekly: sezonowość tygodniowa
# - yearly: sezonowość roczna

Interaktywna Wizualizacja (Plotly)

# Interaktywny wykres (wymaga plotly)
from prophet.plot import plot_plotly
fig = plot_plotly(model, forecast)
fig.show()

# Interaktywne komponenty
from prophet.plot import plot_components_plotly
fig = plot_components_plotly(model, forecast)
fig.show()

# Zalety plotly:
# - Możliwość przybliżania (zoom)
# - Podgląd wartości po najechaniu myszką
# - Eksport do PNG

Python API

Podstawowe Parametry Prophet

from prophet import Prophet

model = Prophet(
    # Typ wzrostu: 'linear' (domyślny) lub 'logistic'
    growth='linear',

    # Punkty zmiany trendu
    changepoints=None,  # Auto-detekcja
    n_changepoints=25,  # Liczba punktów zmiany
    changepoint_range=0.8,  # Tylko pierwsze 80% danych

    # Sezonowość
    yearly_seasonality='auto',  # True, False, lub 'auto'
    weekly_seasonality='auto',
    daily_seasonality='auto',

    # Święta
    holidays=None,  # DataFrame ze świętami

    # Regularyzacja (elastyczność)
    seasonality_prior_scale=10.0,  # Im wyższy, tym bardziej elastyczna sezonowość
    holidays_prior_scale=10.0,
    changepoint_prior_scale=0.05,  # Im wyższy, tym więcej punktów zmiany

    # Interwał ufności
    interval_width=0.95,  # 95% przedział ufności

    # Inne
    uncertainty_samples=1000,
    stan_backend=None
)

Główne Metody Prophet - Część 1

# fit() - trenuj model
model.fit(df)

# make_future_dataframe() - utwórz daty dla prognozy
future = model.make_future_dataframe(
    periods=365,        # Liczba okresów do przewidzenia
    freq='D',           # Częstotliwość: 'D'=dzień, 'M'=miesiąc, 'H'=godzina
    include_history=True  # Czy dołączyć dane historyczne
)

# predict() - wykonaj prognozę
forecast = model.predict(future)

# plot() - wizualizuj prognozę
model.plot(forecast)

# plot_components() - wizualizuj komponenty
model.plot_components(forecast)

Główne Metody Prophet - Część 2

# add_seasonality() - dodaj niestandardową sezonowość
model.add_seasonality(
    name='monthly',
    period=30.5,
    fourier_order=5
)

# add_country_holidays() - dodaj święta krajowe
model.add_country_holidays(country_name='PL')

# add_regressor() - dodaj dodatkową zmienną
model.add_regressor('temperature')

# Zobacz wykryte święta
print(model.train_holiday_names)

Saturating Forecasts

Prognozy z Ograniczeniami

Problem: Wzrost liniowy nie zawsze jest realistyczny. Wiele procesów ma górny limit (cap) lub dolny limit (floor).

Przykłady:

  • Liczba użytkowników (max = populacja rynku)
  • Penetracja rynku (max = 100%)
  • Zajętość hotelu (max = liczba pokoi)
  • Temperatura (floor = 0 Kelvin)

Rozwiązanie: Wzrost logistyczny (growth='logistic')

Forecasting Growth - Wzrost Logistyczny

Określ maksymalną wartość, do której może dążyć prognoza:

import pandas as pd
from prophet import Prophet

# Dane z górnym limitem
df = pd.read_csv('example_data.csv')

# WAŻNE: Dodaj kolumnę 'cap' - maksymalna wartość
df['cap'] = 1000000  # Np. 1 milion użytkowników

# Możesz też mieć różne limity w czasie
# df.loc[df['ds'] < '2021-01-01', 'cap'] = 800000
# df.loc[df['ds'] >= '2021-01-01', 'cap'] = 1000000

# Model z wzrostem logistycznym
model = Prophet(growth='logistic')
model.fit(df)

# WAŻNE: future też musi mieć 'cap'!
future = model.make_future_dataframe(periods=365)
future['cap'] = 1000000

# Prognoza
forecast = model.predict(future)

# Wykres
model.plot(forecast)

Saturating Minimum - Dolny Limit

Oprócz górnego limitu (cap), możesz określić dolny limit (floor):

# Dane z górnym i dolnym limitem
df['cap'] = 1000000   # Maksimum
df['floor'] = 10000   # Minimum (np. minimalna liczba użytkowników)

# Model logistyczny
model = Prophet(growth='logistic')
model.fit(df)

# Future z oboma limitami
future = model.make_future_dataframe(periods=365)
future['cap'] = 1000000
future['floor'] = 10000

# Prognoza
forecast = model.predict(future)

# Prognoza będzie oscylować między floor a cap
print(f"Min prognoza: {forecast['yhat'].min():.0f}")
print(f"Max prognoza: {forecast['yhat'].max():.0f}")

model.plot(forecast)

Trend Changepoints

Punkty Zmiany Trendu

Changepoints to momenty, w których tempo wzrostu/spadku zmienia się.

Przykłady:

  • Wprowadzenie nowego produktu
  • Zmiana strategii marketingowej
  • Kryzys gospodarczy
  • Pandemie, święta

Prophet automatycznie wykrywa changepoints:

  • Domyślnie: 25 potencjalnych punktów zmiany
  • Tylko w pierwszych 80% danych (changepoint_range=0.8)
  • Używa modelu bayesowskiego do regularyzacji

Automatic Changepoint Detection

from prophet import Prophet

# Model z domyślnymi ustawieniami
model = Prophet()
model.fit(df)
forecast = model.predict(future)

# Wizualizacja z zaznaczonymi changepoints
fig = model.plot(forecast)
# Czerwone linie pionowe = wykryte changepoints
from prophet.plot import add_changepoints_to_plot
add_changepoints_to_plot(fig.gca(), model, forecast)
plt.show()

Analiza Wykrytych Changepoints

# Wyświetl wykryte changepoints
print("Wykryte changepoints:")
print(model.changepoints)

# 0   2020-01-15
# 1   2020-02-04
# 2   2020-02-24
# ...

# Sprawdź siłę zmiany trendu w każdym punkcie
print("\nDelta (zmiana trendu):")
print(model.params['delta'])

# Delta pokazuje jak mocno trend się zmienia w każdym punkcie

Adjusting Trend Flexibility

Parametr changepoint_prior_scale kontroluje elastyczność trendu:

# Domyślnie: changepoint_prior_scale = 0.05

# MNIEJ elastyczny trend (mniej zmian, gładszy)
# Użyj gdy dane są zaszumione
model_smooth = Prophet(changepoint_prior_scale=0.01)
model_smooth.fit(df)

# BARDZIEJ elastyczny trend (więcej zmian)
# Użyj gdy masz pewność co do punktów zmiany
model_flexible = Prophet(changepoint_prior_scale=0.5)
model_flexible.fit(df)

# Porównanie
fig, axes = plt.subplots(1, 3, figsize=(18, 5))

model1 = Prophet(changepoint_prior_scale=0.001)
model1.fit(df)
model1.plot(model1.predict(future), ax=axes[0])
axes[0].set_title('Prior Scale = 0.001 (bardzo gładki)')

model2 = Prophet(changepoint_prior_scale=0.05)
model2.fit(df)
model2.plot(model2.predict(future), ax=axes[1])
axes[1].set_title('Prior Scale = 0.05 (domyślny)')

model3 = Prophet(changepoint_prior_scale=0.5)
model3.fit(df)
model3.plot(model3.predict(future), ax=axes[2])
axes[2].set_title('Prior Scale = 0.5 (bardzo elastyczny)')

plt.show()

Specifying the Locations of Changepoints

Jeśli znasz dokładne daty zmian, możesz je ręcznie określić:

from prophet import Prophet

# Określ konkretne daty changepoints
changepoints = [
    '2020-03-15',  # Lockdown COVID
    '2020-06-01',  # Zniesienie ograniczeń
    '2021-01-01',  # Nowy rok, nowa strategia
]

model = Prophet(changepoints=changepoints)
model.fit(df)
forecast = model.predict(future)

# Wizualizacja
fig = model.plot(forecast)
add_changepoints_to_plot(fig.gca(), model, forecast)
plt.show()

# Możesz też kontrolować liczbę auto-wykrywanych punktów
model = Prophet(
    n_changepoints=50,       # Zwiększ z 25 do 50
    changepoint_range=0.9    # Rozważ 90% danych (zamiast 80%)
)
model.fit(df)

# Wyłącz auto-detekcję (użyj tylko ręcznych)
model = Prophet(
    changepoints=changepoints,
    n_changepoints=0  # Wyłącz auto-detekcję
)

Seasonality

Sezonowość w Prophet

Prophet automatycznie wykrywa 3 typy sezonowości:

  • Yearly (roczna) - period=365.25 dni
  • Weekly (tygodniowa) - period=7 dni
  • Daily (dzienna) - period=24 godziny (tylko dla danych godzinowych)

Fourier Order:

Prophet używa szeregów Fouriera do modelowania sezonowości. Wyższy order = bardziej złożone wzorce.

  • Yearly: domyślnie fourier_order=10
  • Weekly: domyślnie fourier_order=3
  • Daily: domyślnie fourier_order=4

Kontrola Sezonowości - Część 1

# Wyłącz konkretne sezonowości
model = Prophet(
    yearly_seasonality=False,   # Wyłącz sezonowość roczną
    weekly_seasonality=True,    # Włącz sezonowość tygodniową
    daily_seasonality=False     # Wyłącz sezonowość dzienną
)

# Auto-detekcja (domyślne)
model = Prophet(
    yearly_seasonality='auto',  # Włącz jeśli dane > 2 lata
    weekly_seasonality='auto',  # Włącz jeśli dane > 2 tygodnie
    daily_seasonality='auto'    # Włącz jeśli dane godzinowe > 2 dni
)

Kontrola Sezonowości - Część 2

# Dostosuj fourier_order (elastyczność sezonowości)
model = Prophet()
model.add_seasonality(
    name='yearly',
    period=365.25,
    fourier_order=20,  # Domyślnie 10, wyższy = bardziej elastyczny
    prior_scale=10.0
)

# Kontrola elastyczności sezonowości
model = Prophet(
    seasonality_prior_scale=15.0  # Domyślnie 10.0
    # Wyższy = bardziej elastyczna sezonowość
    # Niższy = bardziej gładka sezonowość
)

Niestandardowa Sezonowość - Część 1

# Dodaj miesięczną sezonowość
model = Prophet(weekly_seasonality=False)
model.add_seasonality(
    name='monthly',
    period=30.5,        # ~30.5 dni w miesiącu
    fourier_order=5
)

# Dodaj kwartalną sezonowość
model.add_seasonality(
    name='quarterly',
    period=365.25/4,    # ~91.3 dni
    fourier_order=8,
    prior_scale=15.0
)

model.fit(df)

Niestandardowa Sezonowość - Część 2 (Warunkowa)

# Sezonowość warunkowa - tylko w określonych warunkach
# Przykład: sezonowość działa inaczej w weekendy
df['on_weekend'] = df['ds'].dt.weekday >= 5  # Sobota=5, Niedziela=6

model = Prophet()
model.add_seasonality(
    name='weekend_seasonality',
    period=7,
    fourier_order=3,
    condition_name='on_weekend'  # Tylko gdy on_weekend=True
)

# Future też musi mieć tę kolumnę!
future['on_weekend'] = future['ds'].dt.weekday >= 5

model.fit(df)
forecast = model.predict(future)

Holiday Effects

Modelowanie Świąt i Wydarzeń Specjalnych

Prophet pozwala modelować wpływ świąt i wydarzeń specjalnych.

Przykłady:

  • Święta państwowe (Boże Narodzenie, Wielkanoc)
  • Black Friday, Cyber Monday
  • Super Bowl, Mistrzostwa świata
  • Kampanie marketingowe
  • Konferencje firmowe

Format DataFrame ze świętami:

  • holiday - nazwa święta
  • ds - data
  • lower_window - dni przed (opcjonalne)
  • upper_window - dni po (opcjonalne)

Tworzenie Niestandardowych Świąt - Część 1

import pandas as pd

# Stwórz DataFrame z świętami
holidays = pd.DataFrame({
    'holiday': 'christmas',
    'ds': pd.to_datetime([
        '2020-12-25', '2021-12-25', '2022-12-25'
    ]),
    'lower_window': 0,   # Dzień święta
    'upper_window': 1,   # + 1 dzień po
})

# Dodaj więcej świąt
black_friday = pd.DataFrame({
    'holiday': 'black_friday',
    'ds': pd.to_datetime(['2020-11-27', '2021-11-26', '2022-11-25']),
    'lower_window': -1,  # 1 dzień przed
    'upper_window': 1,   # 1 dzień po
})

# Połącz wszystkie święta
holidays = pd.concat([holidays, black_friday])

Tworzenie Niestandardowych Świąt - Część 2

# Użyj świąt w modelu
model = Prophet(holidays=holidays)
model.fit(df)
forecast = model.predict(future)

# Zobacz wpływ świąt w prognozie
print(forecast[['ds', 'yhat', 'christmas', 'black_friday']].tail())

# Każde święto ma swoją kolumnę pokazującą jego wpływ

Built-in Country Holidays

Wbudowane Święta Krajowe

Prophet ma wbudowane święta dla wielu krajów!

Używa biblioteki holidays (Python).

from prophet import Prophet

# Dodaj święta polskie
model = Prophet()
model.add_country_holidays(country_name='PL')
model.fit(df)

# Dostępne kody krajów (wybrane):
# 'US' - USA
# 'UK' - Wielka Brytania
# 'DE' - Niemcy
# 'FR' - Francja
# 'PL' - Polska
# 'IT' - Włochy
# 'ES' - Hiszpania
# 'BR' - Brazylia
# 'CN' - Chiny
# 'JP' - Japonia
# ... i wiele więcej

# Zobacz jakie święta zostały dodane
print(model.train_holiday_names)
# ['New Year', 'Easter Monday', 'Corpus Christi', ...]

forecast = model.predict(future)

# Komponenty zawierają teraz wpływ świąt
model.plot_components(forecast)

Holidays for Subdivisions (Python)

Możesz dodać święta dla konkretnych regionów/stanów:

# Święta dla konkretnego stanu USA
model = Prophet()
model.add_country_holidays(
    country_name='US',
    subdiv='CA'  # Kalifornia
)
model.fit(df)

# Inne przykłady subdivisions:
# US: 'CA', 'NY', 'TX', 'FL', ...
# UK: 'England', 'Scotland', 'Wales', 'Northern Ireland'
# DE: 'BY' (Bawaria), 'BE' (Berlin), ...
# CA: 'ON' (Ontario), 'QC' (Quebec), ...

# Sprawdź dostępne subdivisions
import holidays
print(holidays.country_holidays('US').subdivisions)

# Połączenie kraju z custom holidays
custom_holidays = pd.DataFrame({
    'holiday': 'company_event',
    'ds': pd.to_datetime(['2021-03-15', '2022-03-15']),
})

model = Prophet(holidays=custom_holidays)
model.add_country_holidays(country_name='PL')
model.fit(df)

Regressors

Dodatkowe Zmienne (Additional Regressors)

Regressors to dodatkowe zmienne, które mogą wpływać na prognozę.

Przykłady:

  • Temperatura, pogoda
  • Wydatki na reklamę
  • Ceny konkurencji
  • Ruch na stronie internetowej
  • Wskaźniki ekonomiczne (inflacja, bezrobocie)

Wymagania:

  • Musisz mieć wartości regressora dla WSZYSTKICH dat (historycznych i przyszłych)
  • Jeśli nie masz wartości przyszłych, musisz je przewidzieć osobno

Dodawanie Regressors do Modelu - Część 1

import pandas as pd
import numpy as np

# Dane z dodatkową zmienną (temperatura)
df = pd.DataFrame({
    'ds': pd.date_range('2020-01-01', periods=365),
    'y': np.random.randn(365).cumsum() + 100,
    'temperature': np.random.uniform(0, 30, 365)  # Temperatura 0-30°C
})

# PRZED fit(): dodaj regressor do modelu
model = Prophet()
model.add_regressor(
    name='temperature',
    prior_scale=0.5,  # Regularyzacja (domyślnie 10.0)
    standardize='auto',  # Automatyczna standaryzacja
    mode='additive'  # 'additive' (domyślne) lub 'multiplicative'
)

model.fit(df)

Dodawanie Regressors do Modelu - Część 2

# Future MUSI mieć kolumnę 'temperature'!
future = model.make_future_dataframe(periods=30)

# Musisz przewidzieć przyszłe wartości temperatury
# Opcja 1: Prosta prognoza (średnia)
future['temperature'] = df['temperature'].mean()

# Opcja 2: Sezonowa prognoza
# future['temperature'] = forecast_temperature_model.predict(future)

forecast = model.predict(future)

# Zobacz wpływ temperatury
print(forecast[['ds', 'yhat', 'temperature']].tail())

Wiele Regressors - Część 1

# Dane z wieloma zmiennymi dodatkowymi
df = pd.DataFrame({
    'ds': pd.date_range('2020-01-01', periods=365),
    'y': np.random.randn(365).cumsum() + 1000,
    'ad_spend': np.random.uniform(1000, 5000, 365),  # Wydatki na reklamę
    'temperature': np.random.uniform(0, 30, 365),
    'competitor_price': np.random.uniform(50, 150, 365)
})

# Dodaj wszystkie regressors
model = Prophet()

model.add_regressor('ad_spend', prior_scale=0.5)
model.add_regressor('temperature', prior_scale=0.3)
model.add_regressor('competitor_price', prior_scale=0.7)

model.fit(df)

Wiele Regressors - Część 2

# Future z wszystkimi regressors
future = model.make_future_dataframe(periods=30)
future['ad_spend'] = 3000  # Planowany budżet reklamowy
future['temperature'] = 15  # Średnia temperatura
future['competitor_price'] = 100  # Przewidywana cena konkurencji

forecast = model.predict(future)

# Zobacz wkład każdego regressora
model.plot_components(forecast)
# Wykres pokaże osobne linie dla każdego regressora

Multiplicative Regressors

Additive vs Multiplicative:

  • Additive (domyślny): efekt dodawany do prognozy
  • Multiplicative: efekt mnożony przez prognozę

# Przykład: promocja zwiększa sprzedaż o % (multiplicative)
df['promotion'] = 0  # 0 = brak promocji, 1 = promocja aktywna

# Dodaj dni promocyjne
df.loc[df['ds'].isin(promo_dates), 'promotion'] = 1

model = Prophet()

# Multiplicative regressor
model.add_regressor(
    name='promotion',
    mode='multiplicative',  # Efekt procentowy
    prior_scale=0.5
)

model.fit(df)

# Future z informacją o planowanych promocjach
future = model.make_future_dataframe(periods=60)
future['promotion'] = 0
future.loc[future['ds'].isin(future_promo_dates), 'promotion'] = 1

forecast = model.predict(future)

# Multiplicative: yhat = baseline * (1 + promotion_effect)
# Additive: yhat = baseline + promotion_effect

Cross-Validation dla Szeregów Czasowych

Prophet używa Time Series Cross-Validation:

  • Szacuje błąd out-of-sample
  • Zachowuje kolejność chronologiczną
  • Używa expanding window (rozszerzające się okno)

Parametry cross_validation():

  • initial - początkowy okres treningowy (np. '730 days')
  • period - jak często tworzyć cutoff (np. '180 days')
  • horizon - jak daleko prognozować (np. '365 days')

from prophet.diagnostics import cross_validation

# Cross-validation
df_cv = cross_validation(
    model,
    initial='730 days',    # Minimum 2 lata danych treningowych
    period='180 days',     # Nowy cutoff co 180 dni
    horizon='365 days'     # Prognozuj 365 dni w przód
)

# df_cv zawiera:
# - ds: data prognozy
# - yhat: prognozowana wartość
# - yhat_lower, yhat_upper: przedziały ufności
# - y: rzeczywista wartość
# - cutoff: data końca okresu treningowego

print(f"Liczba prognoz: {len(df_cv)}")
print(df_cv.head())

Performance Metrics - Metryki Wydajności

from prophet.diagnostics import performance_metrics
from prophet.plot import plot_cross_validation_metric
import matplotlib.pyplot as plt

# Oblicz metryki dla różnych horyzontów
df_metrics = performance_metrics(df_cv)

print(df_metrics)
#    horizon        mse       rmse        mae       mape    mdape  coverage
# 0   37 days   12.34  3.51234  2.67890  0.02567  0.02134    0.923
# 1   74 days   15.67  3.95234  3.12345  0.03012  0.02567    0.912
# 2  111 days   18.90  4.34567  3.45678  0.03456  0.02890    0.901

Performance Metrics - Opis Metryk

Metryki:

  • mse: Mean Squared Error
  • rmse: Root Mean Squared Error
  • mae: Mean Absolute Error
  • mape: Mean Absolute Percentage Error
  • mdape: Median Absolute Percentage Error
  • coverage: % wartości w przedziale ufności

# Wizualizacja MAPE vs horizon
fig = plot_cross_validation_metric(df_cv, metric='mape')
plt.title('MAPE w zależności od horyzontu prognozy')
plt.show()

# Wizualizacja RMSE
fig = plot_cross_validation_metric(df_cv, metric='rmse')
plt.show()

Parallelizing Cross Validation - Część 1

Cross-validation może być wolny dla dużych zbiorów danych. Prophet wspiera równoległe przetwarzanie!

from prophet.diagnostics import cross_validation
import multiprocessing

# Sprawdź liczbę rdzeni CPU
n_cores = multiprocessing.cpu_count()
print(f"Dostępne rdzenie: {n_cores}")

# Metoda 1: Użyj parallel z cross_validation (Python)
# Prophet automatycznie używa wszystkich dostępnych rdzeni
df_cv = cross_validation(
    model,
    initial='730 days',
    period='180 days',
    horizon='365 days',
    parallel='processes'  # 'processes', 'threads' lub None
)

Parallelizing Cross Validation - Część 2

# Metoda 2: Równoległe testowanie wielu modeli z joblib
from joblib import Parallel, delayed

def evaluate_model(params):
    model = Prophet(**params)
    model.fit(df)
    df_cv = cross_validation(model, initial='365 days',
                            period='90 days', horizon='180 days')
    df_metrics = performance_metrics(df_cv)
    return df_metrics['mape'].mean()

# Równoległe testowanie wielu modeli
results = Parallel(n_jobs=-1)(  # -1 = użyj wszystkich rdzeni
    delayed(evaluate_model)(params) for params in param_list
)

print(f"Przyspieszenie: ~{n_cores}x")

Hyperparameter Tuning - Grid Search

Najważniejsze hiperparametry do dostrojenia:

  • changepoint_prior_scale - elastyczność trendu (0.001-0.5)
  • seasonality_prior_scale - elastyczność sezonowości (0.01-10)
  • holidays_prior_scale - wpływ świąt (0.01-10)
  • seasonality_mode - 'additive' vs 'multiplicative'

import itertools
from prophet.diagnostics import cross_validation, performance_metrics

# Parametry do przetestowania
param_grid = {
    'changepoint_prior_scale': [0.001, 0.01, 0.1, 0.5],
    'seasonality_prior_scale': [0.01, 0.1, 1.0, 10.0],
    'holidays_prior_scale': [0.01, 0.1, 1.0, 10.0],
    'seasonality_mode': ['additive', 'multiplicative']
}

# Wygeneruj wszystkie kombinacje
all_params = [dict(zip(param_grid.keys(), v))
              for v in itertools.product(*param_grid.values())]

print(f"Liczba kombinacji: {len(all_params)}")

# Lista na wyniki
results = []

# Testuj każdą kombinację
for params in all_params:
    model = Prophet(**params)
    model.fit(df)

    df_cv = cross_validation(model, initial='730 days',
                            period='180 days', horizon='365 days')
    df_metrics = performance_metrics(df_cv)

    results.append({
        **params,
        'mape': df_metrics['mape'].mean(),
        'rmse': df_metrics['rmse'].mean()
    })

Analiza Wyników Tuningu - Część 1

# Utwórz DataFrame z wynikami
results_df = pd.DataFrame(results)

# Sortuj po MAPE
results_df = results_df.sort_values('mape')

print("Top 5 najlepszych modeli:")
print(results_df.head())

# Najlepsze parametry
best_params = results_df.iloc[0].to_dict()
print("\nNajlepsze parametry:")
for key, value in best_params.items():
    if key not in ['mape', 'rmse']:
        print(f"  {key}: {value}")

print(f"\nNajlepszy MAPE: {best_params['mape']:.4f}")
print(f"Najlepszy RMSE: {best_params['rmse']:.4f}")

Analiza Wyników Tuningu - Część 2

# Wizualizacja wpływu parametrów
import matplotlib.pyplot as plt

fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# Wpływ changepoint_prior_scale
results_df.groupby('changepoint_prior_scale')['mape'].mean().plot(
    ax=axes[0, 0], marker='o'
)
axes[0, 0].set_title('Changepoint Prior Scale vs MAPE')

# Wpływ seasonality_prior_scale
results_df.groupby('seasonality_prior_scale')['mape'].mean().plot(
    ax=axes[0, 1], marker='o'
)
axes[0, 1].set_title('Seasonality Prior Scale vs MAPE')

plt.tight_layout()
plt.show()

Random Search i Bayesian Optimization

Dla dużych przestrzeni parametrów Grid Search jest wolny. Użyj alternatywnych metod:

import numpy as np
from sklearn.model_selection import RandomizedSearchCV

# Random Search - losowo próbkuj przestrzeń parametrów
param_distributions = {
    'changepoint_prior_scale': np.logspace(-3, 0, 20),  # 0.001 do 1
    'seasonality_prior_scale': np.logspace(-2, 1, 20),  # 0.01 do 10
    'holidays_prior_scale': np.logspace(-2, 1, 20)
}

# Losuj 50 kombinacji zamiast testować wszystkie
n_iter = 50
results = []

for i in range(n_iter):
    params = {
        'changepoint_prior_scale': np.random.choice(
            param_distributions['changepoint_prior_scale']
        ),
        'seasonality_prior_scale': np.random.choice(
            param_distributions['seasonality_prior_scale']
        ),
        'holidays_prior_scale': np.random.choice(
            param_distributions['holidays_prior_scale']
        )
    }

    model = Prophet(**params)
    model.fit(df)
    df_cv = cross_validation(model, initial='365 days',
                            period='90 days', horizon='180 days')
    df_metrics = performance_metrics(df_cv)

    results.append({**params, 'mape': df_metrics['mape'].mean()})

# Najlepszy wynik
best = min(results, key=lambda x: x['mape'])
print("Najlepsze parametry (Random Search):", best)

Uncertainty Intervals - Przedziały Ufności

# Domyślnie Prophet daje 95% przedział ufności

# Zmień szerokość przedziału
model = Prophet(
    interval_width=0.80  # 80% przedział ufności
)
model.fit(df)
forecast = model.predict(future)

# forecast zawiera:
# - yhat: prognoza (median)
# - yhat_lower: dolna granica (10% percentyl dla interval_width=0.80)
# - yhat_upper: górna granica (90% percentyl)

print(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail())

Uncertainty Intervals - Kontrola Przedziałów

# Szerszy przedział (99%)
model_wide = Prophet(interval_width=0.99)
model_wide.fit(df)
forecast_wide = model_wide.predict(future)

# Węższy przedział (50%)
model_narrow = Prophet(interval_width=0.50)
model_narrow.fit(df)
forecast_narrow = model_narrow.predict(future)

# Kontroluj liczbę próbek (dokładność przedziałów)
model = Prophet(
    uncertainty_samples=2000  # Domyślnie 1000
)

Outliers - Wykrywanie i Obsługa

Outliers to wartości znacząco odstające od reszty danych. Prophet jest odporny, ale ekstrema mogą wpływać na prognozę.

Rodzaje outliers:

  • Błędy pomiarowe
  • Jednorazowe wydarzenia (awarie, promocje)
  • Anomalie w danych

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# Wczytaj dane
df = pd.read_csv('data.csv')

# Metoda 1: IQR (Interquartile Range)
def detect_outliers_iqr(df, column='y', threshold=1.5):
    Q1 = df[column].quantile(0.25)
    Q3 = df[column].quantile(0.75)
    IQR = Q3 - Q1

    lower_bound = Q1 - threshold * IQR
    upper_bound = Q3 + threshold * IQR

    outliers = (df[column] < lower_bound) | (df[column] > upper_bound)

    print(f"Znaleziono {outliers.sum()} outliers")
    return outliers

# Metoda 2: Z-score (odległość od średniej w odchyleniach std)
def detect_outliers_zscore(df, column='y', threshold=3):
    mean = df[column].mean()
    std = df[column].std()

    z_scores = np.abs((df[column] - mean) / std)
    outliers = z_scores > threshold

    print(f"Znaleziono {outliers.sum()} outliers (Z-score)")
    return outliers

# Wizualizacja
outliers_iqr = detect_outliers_iqr(df)
plt.figure(figsize=(14, 5))
plt.plot(df['ds'], df['y'], label='Dane')
plt.scatter(df.loc[outliers_iqr, 'ds'],
           df.loc[outliers_iqr, 'y'],
           color='red', s=100, label='Outliers')
plt.legend()
plt.show()
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# Wczytaj dane
df = pd.read_csv('data.csv')

# Metoda 1: IQR (Interquartile Range)
def detect_outliers_iqr(df, column='y', threshold=1.5):
    Q1 = df[column].quantile(0.25)
    Q3 = df[column].quantile(0.75)
    IQR = Q3 - Q1

    lower_bound = Q1 - threshold * IQR
    upper_bound = Q3 + threshold * IQR

    outliers = (df[column] < lower_bound) | (df[column] > upper_bound)

    print(f"Znaleziono {outliers.sum()} outliers")
    return outliers

# Metoda 2: Z-score (odległość od średniej w odchyleniach std)
def detect_outliers_zscore(df, column='y', threshold=3):
    mean = df[column].mean()
    std = df[column].std()

    z_scores = np.abs((df[column] - mean) / std)
    outliers = z_scores > threshold

    print(f"Znaleziono {outliers.sum()} outliers (Z-score)")
    return outliers

# Wizualizacja
outliers_iqr = detect_outliers_iqr(df)
plt.figure(figsize=(14, 5))
plt.plot(df['ds'], df['y'], label='Dane')
plt.scatter(df.loc[outliers_iqr, 'ds'],
           df.loc[outliers_iqr, 'y'],
           color='red', s=100, label='Outliers')
plt.legend()
plt.show()

Outliers - Usuwanie

# Opcja 1: Usuń outliers całkowicie
def remove_outliers(df, column='y', threshold=1.5):
    Q1 = df[column].quantile(0.25)
    Q3 = df[column].quantile(0.75)
    IQR = Q3 - Q1

    lower = Q1 - threshold * IQR
    upper = Q3 + threshold * IQR

    df_clean = df[(df[column] >= lower) & (df[column] <= upper)]
    print(f"Usunięto {len(df) - len(df_clean)} wierszy")
    return df_clean

df_no_outliers = remove_outliers(df)

# Opcja 2: Zastąp outliers NaN (Prophet interpoluje)
def replace_outliers_with_nan(df, column='y', threshold=3):
    mean = df[column].mean()
    std = df[column].std()

    df_copy = df.copy()
    mask = np.abs((df_copy[column] - mean) / std) > threshold
    df_copy.loc[mask, column] = np.nan

    print(f"Zastąpiono {mask.sum()} wartości na NaN")
    return df_copy

df_with_nans = replace_outliers_with_nan(df)

Outliers - Winsoryzacja i Porównanie

# Opcja 3: Winsoryzacja - obetnij do percentyli
def winsorize(df, column='y', lower=0.01, upper=0.99):
    lower_val = df[column].quantile(lower)
    upper_val = df[column].quantile(upper)

    df_copy = df.copy()
    df_copy[column] = df_copy[column].clip(lower_val, upper_val)
    return df_copy

df_winsorized = winsorize(df)

# Trenuj modele i porównaj
model1 = Prophet().fit(df_no_outliers)
model2 = Prophet().fit(df_with_nans)
model3 = Prophet().fit(df_winsorized)

# Porównaj prognozy
future = model1.make_future_dataframe(periods=30)
forecast1 = model1.predict(future)
forecast2 = model2.predict(future)
forecast3 = model3.predict(future)

Handling Shocks - Obsługa Wstrząsów

Shocks (wstrząsy) to nagłe, nieoczekiwane zmiany w danych, które trwają przez pewien czas.

Przykłady:

  • COVID-19 lockdown
  • Kryzys finansowy
  • Zmiana regulacji prawnych
  • Awaria systemów
  • Viralowa kampania marketingowa

Różnica: Outlier vs Shock

  • Outlier: pojedyncza wartość odstająca
  • Shock: trwała zmiana poziomu lub trendu

Modelowanie Shocks przez Regressor

Użyj binary regressor (0/1) do oznaczenia okresu wstrząsu:

import pandas as pd
from prophet import Prophet

# Dane z wstrząsem (np. COVID-19)
df = pd.read_csv('sales_data.csv')

# Dodaj kolumnę oznaczającą okres lockdown
df['lockdown'] = 0
df.loc[(df['ds'] >= '2020-03-15') &
       (df['ds'] <= '2020-06-01'), 'lockdown'] = 1

# Model z regressorem
model = Prophet()
model.add_regressor('lockdown', mode='additive')
model.fit(df)

# Future musi zawierać wartości regressora
future = model.make_future_dataframe(periods=90)
future['lockdown'] = 0  # Zakładamy brak lockdown w przyszłości

# Lub modeluj stopniowy powrót do normalności
# future['lockdown'] = np.linspace(0.5, 0, len(future))

forecast = model.predict(future)

# Zobacz wpływ lockdown
print(forecast[['ds', 'lockdown', 'yhat']].head(20))

# Komponenty pokażą wpływ lockdown
model.plot_components(forecast)

Modelowanie Shocks przez Changepoints

Jeśli shock zmienił trend na stałe, użyj ręcznych changepoints:

# Określ daty kluczowych wstrząsów
changepoints = [
    '2020-03-15',  # Początek lockdown
    '2020-06-01',  # Koniec lockdown
    '2021-01-01',  # Nowa strategia
]

model = Prophet(
    changepoints=changepoints,
    changepoint_prior_scale=0.5  # Większa elastyczność w tych punktach
)
model.fit(df)

# Opcja: Usuń dane z okresu shock dla czystej prognozy
# Jeśli shock był tymczasowy i nie powtórzy się

df_before_shock = df[df['ds'] < '2020-03-15']
df_after_shock = df[df['ds'] > '2020-06-01']
df_no_shock = pd.concat([df_before_shock, df_after_shock])

model_clean = Prophet()
model_clean.fit(df_no_shock)

# Porównaj prognozy
fig, axes = plt.subplots(1, 2, figsize=(16, 5))

model.plot(forecast, ax=axes[0])
axes[0].set_title('Z uwzględnieniem shock')

forecast_clean = model_clean.predict(
    model_clean.make_future_dataframe(periods=90)
)
model_clean.plot(forecast_clean, ax=axes[1])
axes[1].set_title('Bez shock (dane usunięte)')

plt.show()

Strategie Obsługi Shocks

 

Wybierz strategię w zależności od typu shock:

1. Shock tymczasowy (powrót do normalności):

  • Użyj binary regressor (0/1)
  • Lub oznacz jako outliers i zastąp NaN
  • Lub dodaj jako holiday z window

2. Shock trwały (nowa rzeczywistość):

  • Dodaj manual changepoint w momencie shock
  • Zwiększ changepoint_prior_scale
  • Trenuj model tylko na danych po shock

 

Strategie Obsługi Shocks

 

Wybierz strategię w zależności od typu shock:

 

3. Shock nieznany (nie wiesz czy trwały):

  • Trenuj 2 modele: z shock i bez
  • Monitoruj nowe dane
  • Dostosuj model gdy sytuacja się wyjaśni

4. Multiple shocks:

  • Dodaj regressor dla każdego shock
  • Lub użyj wielu changepoints

 

Dane Nie-dzienne - Godzinowe

# Dane godzinowe
df_hourly = pd.DataFrame({
    'ds': pd.date_range('2020-01-01', periods=24*365, freq='H'),
    'y': np.random.randn(24*365).cumsum() + 100
})

model = Prophet(
    daily_seasonality=True  # Włącz sezonowość dzienną
)
model.fit(df_hourly)

# Prognoza na 7 dni (168 godzin)
future = model.make_future_dataframe(periods=168, freq='H')
forecast = model.predict(future)

Dane Nie-dzienne - Miesięczne

# Dane miesięczne
df_monthly = pd.DataFrame({
    'ds': pd.date_range('2010-01-01', periods=120, freq='MS'),  # MS = month start
    'y': np.random.randn(120).cumsum() + 1000
})

model = Prophet(
    yearly_seasonality=True,
    weekly_seasonality=False,
    daily_seasonality=False
)
model.fit(df_monthly)

# Prognoza na 12 miesięcy
future = model.make_future_dataframe(periods=12, freq='MS')
forecast = model.predict(future)

Zapisywanie i Ładowanie Modelu - Pickle

import pickle

# Metoda 1: Pickle (Python standard)
with open('prophet_model.pkl', 'wb') as f:
    pickle.dump(model, f)

# Ładowanie
with open('prophet_model.pkl', 'rb') as f:
    loaded_model = pickle.load(f)

# Użyj załadowanego modelu
future = loaded_model.make_future_dataframe(periods=30)
forecast = loaded_model.predict(future)

Zapisywanie i Ładowanie Modelu - JSON

from prophet.serialize import model_to_json, model_from_json

# Metoda 2: JSON (zalecana, bardziej portable)
# Zapisz
with open('prophet_model.json', 'w') as f:
    f.write(model_to_json(model))

# Załaduj
with open('prophet_model.json', 'r') as f:
    loaded_model = model_from_json(f.read())

# Użyj załadowanego modelu
future = loaded_model.make_future_dataframe(periods=30)
forecast = loaded_model.predict(future)

# Zapisz też DataFrame z danymi
df.to_csv('training_data.csv', index=False)

Praktyczny Przykład - Prognoza Sprzedaży (1)

import pandas as pd
from prophet import Prophet

# 1. Wczytaj dane sprzedażowe
df = pd.read_csv('sales_data.csv')
df['ds'] = pd.to_datetime(df['date'])
df['y'] = df['sales']
df = df[['ds', 'y']]

# 2. Dodaj informacje o promocjach i pogodzie
df['promotion'] = 0
df.loc[df['ds'].isin(promo_dates), 'promotion'] = 1
df['temperature'] = temperature_data

# 3. Święta
holidays = pd.DataFrame({
    'holiday': 'black_friday',
    'ds': pd.to_datetime(['2020-11-27', '2021-11-26', '2022-11-25']),
    'lower_window': -2,
    'upper_window': 2
})

Praktyczny Przykład - Prognoza Sprzedaży (2)

# 4. Model
model = Prophet(
    holidays=holidays,
    seasonality_mode='multiplicative',  # Sezonowość procentowa
    changepoint_prior_scale=0.05
)
model.add_country_holidays(country_name='PL')
model.add_regressor('promotion', mode='multiplicative')
model.add_regressor('temperature')

# 5. Trenuj model
model.fit(df)

print("Model wytrenowany pomyślnie!")

Praktyczny Przykład - Prognoza (3)

# 6. Future z regressors
future = model.make_future_dataframe(periods=90)

# Dodaj wartości regressors dla przyszłości
future['promotion'] = 0
future.loc[future['ds'].isin(future_promos), 'promotion'] = 1
future['temperature'] = future_temperature_forecast

# 7. Prognoza
forecast = model.predict(future)

# 8. Analiza wyników
print("Prognoza na najbliższe 7 dni:")
print(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail(7))

Praktyczny Przykład - Wizualizacja (4)

# 9. Wizualizacja
import matplotlib.pyplot as plt

fig1 = model.plot(forecast)
plt.title('Prognoza sprzedaży na 90 dni')
plt.show()

fig2 = model.plot_components(forecast)
plt.show()

# 10. Zapisz wyniki
forecast.to_csv('sales_forecast.csv', index=False)

print("Prognoza zapisana do pliku sales_forecast.csv")

Best Practices - Dobre Praktyki

1. Przygotowanie danych:

  • Minimum kilka miesięcy danych historycznych
  • Kolumny MUSZĄ nazywać się 'ds' i 'y'
  • Usuń lub oznacz outliers
  • Prophet radzi sobie z brakami danych (NaN)

2. Modelowanie:

  • Zacznij od prostego modelu, potem dodawaj złożoność
  • Użyj cross-validation do tuningu
  • Dodaj święta i wydarzenia specjalne
  • Użyj regressors jeśli masz dodatkowe dane

3. Ewaluacja:

  • Zawsze sprawdź komponenty (plot_components)
  • Użyj cross_validation dla rzetelnej ewaluacji
  • Wizualizuj prognozy
  • Porównaj z prostymi baseline'ami

Częste Problemy i Rozwiązania

❌ Problem 1: Kolumny nie nazywają się 'ds' i 'y'

✅ Rozwiązanie: df = df.rename(columns={'date': 'ds', 'value': 'y'})

❌ Problem 2: Overfitting (za dużo changepoints)

✅ Rozwiązanie: Zmniejsz changepoint_prior_scale (np. 0.01)

❌ Problem 3: Underfitting (za gładki trend)

✅ Rozwiązanie: Zwiększ changepoint_prior_scale (np. 0.5)

❌ Problem 4: Brak wartości regressora w future

✅ Rozwiązanie: Dodaj kolumnę do future DataFrame

❌ Problem 5: Wolny trening

✅ Rozwiązanie: Zmniejsz uncertainty_samples, użyj mniej regressors

❌ Problem 6: Instalacja pystan nie działa

✅ Rozwiązanie: Użyj conda install -c conda-forge prophet

Podsumowanie

Czego się nauczyliśmy:

  • Czym jest Facebook Prophet i kiedy go używać
  • Instalacja i podstawowe użycie (Quick Start)
  • Python API - parametry i metody
  • Saturating Forecasts - prognozy z ograniczeniami (cap, floor)
  • Trend Changepoints - automatyczna detekcja i ręczne określanie
  • Seasonality - sezonowość roczna, tygodniowa, niestandardowa
  • Holiday Effects - modelowanie świąt i wydarzeń
  • Country Holidays - wbudowane święta dla wielu krajów
  • Regressors - dodawanie zmiennych zewnętrznych
  • Cross-validation i performance metrics
  • Parallelizing cross validation - przyspieszenie obliczeń
  • Hyperparameter tuning - Grid Search i Random Search
  • Outliers - wykrywanie i różne metody obsługi (IQR, Z-score, winsoryzacja)
  • Handling Shocks - strategie modelowania wstrząsów (regressors, changepoints)
  • Best practices i rozwiązywanie problemów

Zasoby i Dalsze Kroki

Oficjalna dokumentacja:

  • https://facebook.github.io/prophet/
  • Quick Start: https://facebook.github.io/prophet/docs/quick_start.html
  • GitHub: https://github.com/facebook/prophet

Dalsze tematy do nauki:

  • Seasonality modes - additive vs multiplicative
  • Sub-daily data - dane minutowe
  • Prophet w R - alternatywna implementacja
  • Ensemble methods - łączenie z innymi modelami
  • Real-time forecasting - aktualizacje na bieżąco

Alternatywne biblioteki:

  • ARIMA/SARIMA (statsmodels)
  • LSTM (TensorFlow/Keras)
  • XGBoost dla szeregów czasowych
  • NeuralProphet - następca Prophet z neural networks

Dziękuję za Uwagę!

Pytania?

"The best time to plant a tree was 20 years ago. The second best time is now." - Najlepszy czas na prognozowanie to teraz!

Powodzenia z prognozowaniem! 📈🔮

Facebook Prophet - Prognozowanie Szeregów Czasowych w Pythonie

By noinputsignal

Private

Facebook Prophet - Prognozowanie Szeregów Czasowych w Pythonie