Рубрики
Без рубрики

Анализ тенденций покупок в Черную пятницу с помощью машинного обучения

Автор оригинала: Guest Contributor.

Вступление

Википедия определяет Черную пятницу как неофициальное название пятницы, следующей за Днем благодарения в Соединенных Штатах, который отмечается в четвертый четверг ноября. [Черная пятница] считается началом сезона рождественских покупок в Америке […].

В этой статье мы попытаемся исследовать различные тенденции из набора данных покупок в Черную пятницу. Мы извлекем полезную информацию, которая ответит на такие вопросы, как: какой пол больше покупает в Черную пятницу? Влияют ли занятия людей на продажи? Какая возрастная группа является самой большой транжирой?

В конце концов, мы создадим простой алгоритм машинного обучения, который предсказывает сумму денег, которую человек, вероятно, потратит в Черную пятницу, в зависимости от таких особенностей, как пол, возраст и профессия.

Набор данных, который мы будем использовать в этой статье, включает в себя 550 000 наблюдений о Черной пятнице, сделанных в розничном магазине. Файл можно скачать по следующей ссылке Kaggle: Black Friday Case Study .

Анализ данных

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

import pandas as pd
import numpy as np
import matplotlib as pyplot
%matplotlib inline
import seaborn as sns

Далее нам нужно импортировать наши данные.

data = pd.read_csv('E:/Datasets/BlackFriday.csv')

Давайте посмотрим на некоторые основные сведения о наших данных!

data.info()

Выход:


RangeIndex: 537577 entries, 0 to 537576
Data columns (total 12 columns):
User_ID                       537577 non-null int64
Product_ID                    537577 non-null object
Gender                        537577 non-null object
Age                           537577 non-null object
Occupation                    537577 non-null int64
City_Category                 537577 non-null object
Stay_In_Current_City_Years    537577 non-null object
Marital_Status                537577 non-null int64
Product_Category_1            537577 non-null int64
Product_Category_2            370591 non-null float64
Product_Category_3            164278 non-null float64
Purchase                      537577 non-null int64
dtypes: float64(2), int64(5), object(5)
memory usage: 49.2+ MB

Рассматривая данные, мы можем сделать вывод, что наш набор обладает 12 различными параметрами: 7 числовыми (целочисленными и плавающими) и 5 объектными переменными. Кроме того, набор данных содержит две короткие переменные типа: Product_Category_2 и Product_Category_3 . Позже мы увидим, как справиться с этой проблемой.

Итак, теперь у нас есть общая картина данных, давайте напечатаем информацию о первых пяти клиентах (первые пять строк нашего фрейма данных):

data.head()

Первый вопрос, который я хочу задать с самого начала этого исследования: правда ли, что женщины – клиенты очень доминируют по сравнению с мужчинами? Мы будем использовать библиотеку seaborn и функцию count plot для построения графика количества клиентов мужского и женского пола.

sns.countplot(data['Gender'])

Ух ты! График показывает, что клиентов-мужчин почти в 3 раза больше, чем клиентов-женщин! Почему это? Может быть, посетители мужского пола с большей вероятностью выйдут и купят что-нибудь для своих дам, когда будет больше сделок.

Давайте немного подробнее рассмотрим категорию Gender . Теперь мы хотим увидеть распределение гендерной переменной, но с учетом категории Возраст . Еще раз будет использована функция count plot , но теперь с определенным параметром hue .

sns.countplot(data['Age'], hue=data['Gender'])

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

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

data.describe()

Далее ниже мы анализируем столбец User_ID с помощью метода unique . Из этого мы можем сделать вывод, что в этом конкретном розничном магазине во время Черной пятницы 5 891 человек купили что-то в магазине. Кроме того, из категории Product_ID мы можем извлечь информацию о том, что продается 3623 различных продукта.

data['User_ID'].nunique()

Выход:

5891
data['User_ID'].nunique()

Выход:

3623

