ExponentialSmoothing - Какой метод прогнозирования использовать для этого графика даты? - PullRequest
2 голосов
/ 06 марта 2020

В настоящее время у меня есть эти данные по сравнению с накопленной суммой. Я хочу предсказать совокупную сумму для будущих дат, используя python. Какой метод прогнозирования я должен использовать?

Plot of date vs cumulative sum

Мои серии дат в этом формате: ['2020-01-20', '2020-01-24', '2020-01-26', '2020-01-27', '2020-01-30', '2020-01-31'] dtype='datetime64[ns]'

  • Я пытался сплайн, но кажется, что сплайн не может обработать ряд даты и времени
  • Я попытался с помощью экспоненциального сглаживания для прогнозирования временных рядов, но результат неверен. Я не понимаю, что означает предикат (3) и почему он возвращает предсказанную сумму для дат, которые у меня уже есть. Я скопировал этот код из примера. Вот мой код для сглаживания выражений:

    fit1 = ExponentialSmoothing(date_cumsum_df).fit(smoothing_level=0.3,optimized=False)
    
    fcast1 = fit1.predict(3)
    
    fcast1
    
    
    
    2020-01-27       1.810000
    2020-01-30       2.467000
    2020-01-31       3.826900
    2020-02-01       5.978830
    2020-02-02       7.785181
    2020-02-04       9.949627
    2020-02-05      11.764739
    2020-02-06      14.535317
    2020-02-09      17.374722
    2020-02-10      20.262305
    2020-02-16      22.583614
    2020-02-18      24.808530
    2020-02-19      29.065971
    2020-02-20      39.846180
    2020-02-21      58.792326
    2020-02-22     102.054628
    2020-02-23     201.038240
    2020-02-24     321.026768
    2020-02-25     474.318737
    2020-02-26     624.523116
    2020-02-27     815.166181
    2020-02-28    1100.116327
    2020-02-29    1470.881429
    2020-03-01    1974.317000
    2020-03-02    2645.321900
    2020-03-03    3295.025330
    2020-03-04    3904.617731
    

Какой метод лучше всего подходит для прогнозирования значений суммы, которое кажется экспоненциально возрастающим? Также я довольно новичок в науке о данных с python, так что go легко для меня. Благодаря.

1 Ответ

2 голосов
/ 06 марта 2020

Экспоненциальное сглаживание работает только для данных без пропущенных значений временных рядов. Я покажу вам прогноз ваших данных на +5 дней в будущем для трех упомянутых вами методов:

  • Экспоненциальная аппроксимация (ваше предположение "кажется, экспоненциально увеличивается")
  • Сплайн-интерполяция
  • Экспоненциальное сглаживание

Примечание. Я получил ваши данные, похитив их с вашего графика, и сохранил даты в dates и значения данных в values

import pandas as pd
import numpy as np
from statsmodels.tsa.holtwinters import ExponentialSmoothing
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from scipy.optimize import curve_fit
from scipy.interpolate import splrep, splev

df = pd.DataFrame()
# mdates.date2num allows functions like curve_fit and spline to digest time series data
df['dates'] = mdates.date2num(dates)
df['values'] = values 

# Exponential fit function
def exponential_func(x, a, b, c, d):
    return a*np.exp(b*(x-c))+d

# Spline interpolation
def spline_interp(x, y, x_new):
    tck = splrep(x, y)
    return splev(x_new, tck)

# define forecast timerange (forecasting 5 days into future)
dates_forecast = np.linspace(df['dates'].min(), df['dates'].max() + 5, 100)
dd = mdates.num2date(dates_forecast)

# Doing exponential fit
popt, pcov = curve_fit(exponential_func, df['dates'], df['values'], 
                       p0=(1, 1e-2, df['dates'][0], 1))

# Doing spline interpolation
yy = spline_interp(df['dates'], df['values'], dates_forecast)

Пока прямо вперед (кроме функции mdates.date2num). Поскольку у вас есть пропущенные данные, вы должны использовать сплайн-интерполяцию к вашим фактическим данным, чтобы заполнить пропущенные временные точки интерполированными данными

# Interpolating data for exponential smoothing (no missing data in time series allowed)
df_interp = pd.DataFrame()
df_interp['dates'] = np.arange(dates[0], dates[-1] + 1, dtype='datetime64[D]')
df_interp['values'] = spline_interp(df['dates'], df['values'], 
                                    mdates.date2num(df_interp['dates']))
series_interp = pd.Series(df_interp['values'].values, 
                          pd.date_range(start='2020-01-19', end='2020-03-04', freq='D'))

# Now the exponential smoothing works fine, provide the `trend` argument given your data 
# has a clear (kind of exponential) trend
fit1 = ExponentialSmoothing(series_interp, trend='mul').fit(optimized=True)

Вы можете построить три метода и посмотреть, как их прогноз на предстоящие пять дней будет

# Plot data
plt.plot(mdates.num2date(df['dates']), df['values'], 'o')
# Plot exponential function fit
plt.plot(dd, exponential_func(dates_forecast, *popt))
# Plot interpolated values
plt.plot(dd, yy)
# Plot Exponential smoothing prediction using function `forecast`
plt.plot(np.concatenate([series_interp.index.values, fit1.forecast(5).index.values]),
     np.concatenate([series_interp.values, fit1.forecast(5).values]))

Сравнение всех трех методов показывает, что вы правильно выбрали экспоненциальное сглаживание. Это выглядит намного лучше при прогнозировании будущих пяти дней, чем другие два метода

enter image description here


Относительно вашего другого вопроса

Я не понимаю, что означает предикат (3) и почему он возвращает предсказанную сумму для дат, которые у меня уже есть.

ExponentialSmoothing.fit() возвращает объект statsmodels.tsa.holtwinters.HoltWintersResults которая имеет две функции, которые вы можете использовать для прогнозирования / прогнозирования значений: predict и forecast:

predict занимает start и end наблюдает за вашими данными и применяет модель ExponentialSmoothing к соответствующим значениям даты. Для прогнозирования значений в будущем вы должны указать параметр end, который будет в будущем

>> fit1.predict(start=np.datetime('2020-03-01'), end=np.datetime64('2020-03-09'))
2020-03-01    4240.649526
2020-03-02    5631.207307
2020-03-03    5508.614325
2020-03-04    5898.717779
2020-03-05    6249.810230
2020-03-06    6767.659081
2020-03-07    7328.416024
2020-03-08    7935.636353
2020-03-09    8593.169945
Freq: D, dtype: float64

В вашем примере predict(3) (который равен predict(start=3), прогнозирует значения на основе ваших дат, начиная с третья дата и без какого-либо прогнозирования.

forecast() выполняет только прогнозирование. Вы просто передаете число наблюдений, которое хотите прогнозировать в будущем.

>> fit1.forecast(5)
2020-03-05    6249.810230
2020-03-06    6767.659081
2020-03-07    7328.416024
2020-03-08    7935.636353
2020-03-09    8593.169945
Freq: D, dtype: float64

Поскольку обе функции основаны на той же модели ExponentialSmoothing.fit их значения равны для одинаковых дат.

...