новички идут читать обсуждения
новички идут читать обсуждения

Оглавление

Вступление

Привет читатель,эта стать является переводом решений соревнования Forecasting Mini‑Course Sales на Kaggle и дополнениями от автора данной статьи.

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

Кому это надо? Эта статья предусмотрена для новичков или людей ищущих вдохновения для своего проекта.

Kaggle playground series

Как и в детстве ,мы начинаем познавать мир с песочницы.

Kaggle Playground Series - это серия соревнований по машинному обучению, которые проводятся Kaggle для новичков и людей которые хотят попрактиковать свои навыки ml .

Эти соревнования могут помочь новичкам в изучение ml и ds, благодарю тому ,что на испытания есть открытые дискуссии и примеры прошлых решений, которые публикуют верхние места таблиц

Соревнования в Kaggle Playground Series обычно основаны на небольших наборах данных, которые легко понять и обработать. Это делает их идеальным выбором для новичков, которые только начинают изучать машинное обучение.

Если вы только начинаете свой путь в ml или ds,то это идеальное место для практики , как и все соревнования на Kaggle.

Данные

когда только скачал датасет
когда только скачал датасет

Как и везде, нам нужно понять что нам дано, а точнее дано ли.

Ну раз вы читаете эту статью то вам скорее всего дано,если конечно автор её вообще допишет и опубликует.

Итак,что по данным?

Данные содержат продажи различных вымышленных учебных модулей за весь год из разных вымышленных магазинов под брендом Kaggle в разных (реальных!) странах. А точнее данные включают такие колонки: дата, страна продажи ,магазин продажи ,название курса, количество продаж.

Этот набор данных полностью синтетический, но содержит множество эффектов, которые вы видите в реальных данных, например, влияние выходных и праздничных дней, сезонность и т.д. Набор данных для обучения начинается с 1.01.2017 и до 31.12.2021 (~137к строк) , тестовые же данные захватывают весь 2022 год (~27,4к строк).

Примерно так выглядят данные за первые 1000 строк:

солянка данных
солянка данных

Но так как данные у нас из разных продуктов, давайте посмотрим на каждый продукт отдельно:

'Using LLMs to Improve Your Coding'
'Using LLMs to Improve Your Coding'
'Using LLMs to Train More LLMs'
'Using LLMs to Train More LLMs'
'Using LLMs to Win Friends and Influence People'
'Using LLMs to Win Friends and Influence People'
'Using LLMs to Win More Kaggle Competitions'
'Using LLMs to Win More Kaggle Competitions'
'Using LLMs to Write Better'
'Using LLMs to Write Better'
Так, и что же мы тут видим?Пожалуйста немного подумайте, но не долго.

Периодичность , сезонность . То есть график повторяется , а это очень полезно для прогнозирования.

Но как же нам это использовать ?

Дата

Откуда код

В этом отделе я буду использовать код из решения 9 места по соревнованию https://www.kaggle.com/code/yeoyunsianggeremie/s3e19-catboost-smoothing-post-processing/notebook

Для начала работы с датой нам нужно преобразовать дату в особый формат datetime:

df.date = pd.to_datetime(df.date)

немного подробно можно прочитать здесь.

Начнем с простого, а именно с обработки даты,в наших данных они представлены в формате гггг.мм.дд , эту дату мы можем преобразовать в такие полезные штуки как:

Год

df['year'] = df.date.dt.year

Месяц

df['month'] = df.date.dt.month

День в месяце (1-31)

df['dayofmonth'] = df.date.dt.day

День недели (0-6)

df['dayofweek'] = df.date.dt.dayofweek

Название дня

df['dayname'] = df.date.dt.strftime('%A')

День года (1 - 365)

df['dayofyear'] = df.date.dt.dayofyear

Но зачем мы это делаем? Ответ очень прост - прогнозирование за счёт исторических данных дня .Ведь каждая дата, кроме наверное года повторяется, это дает нашей будущей модели возможность предсказывать за счет прошлых значений в этот день.

Код коротко
def extractDate(df):
    df.date = pd.to_datetime(df.date) 
    df['year'] = df.date.dt.year
    df['month'] = df.date.dt.month
    df['dayofmonth'] = df.date.dt.day
    df['dayofweek'] = df.date.dt.dayofweek
    df['dayname'] = df.date.dt.strftime('%A')
    df['dayofyear'] = df.date.dt.dayofyear
