[Python] Facebook Prophet - Not getting desired result

Discussão em 'Python' iniciado por Stack, Abril 8, 2025.

  1. Stack

    Stack Membro Participativo

    I am relatively new to Python and I understand a little bit of Data Science here and there...

    My problem is, I am trying to setup an AI focusing on water consumption rates and the goal is to make the model predict values in that 95% confidence interval.

    The data I got is structured pretty poorly, but I managed via scripts to "clean" and format them properly for my Prophet.

    Now the thing is, I have been trying quite some time to tweak Prophet, but I don't know if the data I got is not sufficient (around 9 years (in days) for one location and around 7 years (in days as well) for the other) or if I failed to train Prophet properly (such as ignoring anomalies or similar).

    Even with ChatGPT4o, ChatGPT 4.5 or even the customized ChatGPT models such as "Python" - they did not help me out that much with this matter.

    Here is an example of my Prophet-plot-output: Prophet output

    Red is the actual value and blue is what Prophet predicted for that time-frame.

    TL;DR - I do not need every single column from the CSVs it's reading, and I need some help to properly tweak Prophet (if possible). I can provide one example CSV and would appreciate any help.

    Code (for example the output above):

    import os
    import pandas as pd
    from prophet import Prophet
    import matplotlib.pyplot as plt
    import numpy as np

    input_folder = 'Example-Folder'
    forecast_folder_path = 'Example-Folder_forecast'
    os.makedirs(forecast_folder_path, exist_ok=True)

    needed_columns = {
    'B': "Example-Location"
    'C': "Example-Location"
    'D': "Example-Location"
    'E': ""Example-Location"
    'F': "Example-Location"
    }
    column_indices = {'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5}

    combined_data = pd.DataFrame()
    all_forecasts = {}

    for file_name in os.listdir(input_folder):
    if file_name.endswith('.csv') and '0125' not in file_name:
    file_path = os.path.join(input_folder, file_name)
    df = pd.read_csv(file_path, delimiter=';', on_bad_lines='skip', header=None)
    if df.shape[1] >= 6:
    cols = [0] + list(column_indices.values())
    df = df.iloc[:, cols]
    df.columns = ['ds'] + [needed_columns[key] for key in column_indices]
    df['ds'] = pd.to_datetime(df['ds'], errors='coerce')
    for col in df.columns[1:]:
    df[col] = pd.to_numeric(df[col], errors='coerce')
    df[col] = df[col].apply(lambda x: x if x > 0 else np.nan)
    df = df.ffill().bfill()
    combined_data = pd.concat([combined_data, df])

    combined_data = combined_data[combined_data['ds'] <= pd.to_datetime('2024-12-31')]

    actual_jan_path = os.path.join(input_folder, 'j25_m01_Mengen3_m_0125.csv')
    actual_jan_df = pd.read_csv(actual_jan_path, delimiter=';', header=None)
    actual_jan_df = actual_jan_df.iloc[:, [0] + list(column_indices.values())]
    actual_jan_df.columns = ['ds'] + [needed_columns[key] for key in column_indices]
    actual_jan_df['ds'] = pd.to_datetime(actual_jan_df['ds'], errors='coerce')
    for col in actual_jan_df.columns[1:]:
    actual_jan_df[col] = pd.to_numeric(actual_jan_df[col], errors='coerce')

    for col in combined_data.columns[1:]:
    print(f"Processing {col}...")
    container_data = combined_data[['ds', col]].copy().dropna()
    container_data.columns = ['ds', 'y']

    if len(container_data) < 250:
    print(f"Not enough data for {col}. Skipping.")
    continue

    y_max_cap = container_data['y'].quantile(0.99)
    container_data = container_data[container_data['y'] <= y_max_cap]

    y_min = container_data['y'].min()
    y_max = container_data['y'].max()
    y_mean = container_data['y'].mean()

    container_data['y'] = np.log1p(container_data['y'])

    model = Prophet(
    daily_seasonality=False,
    weekly_seasonality=False,
    yearly_seasonality=False,
    changepoint_prior_scale=0.01,
    seasonality_prior_scale=2.0,
    n_changepoints=20,
    interval_width=0.9
    )

    model.add_seasonality(name='monthly', period=30.5, fourier_order=6, prior_scale=5)
    model.add_seasonality(name='biweekly', period=14, fourier_order=4, prior_scale=3)
    model.add_seasonality(name='weekend', period=7, fourier_order=3, prior_scale=2)
    model.fit(container_data)

    future = pd.date_range(start='2025-01-01', end='2025-01-31')
    future_df = pd.DataFrame({'ds': future})
    forecast = model.predict(future_df)
    forecast['yhat'] = np.expm1(forecast['yhat'])
    forecast['yhat'] = forecast['yhat'].clip(lower=y_min, upper=y_max)
    forecast['yhat'] = forecast['yhat'].apply(lambda x: y_mean if x <= 0 else x).round(2)

    all_forecasts[col] = forecast[['ds', 'yhat']].rename(columns={'yhat': f'{col}_forecast'})

    combined_forecasts = all_forecasts[list(all_forecasts.keys())[0]][['ds']].copy()
    for forecast_df in all_forecasts.values():
    combined_forecasts = pd.merge(combined_forecasts, forecast_df, on='ds')
    combined_forecasts.to_csv(os.path.join(forecast_folder_path, 'forecast_mengen3_m_filtered.csv'), index=False)

    for col in all_forecasts:
    plt.figure(figsize=(10, 6))
    actual = actual_jan_df[['ds', col]].copy().dropna()
    actual = actual.sort_values('ds')
    actual.columns = ['ds', 'actual']

    forecast = all_forecasts[col]
    merged = pd.merge(actual, forecast, on='ds', how='inner')

    actual['actual'] = actual['actual'].clip(lower=actual['actual'].quantile(0.01),
    upper=actual['actual'].quantile(0.99))

    plt.plot(actual['ds'], actual['actual'], color='red', marker='o', label=f'Actual {col}')
    plt.plot(forecast['ds'], forecast[f'{col}_forecast'], color='blue', marker='o', label=f'Forecasted {col}')
    plt.xlabel('Date')
    plt.ylabel(f'{col} Water Volume (m³)')
    plt.title(f'Forecasted Water Volume for {col} vs Actual')
    plt.xlim(pd.to_datetime("2025-01-01"), pd.to_datetime("2025-01-31"))
    plt.xticks(rotation=45)
    plt.grid(True)
    plt.legend()
    plt.tight_layout()
    plt.show()

    Continue reading...

Compartilhe esta Página