Теперь давайте рассмотрим категорию Род занятий|/. Номер Occupation - это идентификационный номер типа занятия каждого клиента. Мы видим, что существует около 20 различных профессий. Но давайте проведем точный анализ. Во-первых, нам нужно создать функцию, которая будет извлекать все уникальные элементы из одного столбца (чтобы извлечь все разные профессии).

Для этого мы будем использовать функцию unique из библиотеки numpy Python.

def unique(column):
    x = np.array(column)
    print(np.unique(x))
print("The unique ID numbers of customers occupations:")
unique(data['Occupation'])

Выход:

The unique ID numbers of costumers occupations:
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20]

Как мы видим, в течение торгового дня регистрируется 21 идентификатор профессии.

Номер профессии может представлять различные профессии клиентов: например, номер 1 может быть инженером, номер 2 – врачом, номер 3-художником и т. д.

Было бы также интересно посмотреть, сколько денег потратила каждая группа клиентов (сгруппированная по идентификатору профессии). Для этого мы можем использовать цикл for и суммировать потраченные деньги для каждого отдельного идентификатора профессии:

occupations_id = list(range(0, 21))
spent_money = []
for oid in occupations_id:
    spent_money.append(data[data['Occupation'] == oid]['Purchase'].sum())

spent_money

Выход:

[625814811,
 414552829,
 233275393,
 160428450,
 657530393,
 112525355,
 185065697,
 549282744,
 14594599,
 53619309,
 114273954,
 105437359,
 300672105,
 71135744,
 255594745,
 116540026,
 234442330,
 387240355,
 60249706,
 73115489,
 292276985]

Мы создали список spent_money , который включает суммированные количества долларов для Профессий идентификаторов – от 0 до 20. Может показаться странным, что на это тратятся сотни миллионов долларов. Но имейте в виду, что наш набор данных включает в себя 500 000 наблюдений, так что это на самом деле очень вероятно. Или, может быть, розничный магазин на самом деле большой торговый центр. Другое объяснение огромных сумм денег, потраченных каждой профессией, заключается в том, что эти данные могут представлять транзакции для нескольких вечеров Черной пятницы, а не только для одного.

Теперь у нас есть информация о том, сколько денег тратится на каждую категорию занятий. Давайте теперь графически построим эту информацию.

import matplotlib.pyplot as plt; plt.rcdefaults()
import matplotlib.pyplot as plt

objects = ('0', '1', '2', '3', '4', '5','6','7','8','9','10', '11','12', '13', '14', '15', '16', '17', '18', '19', '20')
y_pos = np.arange(len(objects))

plt.bar(y_pos, spent_money, align='center', alpha=0.5)
plt.xticks(y_pos, objects)
plt.ylabel('Money spent')
plt.title('Occupation ID')

plt.show()

Можно легко заметить, что люди, имеющие профессии 0 и 4, тратили больше всего денег во время продаж в Черную пятницу. С другой стороны, люди, принадлежащие к профессиям с ID 18, 19 и особенно к профессии 8, потратили наименьшую сумму денег. Это может означать, что эти группы являются самыми бедными или, наоборот, самыми богатыми людьми, которые не любят делать покупки в таких розничных магазинах. У нас есть недостаток информации, чтобы ответить на этот вопрос, и из-за этого мы остановимся здесь на анализе категории Оккупация .

Следующая переменная-City_Category . Эта категория дает нам информацию о городах, из которых находятся наши клиенты. Во-первых, давайте посмотрим, сколько у нас разных городов.

data['City_Category'].nunique()

Выход:

3

Теперь будет интересно посмотреть в процентах, каково соотношение клиентов из каждого города. Эта информация будет представлена в виде цветной круговой диаграммы. Мы можем сделать это в 5 строках кода. Всемогущий Питон, спасибо!:)

explode = (0.1, 0, 0)
fig1, ax1 = plt.subplots(figsize=(11,6))
ax1.pie(data['City_Category'].value_counts(), explode=explode, labels=data['City_Category'].unique(), autopct='%1.1f%%')
plt.legend()
plt.show()

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

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