extractDate(train) #ваш dataframe в скобках

Примерно так выглядит таблица после наших манипуляций :

Праздники

Нет ,нет , не нужно ничего праздновать.Нам всего лишь нужно добавить в нашу таблицу пару столбцов с праздниками . Зачем? Как мы знаем в праздники подарки либо дарят, либо получают , но в любом случае их покупают , а это нам и нужно.И для облегчения работы модели мы можем добавить маркеры (столбцы) праздников.

Но как это сделать?

Для работы с праздниками есть специальный модуль holidays, установим его

pip install holidays

Далее для обработки праздников можно использовать примерно такой код:

from datetime import datetime
import holidays

#данные должны быть в формате datetime
# Функция для получения информации о празднике
def get_holiday_info(row):
    country = row['country']
    date = row['date'].date()
    holiday_obj = holidays.CountryHoliday(country)
    is_holiday = int(date in holiday_obj)
    holiday_name = holiday_obj.get(date)
    if is_holiday==0:
        holiday_name = 'Not Holiday'
    return is_holiday, holiday_name

# Добавляем столбцы с информацией о праздниках
df[['is_holiday', 'holiday_name']] = df.apply(get_holiday_info, axis=1, result_type='expand')

Этот код делает из такой таблицы :

Такую:

Ну,скорее всего ваш день рождение этот модуль не найдет , но большинство известных праздников там будут представлены.

Модель

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

Моделью является линейная регрессия с метрикой SMAPE.

Модель получается примерно такая :

ln(sold)=ln(GDP)+b1const(store)+b2(product)+b3waves(product)+b4holiday effect+b5weekend+b6covid

Или же:

ln(продано)=ln(ВВП) + b1const(магазин) + b2(продукт) + b3волны(продукт) + b4праздничный эффект + b5выходные + b6covid

такая модель учитывает многие факторы ,которые могут быть в реальной жизни и влиять на продажи курсов.

Для оценки результатов модели используется smape,поскольку эту метрику легче интерпретировать . Формула для метрики получается такая:

И получившийся код:

from sklearn.model_selection import GroupKFold
pd.options.mode.chained_assignment = None  # default='warn'

kf = GroupKFold(n_splits=5)
train_a = []
val_a = []
val_Q1_a = []
val_Q234_a = []
for fold, (train_idx, val_idx) in enumerate(kf.split(train_data, groups=train_data.date.dt.year)):
    X_tr = train_data.iloc[train_idx]
    X_va = train_data.iloc[val_idx]
    if X_va.iloc[1].year == 2020:
        continue
    print(X_va.iloc[1].year)
    coef, model, train_mean, val_mean, val_Q1, val_Q234 = fit_model(
        X_tr, X_va, use_columns)
    train_a.append(train_mean)
    val_a.append(val_mean)
    val_Q1_a.append(val_Q1)
    val_Q234_a.append(val_Q234)

# Compute mean
train_mean = np.mean(train_a)
val_mean = np.mean(val_a)
val_Q1_mean = np.mean(val_Q1_a)
val_Q234_mean = np.mean(val_Q234_a)

# Compute standard error of the mean
train_sem = stats.sem(train_a)
val_sem = stats.sem(val_a)
val_Q1_sem = stats.sem(val_Q1_a)
val_Q234_sem = stats.sem(val_Q234_a)

print(f"Train mean: {train_mean:.4f} ± {train_sem:.4f}")
print(f"Validation mean: {val_mean:.4f} ± {val_sem:.4f}")
print(f"Validation Q1 mean: {val_Q1_mean:.4f} ± {val_Q1_sem:.4f}")
print(f"Validation Q234 mean: {val_Q234_mean:.4f} ± {val_Q234_sem:.4f}")

Это лишь маленький кусок кода,остальная часть есть в решение в разделе модели.

Заключение

Данная статья не даст каких либо сверх знаний и умений.Я лишь немного приоткрыл завесу тайн решения задач на гегле,с помощью перевода и пересказа небольшого количества статей.Если вам было интересно читать эту статью , то вот лидерборд этого соревнования,в котором есть огромное количество статей по решению этой задачи.Также здесь можно найти решения задач прошлых лет.

Всем спасибо,всем пока.

Комментарии (0)