Оглавление:

  1. Введение
  2. Цели
  3. Исследовательский анализ данных
  4. Моделирование
  5. Заключение

Введение

Каждая организация может извлечь выгоду из прогноза продаж, чтобы помочь им принимать более обоснованные решения, а точное прогнозирование продаж является важным и недорогим способом увеличения прибыли. Без эффективного прогнозирования клиентского спроса и будущих продаж продуктов/услуг ни один бизнес не сможет улучшить свои финансовые показатели. Владельцы бизнеса традиционно прогнозировали доходы на основе своего многолетнего опыта, который оказался менее точным. В наши дни владельцы бизнеса не просто хотят полагаться на свои собственные суждения, чтобы предвидеть продажи; они хотят использовать исторические данные для точного прогнозирования продаж. Лучший способ прогнозировать продажи со значительно большей точностью — использовать глубокое и машинное обучение. В этой статье я покажу, как применять машинное обучение для прогнозирования будущих продаж.

Цели

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

Описание набора данных

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

Поля данных:

Id — идентификатор, представляющий дубликат (Store, Date) в тестовом наборе.

Магазин — уникальный идентификатор для каждого магазина.

Продажи — оборот за любой день (это то, что вы прогнозируете).

Клиенты — количество клиентов в определенный день.

Открыто — индикатор того, был ли магазин открыт: 0 = закрыт, 1 = открыт.

StateHoliday — указывает на государственный праздник. Обычно все магазины, за редким исключением, закрыты в государственные праздники. Обратите внимание, что все школы закрыты в праздничные и выходные дни. a = государственный праздник, b = праздник Пасхи, c = Рождество, 0 = нет

SchoolHoliday – указывает, повлияло ли на (Магазин, Дата) закрытие государственных школ.

StoreType — различает 4 разные модели магазина: a, b, c, d.

Ассортимент — описывает уровень ассортимента: a = базовый, b = дополнительный, c = расширенный. Подробнее об ассортименте здесь.

CompetitionDistance — расстояние в метрах до ближайшего магазина конкурента.

CompetitionOpenSince[Месяц/Год] — указывает примерный год и месяц открытия ближайшего конкурента.

Акция – указывает, проводится ли в этот день акция в магазине.

Promo2 — Promo2 — это продолжающаяся и последовательная акция для некоторых магазинов: 0 = магазин не участвует, 1 = магазин участвует.

Promo2Since[Год/Неделя] – указывает год и календарную неделю, когда магазин начал участвовать в акции Promo2.

PromoInterval — описывает последовательные интервалы запуска Promo2, называя месяцы, в которые акция начинается заново. Например. «Февраль, май, август, ноябрь» означает, что каждый раунд начинается в феврале, мае, августе и ноябре любого данного года для этого магазина.

Есть два отдельных файла CSV, которые будут использоваться для обучения модели. Это:

  • Train.csv
  • store.csv

Мы соединим эти две таблицы на основе идентификатора магазина по каждому из данных для обучения.

Исследовательский анализ набора данных

train_df = pd.read.csv(“train.csv”)
store_df = pd.read_csv(“store.csv”)

Обзор данных

train_df.head()

store_df.head()

Теперь мы можем объединить две таблицы на основе идентификатора магазина следующим образом:

data = pd.merge(train_df, store_df, on=’Store’)

Общий объем продаж в магазинах:

plt.figure(figsize=(12, 7))
sns.scatterplot(data=train_df, x=train_df[‘Store’], y=train_df[‘Sales’])

Большинство продаж находятся в диапазоне от 0 до 2200, и есть несколько выбросов, которые необходимо обработать.

Корреляция продаж с покупателями для каждого типа магазина:

plt.figure(figsize=(12, 7))
sns.scatterplot(data=train_df[“Sales”, “Customers”], x=train_df[‘Customers’], y=train_df[‘Sales’])

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

Корреляция продаж с конкуренцией Расстояние

plt.figure(figsize=(12, 7))
sns.scatterplot(data=train_df[“Sales”, “CompetitionDistance”], x=train_df[CompetitionDistance], y=train_df[‘Sales’])

Интересно, что по мере увеличения дистанции до конкурентов продажи снижаются. Есть некоторые продажи для магазина типа А, так как дистанция конкуренции очень высока.

Распродажи в праздничные дни

plt.figure(figsize=(12, 7))
sns.barplot(data=holiday_df, x=’’StateHoliday’, y=’Sales’)

В праздничные дни распродаж меньше

Продажи за каждый месяц в магазине

sns.relplot(x=”Month”, y=”Sales”, hue=”StoreType”, data=train_df);

В июне самый высокий объем продаж, а в январе самый низкий

Продажи каждый день

sns.relplot(x=”DayOfWeek”, y=”Sales”, hue=”StoreType”, data=train_df);

Магазин B в основном открыт по субботам, и в нем больше продаж

