Автор оригинала: 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
Вывод
Машинное обучение может быть использовано для решения самых разных задач. В этой статье мы использовали алгоритм машинного обучения, чтобы предсказать сумму, которую клиент, скорее всего, потратит в Черную пятницу. Мы также провели исследовательский анализ данных, чтобы найти интересные тенденции из набора данных. Ради практики я предлагаю вам попытаться предсказать Продукт, который клиент с большей вероятностью купит, в зависимости от его пола, возраста и профессии.