def test_plot_series_uniform_treatment_of_int64_range_index_types(): """Test that int64 and range indices are treated the same without error.""" _check_soft_dependencies("matplotlib") import matplotlib.pyplot as plt y1 = pd.Series(np.arange(10)) y2 = pd.Series(np.random.normal(size=10)) y1.index = pd.Int64Index(y1.index) y2.index = pd.RangeIndex(y2.index) plot_series(y1, y2) plt.gcf().canvas.draw_idle()
def test_plot_series_uniform_treatment_of_int64_range_index_types(): # We test that int64 and range indices are treated uniformly and do not raise an # error of inconsistent index types _check_soft_dependencies("matplotlib") import matplotlib.pyplot as plt y1 = pd.Series(np.arange(10)) y2 = pd.Series(np.random.normal(size=10)) y1.index = pd.Int64Index(y1.index) y2.index = pd.RangeIndex(y2.index) plot_series(y1, y2) plt.gcf().canvas.draw_idle()
def plot(self): from sktime.utils.plotting import plot_series from io import BytesIO buf = BytesIO() fig, _ = plot_series(self.pd_past5days, labels=['past5days']) fig.savefig(buf) self.plot = buf.getvalue() self.next(self.end)
def load_forecast( data, model_path='Models/6689489_NaiveForecaster_2017-01_2019-04_5.model'): """ Load saved forcasting model and plotting Parameters ---------- data: pandas DataFrame main dataset with customer_id, product_id and Timestamp model_path: .model file path to previously saved model Returns ------- sMAPE Loss: print plot: matplotlib figure plot train, test and predicted values """ y_train, y_test = temporal_train_test_split( prepare_data(data, int(model_path.split('_')[0].split('/')[-1]), start=model_path.split('_')[-3], end=model_path.split('_')[-2]), test_size=int(model_path.split('_')[-1].split('.')[0])) fh = ForecastingHorizon(y_test.index, is_relative=False) f = load(model_path) y_pred = f.predict(fh) print('sMAPE Loss :', smape_loss(y_pred, y_test)) plot = plot_series(y_train, y_test, y_pred, labels=["y_train", "y_test", "y_pred"]) return plot
def _plot_series(series, ax=None, **kwargs): if isinstance(series, tuple): return plot_series(*series, ax=ax, **kwargs) else: return plot_series(series, ax=ax, **kwargs)
from sktime.forecasting.model_selection import ( ForecastingGridSearchCV, SlidingWindowSplitter, temporal_train_test_split, ) from sktime.forecasting.naive import NaiveForecaster from sktime.forecasting.theta import ThetaForecaster from sktime.forecasting.trend import PolynomialTrendForecaster from sktime.performance_metrics.forecasting import sMAPE, smape_loss from sktime.transformations.series.detrend import Deseasonalizer, Detrender from sktime.utils.plotting import plot_series y = load_airline() type(y) plot_series(y) y.index y_train, y_test = temporal_train_test_split(y, test_size = 24) plot_series(y_train, y_test) fh = ForecastingHorizon(y_test.index, is_relative=False) fh ets_frcstr = ExponentialSmoothing(trend='additive', seasonal='additive', sp=12) ets_frcstr.fit(y_train)
def forecast(data, customer_id, start='2017-01', end='2019-04', model_type='NaiveForecaster', test_size_month=5, model_storage_path=''): """ Main function for build forecasting model on selected customer and time interval, save the model and plotting Parameters ---------- data: pandas DataFrame main dataset with customer_id, product_id and Timestamp customer_id: int start: string start year and month in '2020-01' format end: string end year and month in '2020-01' format *** this month will not be included *** model_type: type of model to use in forecasting select from : ['NaiveForecaster', 'PolynomialTrendForecaster', 'ThetaForecaster', 'KNeighborsRegressor', 'ExponentialSmoothing', 'AutoETS', 'AutoARIMA', 'TBATS', 'BATS', 'EnsembleForecaster'] test_size_month: number of month that will be excluded from end of interval to use as test dataset model_storage_path: string the folder that you want to store saved models Returns ------- sMAPE Loss: print plot: matplotlib figure plot train, test and predicted values """ y_train, y_test = temporal_train_test_split(prepare_data(data, customer_id, start=start, end=end), test_size=test_size_month) fh = ForecastingHorizon(y_test.index, is_relative=False) if model_type == 'NaiveForecaster': forecaster = NaiveForecaster(strategy="last", sp=12) elif model_type == 'PolynomialTrendForecaster': forecaster = PolynomialTrendForecaster(degree=2) elif model_type == 'ThetaForecaster': forecaster = ThetaForecaster(sp=6) elif model_type == 'KNeighborsRegressor': regressor = KNeighborsRegressor(n_neighbors=1) forecaster = ReducedRegressionForecaster(regressor=regressor, window_length=12, strategy="recursive") elif model_type == 'ExponentialSmoothing': forecaster = ExponentialSmoothing(trend="add", seasonal="multiplicative", sp=12) elif model_type == 'AutoETS': forecaster = AutoETS(auto=True, sp=12, n_jobs=-1) elif model_type == 'AutoARIMA': forecaster = AutoARIMA(sp=12, suppress_warnings=True) elif model_type == 'TBATS': forecaster = TBATS(sp=12, use_trend=True, use_box_cox=False) elif model_type == 'BATS': forecaster = BATS(sp=12, use_trend=True, use_box_cox=False) elif model_type == 'EnsembleForecaster': forecaster = EnsembleForecaster([ ("ses", ExponentialSmoothing(seasonal="multiplicative", sp=12)), ( "holt", ExponentialSmoothing(trend="add", damped_trend=False, seasonal="multiplicative", sp=12), ), ( "damped", ExponentialSmoothing(trend="add", damped_trend=True, seasonal="multiplicative", sp=12), ), ]) try: forecaster.fit(y_train) except: forecaster.fit(y_train + 1) y_pred = forecaster.predict(fh) dump( forecaster, f'{model_storage_path}/{customer_id}_{model_type}_{start}_{end}_{test_size_month}.model' ) print('sMAPE Loss :', smape_loss(y_pred, y_test)) plot = plot_series(y_train, y_test, y_pred, labels=["y_train", "y_test", "y_pred"]) return plot
# setting graphs size plt.rcParams["figure.figsize"] = [16, 7] # for fancy plots plt.style.use('ggplot') df = pd.read_csv( 'https://raw.githubusercontent.com/selva86/datasets/master/a10.csv', parse_dates=['date'], index_col="date") df.index = pd.PeriodIndex(df.index, freq="M") series = df.T.iloc[0] plot_series(series) model_auto = AutoARIMA(sp=12, suppress_warnings=True).fit(series) summary = model_auto.summary() def get_params(summary_text): full = re.findall(r'SARIMAX\(.*?\)x\(.*?\)', summary_text)[0] info = [int(_) for _ in re.findall(r'\d+', full)] return info p, d, q, P, D, Q, S = get_params(summary.as_text()) y_train, y_test = temporal_train_test_split(series, test_size=24)
def app(): """ Part for creating web page """ state = _get_state() st.title("ARIMA модель") state.uploaded_file = st.sidebar.file_uploader("Выберите файл", type=['csv', 'xlsx', 'xls']) if state.uploaded_file is not None: state.data_frame = reading_data_frame(state.uploaded_file) state.column_to_predict = st.selectbox('Выберите колонку для обучения', state.data_frame.columns, key="column_training") if state.column_to_predict is not None: # state.data_frame = state.data_frame.dropna(subset=[state.column_to_predict]) state.tts = st.slider( 'Выберите необходимую величину обучающей выборки', 0.05, 0.5, (0.2), step=0.05, key='split_size') state.y_train, state.y_test = temporal_train_test_split( state.data_frame[state.column_to_predict], test_size=state.tts) with _lock: fig0, ax0 = plot_series(state.y_train, state.y_test, labels=['Train', 'Test']) st.pyplot(fig0) state.window = st.slider( 'Выберите необходимую величину rolling window', 1, 20, (5), step=1, key='window') state.rolling_mean = state.data_frame[ state.column_to_predict].rolling(window=state.window).mean() state.rolling_std = state.data_frame[ state.column_to_predict].rolling(window=state.window).std() with _lock: fig1, ax1 = plt.subplots() state.data_frame[state.column_to_predict].plot() ax1.plot(state.rolling_mean, color='red', label='Rolling Mean') ax1.plot(state.rolling_std, color='black', label='Rolling Std') ax1.legend(loc='best') ax1.set_title('Rolling Mean & Standard Deviation') st.pyplot(fig1) # Dickey–Fuller test: with st_stdout("code"): adfuller_func(state.data_frame[state.column_to_predict]) else: st.warning("Загрузите файл для начала работы") state.sync()
def app(): """ Part for creating web page """ state = _get_state() st.title('Туториал по исследованию временных рядов при помощи Python.') st.write( 'Мы рассмотрим как работать с ARIMA-моделью в Python. Есть несколько различных библиотек, которые позволяют исследовать временные ряды. Мы решили использовать sktime, statsmodels, и классическую библиотеку pandas. Где это будет возможно, мы даже сравним возможности этих библиотек, хотя в основном наш выбор пал на самие понятные и негромоздкие решения.' ) code1 = """ import numpy as np import pandas as pd from matplotlib import pyplot as plt from statsmodels.tsa.stattools import adfuller from statsmodels.tsa.seasonal import seasonal_decompose from statsmodels.tsa.arima_model import ARIMA from sktime.datasets import load_airline from sktime.utils.plotting import plot_series from pandas.plotting import register_matplotlib_converters from sktime.forecasting.model_selection import temporal_train_test_split import pmdarima as pm register_matplotlib_converters() """ st.code(code1, language="python") st.write( "Для начала, рассмотрим самые стандартные операции с времеными рядами. У нас есть шаблонный набор даных об авиаперелётах, собранный по конкретонй компании. В следующих нескольких строках мы просто загружаем эти самые данные, и что-нибудь делаем. Если конкретней, строим график, делаем train-test split. Это, в целом, стандартный подход к временным рядам, но от этого не менее важный." ) code2 = """ y = load_airline() plot_series(y) """ st.code(code2, language="python") y, df, rolling_mean, rolling_std = load_dataset() st.line_chart(df) st.write( "На получившийся график можно взглянуть повнимательней. Сразу видна сезонность данных, явные пики и проседания, Ну и прииерно на глазок можно углядеть тренд на увеличение среднегодового колличества пассажиров, даже несмотря на сезонные провалы." ) code3 = """ y_train, y_test = temporal_train_test_split(y, test_size=24) plot_series(y_train, y_test, labels=['Train', 'Test']) """ st.code(code3, language="python") y_train, y_test = temporal_train_test_split(y, test_size=24) with _lock: fig0, ax0 = plot_series(y_train, y_test, labels=['Train', 'Test']) st.pyplot(fig0) st.write( "А вот тут мы уже сделали разбивку данных на тестовый и обучающий набор. Синим обозначен обучающий, а золотым - тестовый." ) st.write( "Посмотрим на график. Синим показано наблюдаемое количество пассажиров авиалиний. Красным показано скользящее среднее, а чёрным - скользящее стандартное отклонение." ) code4 = """ df = pd.DataFrame(y) df.index = df.index.to_timestamp() rolling_mean = df.rolling(window = 12).mean() rolling_std = df.rolling(window = 12).std() df.plot() plt.plot(rolling_mean, color = 'red', label = 'Rolling Mean') plt.plot(rolling_std, color = 'black', label = 'Rolling Std') plt.legend(loc = 'best') plt.title('Rolling Mean & Rolling Standard Deviation') plt.show() """ st.code(code4, language="python") with _lock: fig1, ax1 = plots(df, rolling_mean, rolling_std, 'Number of airline passengers') """ fig1, ax1 = plt.subplots() ax1.plot(df, label='Number of airline passengers') ax1.plot(rolling_mean, color='red', label='Rolling Mean') ax1.plot(rolling_std, color='black', label='Rolling Std') ax1.legend(loc='best') ax1.set_title('Rolling Mean & Rolling Standard Deviation') """ st.pyplot(fig1) y = y st.write( "Здесь мы переходим к немного более сложным вещам. Мы применяем к нашему ряду расширенный тест Дики - Фуллера." ) with st.echo(): result = adfuller(y) print('ADF Statistic: {}'.format(result[0])) print('p-value: {}'.format(result[1])) print('Critical Values:') for key, value in result[4].items(): print("\t{}: {}".format(key, value)) if result[0] > result[4]["5%"]: print( "Не удалось отклонить нулевую гипотезу - временной ряд нестационарный" ) else: print("Нулевая гипотеза отклонена – временной ряд стационарен") st.text("Output:") output = st.empty() with st_capture(output.code): result = adfuller(y) print('ADF Statistic: {}'.format(result[0])) print('p-value: {}'.format(result[1])) print('Critical Values:') for key, value in result[4].items(): print("\t{}: {}".format(key, value)) if result[0] > result[4]["5%"]: print( "Не удалось отклонить нулевую гипотезу - временной ряд нестационарный" ) else: print("Нулевая гипотеза отклонена – временной ряд стационарен") code5 = """ df_log = np.log(y) df_log.plot() """ st.code(code5, language="python") df_log = np.log(y) df_log.index = df_log.index.to_timestamp() with _lock: fig2, ax2 = plt.subplots() ax2.plot(df_log, label='Log') ax2.legend(loc='best') ax2.set_title('Logged number of airline passengers') st.pyplot(fig2) st.write( "Далее будет функция, считающая наши скользящие средние, делающая тест Дики - Фуллера, и заодно показывающая график." ) with st.echo(): def get_stationarity(timeseries): # rolling statistics rolling_mean = timeseries.rolling(window=12).mean() rolling_std = timeseries.rolling(window=12).std() # rolling statistics plot timeseries.plot() plt.plot(rolling_mean, color='red', label='Rolling Mean') plt.plot(rolling_std, color='black', label='Rolling Std') plt.legend(loc='best') plt.title('Rolling Mean & Standard Deviation') plt.show(block=False) # Dickey–Fuller test: result = adfuller(timeseries) print('ADF Statistic: {}'.format(result[0])) print('p-value: {}'.format(result[1])) print('Critical Values:') for key, value in result[4].items(): print('\t{}: {}'.format(key, value)) if result[0] > result[4]["5%"]: print( "Не удалось отклонить нулевую гипотезу - временной ряд нестационарный" ) else: print("Нулевая гипотеза отклонена – временной ряд стационарен") st.write( "Отметим, что тут мы немного корректируем данные, вычитая среднее.") code6 = """ rolling_mean = df_log.rolling(window=12).mean() df_log_minus_mean = df_log - rolling_mean df_log_minus_mean.dropna(inplace=True) get_stationarity(df_log_minus_mean) """ st.code(code6, language="python") rolling_mean = df_log.rolling(window=12).mean() df_log_minus_mean = df_log - rolling_mean df_log_minus_mean.dropna(inplace=True) rolling_mean_log_minus_mean = df_log_minus_mean.rolling(window=12).mean() rolling_std_log_minus_mean = df_log_minus_mean.rolling(window=12).std() with _lock: fig3, ax3 = plots(df_log_minus_mean, rolling_mean_log_minus_mean, rolling_std_log_minus_mean, 'Number of airline passengers (log minus mean)') """ fig3, ax3 = plt.subplots() ax3.plot(df_log, label='Log') ax3.legend(loc='best') ax3.set_title('Logged number of airline passengers') """ st.pyplot(fig3) output = st.empty() with st_capture(output.code): result = adfuller(df_log_minus_mean) print('ADF Statistic: {}'.format(result[0])) print('p-value: {}'.format(result[1])) print('Critical Values:') for key, value in result[4].items(): print("\t{}: {}".format(key, value)) if result[0] > result[4]["5%"]: print( "Не удалось отклонить нулевую гипотезу - временной ряд нестационарный" ) else: print("Нулевая гипотеза отклонена – временной ряд стационарен") st.write( "График сверху показывает получившийся результат. Поверх количества пассажиров можно увидеть скользящие соеднее и стандартное отклонение." ) code7 = """ rolling_mean_exp_decay = df_log.ewm(halflife=12, min_periods=0, adjust=True).mean() df_log_exp_decay = df_log - rolling_mean_exp_decay df_log_exp_decay.dropna(inplace=True) get_stationarity(df_log_exp_decay) """ st.code(code7, language="python") rolling_mean_exp_decay = df_log.ewm(halflife=12, min_periods=0, adjust=True).mean() df_log_exp_decay = df_log - rolling_mean_exp_decay df_log_exp_decay.dropna(inplace=True) rolling_mean_log_exp_decay = df_log_exp_decay.rolling(window=12).mean() rolling_std_log_exp_decay = df_log_exp_decay.rolling(window=12).std() with _lock: fig4, ax4 = plots(df_log_exp_decay, rolling_mean_log_exp_decay, rolling_std_log_exp_decay, 'Number of airline passengers') st.pyplot(fig4) output1 = st.empty() with st_capture(output1.code): result = adfuller(df_log_exp_decay) print('ADF Statistic: {}'.format(result[0])) print('p-value: {}'.format(result[1])) print('Critical Values:') for key, value in result[4].items(): print("\t{}: {}".format(key, value)) if result[0] > result[4]["5%"]: print( "Не удалось отклонить нулевую гипотезу - временной ряд нестационарный" ) else: print("Нулевая гипотеза отклонена – временной ряд стационарен") code8 = """ df_log_shift = df_log - df_log.shift() df_log_shift.dropna(inplace=True) get_stationarity(df_log_shift) """ st.code(code8, language="python") df_log_shift = df_log - df_log.shift() df_log_shift.dropna(inplace=True) rolling_mean_shift = df_log_shift.rolling(window=12).mean() rolling_std_shift = df_log_shift.rolling(window=12).std() with _lock: fig5, ax5 = plots(df_log_shift, rolling_mean_shift, rolling_std_shift, 'Number of airline passengers') st.pyplot(fig5) output2 = st.empty() with st_capture(output2.code): result = adfuller(df_log_shift) print('ADF Statistic: {}'.format(result[0])) print('p-value: {}'.format(result[1])) print('Critical Values:') for key, value in result[4].items(): print("\t{}: {}".format(key, value)) if result[0] > result[4]["5%"]: print( "Не удалось отклонить нулевую гипотезу - временной ряд нестационарный" ) else: print("Нулевая гипотеза отклонена – временной ряд стационарен") st.write( "Мы рассмотрели как можно изменять датасет для того, чтобы получить стационарный временной ряд. Теперь мы применим autoarima, для автоматического расчета оптимальных параметров модели" ) model = pm.auto_arima(y_train, seasonal=True, m=12) # make your forecasts # predict N steps into the future forecasts = model.predict(y_test.shape[0]) x = np.arange(y.shape[0]) code9 = """ model = pm.auto_arima(y_train, seasonal=True, m=12) forecasts = model.predict(y_test.shape[0]) x = np.arange(y.shape[0]) plt.plot(x[:120], y_train, c='blue') plt.plot(x[120:], forecasts, c='green') plt.show() """ st.code(code9, language="python") st.write( "Приведенный код обучает модель с автоподбором параметров на тренировочных данных (y_train), строит прогноз на количество элементов в тестовых данных, а затем мы строим график прогнозных значений" ) fig6, ax6 = plt.subplots() ax6.plot(x[:120], y_train, c='blue', label='Тренировочные данные') ax6.plot(x[120:], forecasts, c='green', label='Предсказанные значения') ax6.legend(loc='best') st.pyplot(fig6) st.write('Теперь посмотрим какие параметры у нашей модели') code10 = """ model.summary() """ st.code(code10, language="python") output3 = st.empty() with st_capture(output3.code): print(model.summary()) code11 = """ # Create predictions for the future, evaluate on test preds, conf_int = model.predict( n_periods=y_test.shape[0], return_conf_int=True) # ############################################################################# # Plot the points and the forecasts df.index = df.index.to_timestamp() plt.plot(df.index[:y_train.shape[0]], y_train, alpha=0.75) plt.plot(df.index[y_train.shape[0]:], preds, alpha=0.75) # Forecasts plt.scatter(df.index[y_train.shape[0]:], y_test, alpha=0.4, marker='x') # Test data plt.fill_between(df.index[-preds.shape[0]:], conf_int[:, 0], conf_int[:, 1], alpha=0.1, color='b') """ st.code(code11, language="python") st.write( "Теперь мы построим график предсказаний, а Х будут обозначать реальные данные" ) # Create predictions for the future, evaluate on test preds, conf_int = model.predict(n_periods=y_test.shape[0], return_conf_int=True) # ############################################################################# # Plot the points and the forecasts fig7, ax7 = plt.subplots() ax7.plot(df.index[:y_train.shape[0]], y_train, alpha=0.75) ax7.plot(df.index[y_train.shape[0]:], preds, alpha=0.75) # Forecasts ax7.scatter(df.index[y_train.shape[0]:], y_test, alpha=0.4, marker='x') # Test data ax7.fill_between(df.index[-preds.shape[0]:], conf_int[:, 0], conf_int[:, 1], alpha=0.1, color='b') st.pyplot(fig7) st.write( "Как мы видим, модель достаточно точно описала график, давайте теперь оценим нашу модель метрикой MAPE (средняя абсолютная ошибка в процентах)" ) code12 = """ def mean_absolute_percentage_error(y_true, y_pred): y_true, y_pred = np.array(y_true), np.array(y_pred) return np.mean(np.abs((y_true - y_pred) / y_true)) * 100 print(mean_absolute_percentage_error(y_test, preds)) """ st.code(code12, language="python") output4 = st.empty() with st_capture(output4.code): def mean_absolute_percentage_error(y_true, y_pred): y_true, y_pred = np.array(y_true), np.array(y_pred) return np.mean(np.abs((y_true - y_pred) / y_true)) * 100 print(mean_absolute_percentage_error(y_test, preds)) st.write("10% отклонение выглядит отлично, модель справилась на ура") state.sync()