Первая часть тут. В первой части я рассмотрел возможности автоматизированного прогнозирования на данных из учебного датасета. Во второй части посмотрим насколько хорошо можно предсказывать трафик из Демонстрационного счетчика Метрики. Загрузим данные тут.Скачайте данные в удобном форматеДля начала взглянем на данные:Длинные красные и желтые пики как бы намекают, что в данных большие выбросы, но об этом позже.Сначала заглушим все предупреждения, популярная практика в машинном обучении:import warnings # Отключение всех предупреждений warnings.filterwarnings("ignore")Необходимые импорты:from sktime.forecasting.ets import AutoETS from sktime.forecasting.base import ForecastingHorizon from sktime.param_est.seasonality import SeasonalityACF from sktime.utils.plotting import plot_series from sktime.split import temporal_train_test_split from sktime.performance_metrics.forecasting import mean_squared_errorЗагрузим данные:import pandas as pd df = pd.read_excel('названиефайла.xlsx', skiprows=5) df = df.drop(index=0) # удалил первую строку с суммой df['Дата визита'] = pd.to_datetime(df['Дата визита']) df = df.set_index('Дата визита')Выберем все источники трафика:df['Источник трафика'].unique()Результат:array(['Прямые заходы', 'Переходы по ссылкам на сайтах', 'Переходы из поисковых систем', 'Внутренние переходы', 'Переходы из социальных сетей', 'Переходы по рекламе', 'Не определено', 'Переходы по QR-коду', 'Переходы из мессенджеров', 'Переходы с почтовых рассылок', 'Переходы с сохранённых страниц', 'Переходы из рекомендательных систем'], dtype=object)Пропишем частоту, методом .asfreq('D'). Вангую, что в данных еще полно пропусков, чтобы от них избавится воспользуемеся лайфхаком .resample('D') что дальше указывать, без разницы, т.к. сумма и среднее за 1 день одинаковые:df['Визиты'][df['Источник трафика'] == 'Прямые заходы'].asfreq('D').resample('D').sum()И дальше просто перебираем все значения из списка трафика по циклу. Игрек у нас целевая переменная, которую предсказываем:for source in df['Источник трафика'].unique(): y = df['Визиты'][df['Источник трафика'] == source].asfreq('D').resample('D').sum()Чтобы отфильтровать источники, где мало трафика, я использую условие:if sum(y) > 600:Я просто скопирую весь код из первой части и получу прогнозы:RMSE: 92.7407873900574RMSE: 823.8282501025691RMSE: 10.963368558301537RMSE: 11.33234471603892RMSE: 2.43193144362868RMSE: 2.512959448749721RMSE: 0.7466906330369009Как видите, модель на автоматических настройках неплохо справилась с предсказаниями, на что указывает низкая ошибка RMSE: 10.96 для "Переходов из поисковых систем". Но в в источнике "Не определено" тоже низкая ошибка RMSE: 0.7466906330369009. Но данных мало, поэтому прогноз получается не очень удачный, так низкая ошибка не всегда означает хороший прогноз.Но в прямых заходах мы сразу видим сильный выброс:Средний уровень меньше 200, а выброс больше 1000, в 5 раз.Что бы улучшить результаты очистим от выбросов:# Агрегируем данные по дням y = df['Визиты'][df['Источник трафика'] == 'Прямые заходы'].asfreq('D').resample('D').sum() # Устанавливаем границы по квантилям 0.01 и 0.9 lower_bound, upper_bound = y.quantile(0.01), y.quantile(0.9) # Заменим выбросы средним значением без выбросов y = y.mask((y < lower_bound) | (y > upper_bound), y[(y >= lower_bound) & (y <= upper_bound)].mean())И таким образом финальный код примет вид:import warnings # Отключение всех предупреждений warnings.filterwarnings("ignore") from sktime.forecasting.ets import AutoETS from sktime.forecasting.base import ForecastingHorizon from sktime.param_est.seasonality import SeasonalityACF from sktime.utils.plotting import plot_series from sktime.split import temporal_train_test_split from sktime.performance_metrics.forecasting import mean_squared_error import pandas as pd df = pd.read_excel('Metrica_live_demo.xlsx', skiprows=5) df = df.drop(index=0) # удалил первую строку с суммой df['Дата визита'] = pd.to_datetime(df['Дата визита']) # не забудьте задать формат Дейттайм df = df.set_index('Дата визита') for source in df['Источник трафика'].unique(): y = df['Визиты'][df['Источник трафика'] == source].asfreq('D').resample('D').sum() if sum(y) > 600: # Устанавливаем границы по квантилям 0.01 и 0.9 lower_bound, upper_bound = y.quantile(0.01), y.quantile(0.9) # Заменим выбросы средним значением без выбросов y = y.mask((y < lower_bound) | (y > upper_bound), y[(y >= lower_bound) & (y <= upper_bound)].mean()) # Оцениваем сезонность sp_est = SeasonalityACF() sp_est.fit(y.diff().dropna()) sp = sp_est.get_fitted_params().get("sp") y_train, y_test = temporal_train_test_split(y=y, test_size=7) # fh = range(1, 7+1) # Одно и тоже fh = ForecastingHorizon(y_test.index, is_relative=False) forecaster = AutoETS(auto=True, sp=sp) forecaster.fit(y_train, fh=fh) y_pred = forecaster.predict() rmse = mean_squared_error(y_test, y_pred, square_root=True) print(f"RMSE: {rmse}") plot_series(y_train[-30:], y_test, y_pred, labels=["Тренировочные данные", "Тестовые данные", "Прогноз"], title=source); y_pred = forecaster.fit_predict(y, fh=range(1, 7+1)) plot_series(y[-30:], y_pred, labels=["Исходные данные", "Прогноз"]);В результате получатся прогнозы каждого канала отдельно:RMSE: 14.51167840868573Прогноз на неделю впередRMSE: 13.428761193935136Прогноз на неделю впередRMSE: 12.707287737822499Прогноз на неделю впередRMSE: 20.491963781768874Модели сложно предсказывать, когда данных малоRMSE: 1.492855746504661Несмотря на низкую ошибку, такой прогноз вряд ли можно называть удачнымRMSE: 1.439218659182318Часто модель просто рисует какой-то средний уровеньRMSE: 0.35574552297004924Тут уже предсказывается среднее количество трафика за неделю. А еще я удалил половину источников трафика, где было совсем мало данных.Можно ли улучшить этот результат? Конечно можно! Из этой библиотеки sktime я еще и половины ее возможностей не выжал.Как правило это достигается за счет:0. Предобработки данных: удаление выбросов (реализовано) и фильтрации/преобразовании данных (не реализовано).1. Декомпозици трафика и предсказания каждой компоненты отдельно (ETS модель уже делает это)2. Подбора гиперпараметров модели (не реализовано).3. Усреднения прогнозов моделей (не реализовано).Выводы:1. Машинное обучение - это не космическая наука, и при правильном подходе можно получить хороший результат за 50 строк кода.2. На полностью автоматических настройках моделей с автоматическим определением сезонности можно получать хорошие прогнозы вообще не вникая в процессы "под капотом".3. Данный подход можно использовать для автоматизации предиктивной аналитики, поиска выбросов, аномалий, точек перехода и много чего еще.В следующих уроках я хочу рассмотреть:Разделение временного ряда на компонентыАвтоматический выбор модели для прогнозаПодбор гиперпараметровКросс-валидациюБектестингВсем спасибо, кто дочитал. Ставьте лайки, пишите комментарии, чтобы ускорить выход следующих частей.