До сих пор мы рассмотрели несколько основных методов анализа необработанных данных. Прежде чем мы сможем применить алгоритмы машинного обучения к нашему набору данных, нам нужно преобразовать его в определенную форму, с которой могут работать алгоритмы машинного обучения. Задача алгоритмов обучения будет состоять в том, чтобы предсказать значение переменной Purchase , учитывая информацию о клиенте в качестве входных данных.

Первое, что нам нужно сделать, это разобраться с отсутствующими данными в столбцах Product_Category_2 и Product_Category_3 . У нас есть только 30% данных внутри Product_Category_3 и 69% данных внутри Product_Category_2 . 30% реальных данных-это небольшое соотношение, мы могли бы заполнить недостающие значения внутри этой категории средним из существующих значений, но это означает, что 70% данных будут искусственными, что может разрушить нашу будущую модель машинного обучения. Лучшей альтернативой для решения этой проблемы является исключение этой колонки из дальнейшего анализа. Для этого мы будем использовать функцию drop :

data = data.drop(['Product_Category_3'], axis=1)

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

data['Product_Category_2'].fillna((data['Product_Category_2'].mean()), inplace=True)

Давайте теперь еще раз проверим фрейм данных:

data.info()

Выход:


RangeIndex: 537577 entries, 0 to 537576
Data columns (total 11 columns):
User_ID                       537577 non-null int64
Product_ID                    537577 non-null object
Gender                        537577 non-null object
Age                           537577 non-null object
Occupation                    537577 non-null int64
City_Category                 537577 non-null object
Stay_In_Current_City_Years    537577 non-null object
Marital_Status                537577 non-null int64
Product_Category_1            537577 non-null int64
Product_Category_2            537577 non-null float64
Purchase                      537577 non-null int64
dtypes: float64(1), int64(5), object(5)
memory usage: 45.1+ MB

Проблема пропущенных значений решена. Далее мы удалим столбцы, которые не помогают в предсказании.

User_ID is-это номер, автоматически присваиваемый каждому клиенту, и он не полезен для целей прогнозирования.

Столбец Product_ID содержит информацию о приобретенном продукте. Это не особенность клиента. Поэтому мы уберем и это.

data = data.drop(['User_ID','Product_ID'], axis=1)
data.info()

Выход:


RangeIndex: 537577 entries, 0 to 537576
Data columns (total 9 columns):
Gender                        537577 non-null object
Age                           537577 non-null object
Occupation                    537577 non-null int64
City_Category                 537577 non-null object
Stay_In_Current_City_Years    537577 non-null object
Marital_Status                537577 non-null int64
Product_Category_1            537577 non-null int64
Product_Category_2            537577 non-null float64
Purchase                      537577 non-null int64
dtypes: float64(1), int64(4), object(4)
memory usage: 36.9+ MB

Наш окончательный выбор основан на 9 столбцах – одной переменной, которую мы хотим предсказать (столбец Покупка ), и 8 переменных, которые мы будем использовать для обучения нашей модели машинного обучения.

Как видно из таблицы info, мы имеем дело с 4 категориальными столбцами. Однако базовые модели машинного обучения способны обрабатывать числовые значения. Поэтому нам нужно преобразовать категориальные столбцы в числовые.

Мы можем использовать функцию get_dummies Python, которая преобразует категориальные значения в одномерные кодированные векторы. Как это работает? У нас есть 3 города в нашем наборе данных: A, B и C. Предположим, что клиент из города B. Функция get_dummies вернет вектор с одним горячим кодированием для этой записи, который выглядит следующим образом: [0 1 0] . Для костюмера из города А: [1 0 0] и от С: [0 0 1] . Короче говоря, для каждого города создается новый столбец, который заполняется всеми нулями, за исключением строк, где клиент принадлежит к этому конкретному городу. Такие строки будут содержать 1.

Следующий скрипт создает однократно закодированные векторы для столбцов Gender , Age , City и Stay_In_Current_City_Years .

df_Gender = pd.get_dummies(data['Gender'])
df_Age = pd.get_dummies(data['Age'])
df_City_Category = pd.get_dummies(data['City_Category'])
df_Stay_In_Current_City_Years = pd.get_dummies(data['Stay_In_Current_City_Years'])