Предварительная обработка данных

  • Заполнение пропущенных значений
  • Заполните числовые признаки их медианой
miss_1 = [‘Promo2SinceYear’, ‘Promo2SinceWeek’, ‘CompetitionOpenSinceMonth’, ‘CompetitionOpenSinceYear’, ‘CompetitionDistance’]
for col in miss_1:
 df[col] = df[col].fillna(df[col].median()
  • Заполнить категориальные признаки режимом
Categ_var = [‘PromoInterval’]
for col in Categ_var:
  df[col] = df[col].fillna(df[col].mode()[0])

df[‘Открыть] = df[‘Открыть].fillna(0)

Они должны заполнить все пропущенные значения

  • Обработка выбросов

Большинство выбросов находятся в столбце «Продажи и клиенты», я заменил выбросы на IQR.

Columns = [‘Sales’, ‘Customers’]
for col in columns:
Q1, Q3 = df[col].quantile(
0.25), df[col].quantile(0.75)
IQR = Q3 — Q1
cut_off = IQR * 1.5
lower, upper = Q1 — cut_off, Q3 + cut_off
df[col] = np.where(
df[col] > upper, upper, df[col])
df[col] = np.where(
df[col] < lower, lower, df[col])
  • Кодировка этикетки
from sklearn.preprocessing import LabelEncoder
categorical_columns = [‘PromoInterval’, ‘Assortment’, ‘StoreType’]
# Label encoding
label_encoded_columns = preprocess.label_encode(train_df, categorical_columns)
label_encoded_columns = []
# For loop for each columns
le = LabelEncoder()
for col in categorical_columns:
 # We define new label encoder to each new column
 # Encode our data and create new Dataframe of it,
 column_dataframe = pd.DataFrame(
 le.fit_transform(df[col]), columns=[col])
 # and add new DataFrame to “label_encoded_columns” list
 label_encoded_columns.append(column_dataframe)
 # Merge all data frames
label_encoded_columns = pd.concat(label_encoded_columns, axis=1)
train_df.drop(categorical_columns, axis=1, inplace=True)
# Merge DataFrames
train_df = pd.concat([train_df, label_encoded_columns], axis=1)

Моделирование

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

Модель машинного обучения (случайный лесной регрессор)

При построении модели машинного обучения можно использовать конвейер sklearn для одновременного вычисления всех этапов очистки данных и моделирования. Что касается машинного обучения, я использовал Random Forest Regressor для прогнозирования продаж.

from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestRegressor

data_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='mean'))
,('scaler', StandardScaler())
])
pipeline = Pipeline(steps = [
('preprocessor', data_transformer)
,('regressor',RandomForestRegressor(max_depth=57, random_state=0))
])

Наконец, подогнать и оценить модель

model_rg = pipeline.fit(X_train, y_train)
model_rg.score(X_test, y_test)

Я получил точность около 90%.

Чтобы сохранить модель:

# Save model based on time st
model_rg = '../models/' + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") + '.pkl'
pickle.dump(rf_model, open(rf_model_path, 'wb'))

Подход к глубокому обучению

Для глубокого обучения я использовал TensorFlow для обучения своей модели. При обучении данных, представляющих собой временные ряды или меняющихся сверхурочно, разбиение на поезд-тест отличается от того, как это делается с использованием библиотеки train_test_split из sklearn. Это потому, что мы хотим научить наши данные предсказывать будущее на основе прошлых невидимых данных. Лучший способ сделать это — отсортировать данные на основе индекса даты и разделить их вручную. Вот раздел кода, который я использовал для разделения данных:

train_size = int(len(df2) * 0.70) 
test_size = len(df2) - train_size 
train, testt = df2.iloc[0:train_size], df2.iloc[train_size:len(df2)]
print(train.shape, testt.shape) #(591036, 2) (253302, 2)

То же самое касается тестовых данных:

test_size = int(len(testt) * 0.50)
val_size = len(testt) - test_size
test, val = testt.iloc[0:test_size],testt.iloc[test_size:len(testt)]
print(val.shape, test.shape)

Затем мы можем построить модель LSTM для обучения данных:

model = Sequential()
model.add(LSTM(128, input_shape=(X_train.shape[1], train.shape[2])))
model.add(Dropout(rate=0.2))
model.add(RepeatVector(X_train.shape[1]))
model.add(LSTM(128, return_sequences=True))
model.add(Dropout(rate=0.2))
model.add(TimeDistributed(Dense(X_train.shape[2])))
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001, epsilon=1e-08, decay=0.01), loss='mae')
model.summary()

Наконец, подгоните данные

history = model.fit(X_train, y_train, epochs=10, batch_size=40, validation_data=(X_val, y_val), callbacks=[keras.callbacks.EarlyStopping(monitor='val_loss', patience=3, mode='min')], shuffle=False)

Заключение

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

Рекомендации





https://medium.com/vickdata/a-simple-guide-to-scikit-learn-pipelines-4ac0d974bdcf