data_final = pd.concat([data, df_Gender, df_Age, df_City_Category, df_Stay_In_Current_City_Years], axis=1)

data_final.head()

На следующем снимке экрана представлены вновь созданные фиктивные столбцы. Как видите, все категориальные переменные преобразуются в числовые. Таким образом, если клиенту от 0 до 17 лет (например), то только это значение столбца будет равно 1, а другие, другие столбцы возрастной группы будут иметь значение 0. Аналогично, если это клиент мужского пола, столбец с именем ” M “будет равен 1, а столбец “F” – 0.

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

Прогнозирование потраченной суммы

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

Линейная регрессия представляет собой очень простой метод контролируемого обучения и является эффективным инструментом для прогнозирования количественных ответов. Вы можете найти основную информацию об этом прямо здесь: Линейная регрессия в Python

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

Хватит теории, давайте построим настоящую систему ML! Во-первых, нам нужно создать входные и выходные векторы для нашей модели:

X = data_final[['Occupation', 'Marital_Status', 'Product_Category_2', 'F', 'M', '0-17', '18-25', '26-35', '36-45', '46-50', '51-55', '55+', 'A', 'B', 'C', '0', '1', '2', '3', '4+']]
y = data_final['Purchase']

Теперь мы импортируем функцию train_test_split , чтобы разделить все наши данные на два набора: обучающий и тестовый. Обучающий набор будет использоваться в соответствии с нашей моделью. Обучающие данные всегда используются для обучения, корректировки параметров модели и минимизации ошибки на выходе. Остальные данные (тестовый набор) будут использоваться для оценки производительности.

Приведенный ниже сценарий разбивает наш набор данных на 60% обучающий набор и 40% тестовый набор:

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4)

Теперь пришло время импортировать нашу модель линейной регрессии и обучить ее на нашем обучающем наборе:

from sklearn.linear_model import LinearRegression

lm = LinearRegression()
lm.fit(X_train, y_train)
print(lm.fit(X_train, y_train))

Выход:

LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None,
         normalize=False)

Поздравляю людей! Наша модель обучена. Теперь мы можем вывести значение параметра перехвата и значения всех коэффициентов нашей модели после процедуры обучения:

print('Intercept parameter:', lm.intercept_)
coeff_df = pd.DataFrame(lm.coef_, X.columns, columns=['Coefficient'])
print(coeff_df)

Выход:

Intercept parameter: 11224.23064289564
                    Coefficient
Occupation             8.110850
Marital_Status       -79.970182
Product_Category_2  -215.239359
F                   -309.477333
M                    309.477333
0-17                -439.382101
18-25               -126.919625
26-35                 67.617548
36-45                104.096403
46-50                 14.953497
51-55                342.248438
55+                   37.385839
A                   -376.683205
B                   -130.046924
C                    506.730129
0                    -46.230577
1                      4.006429
2                     32.627696
3                     11.786731
4+                    -2.190279

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

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

predictions = lm.predict(X_test)
print("Predicted purchases (in dollars) for new costumers:", predictions)

Выход:

Predicted purchases (in dollars) for new costumers: [10115.30806914  8422.51807746  9976.05377826 ...  9089.65372668
  9435.81550922  8806.79394589]

Оценка эффективности модели ML

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

Чтобы найти эти значения, мы можем использовать методы из класса metrics из библиотеки sklearn .

from sklearn import metrics

print('MAE:', metrics.mean_absolute_error(y_test, predictions))
print('MSE:', metrics.mean_squared_error(y_test, predictions))

Выход:

MAE: 3874.1898429849575
MSE: 23810661.195583127

Вывод

Машинное обучение может быть использовано для решения самых разных задач. В этой статье мы использовали алгоритм машинного обучения, чтобы предсказать сумму, которую клиент, скорее всего, потратит в Черную пятницу. Мы также провели исследовательский анализ данных, чтобы найти интересные тенденции из набора данных. Ради практики я предлагаю вам попытаться предсказать Продукт, который клиент с большей вероятностью купит, в зависимости от его пола, возраста и профессии.