Análisis de las tendencias de compra del Black Friday a través del Machine Learning

A

Introducción

Wikipedia define Black Friday como un nombre informal para el viernes siguiente al Día de Acción de Gracias en los Estados Unidos, que se celebra el cuarto jueves de noviembre. [Black Friday is] considerado como el comienzo de la temporada de compras navideñas de Estados Unidos […].

En este artículo, intentaremos explorar diferentes tendencias del conjunto de datos de compras del Black Friday. Extraeremos información útil que responderá a preguntas como: ¿qué género compra más en Black Friday? ¿Las ocupaciones de las personas tienen algún impacto en las ventas? ¿Qué grupo de edad es el que más gasta?

Al final, crearemos un algoritmo de Machine Learning simple que predice la cantidad de dinero que es probable que una persona gaste el Black Friday en función de características como el género, la edad y la ocupación.

El conjunto de datos que usaremos en este artículo incluye 550.000 observaciones sobre el Black Friday, que se realizan en una tienda minorista. El archivo se puede descargar en el siguiente enlace de Kaggle: Estudio de caso de Black Friday.

Análisis de los datos

El primer paso es importar las bibliotecas que necesitaremos en esta sección:

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

A continuación, necesitamos importar nuestros datos.

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

¡Veamos información básica sobre nuestros datos!

data.info()

Salida:

<class 'pandas.core.frame.DataFrame'>
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

Al observar los datos, podemos concluir que nuestro conjunto posee 12 parámetros diferentes: 7 numéricos (enteros y flotantes) y 5 variables de objeto. Además, el conjunto de datos contiene dos variables de tipo corto: Product_Category_2 y Product_Category_3. Más adelante veremos cómo manejar este problema.

Bien, ahora tenemos una imagen general de los datos, imprimamos información sobre los primeros cinco clientes (las primeras cinco filas de nuestro DataFrame):

data.head()

La primera pregunta que quiero hacer desde el comienzo de este estudio, ¿es cierto que las clientas son muy dominantes en comparación con los clientes masculinos? Usaremos el seaborn biblioteca y la countplot función para trazar el número de clientes masculinos y femeninos.

sns.countplot(data['Gender'])

¡Guauu! ¡El gráfico muestra que hay casi 3 veces más clientes hombres que mujeres! ¿Porqué es eso? Tal vez sea más probable que los visitantes masculinos salgan y compren algo para sus mujeres cuando haya más ofertas.

Exploremos el Gender categoría un poco más. Queremos ver ahora la distribución de la variable de género, pero teniendo en cuenta la Age categoría. Una vez más countplot se utilizará la función, pero ahora con definida hue parámetro.

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

De la figura anterior, podemos concluir fácilmente que el mayor número de clientes pertenece al grupo de edad entre 26 y 35, para ambos sexos. La población más joven y de mayor edad está mucho menos representada en el Black Friday. Con base en estos resultados, la tienda minorista debería vender la mayoría de los productos dirigidos a personas entre los veinte y los treinta años. Para aumentar las ganancias, se puede aumentar la cantidad de productos dirigidos a personas de alrededor de treinta años, mientras que se puede reducir la cantidad de productos dirigidos a la población mayor o más joven.

A continuación, utilizaremos la función describe para analizar nuestras categorías, en términos de valores medios, valores mínimo y máximo, desviaciones estándar, etc.

data.describe()

Además, a continuación analizamos el User_ID columna usando el nunique método. De esto podemos concluir que en esta tienda minorista específica, durante el Black Friday, 5.891 clientes diferentes han comprado algo en la tienda. Además, de Product_ID categoría podemos extraer información de que se comercializan 3.623 productos diferentes.

data['User_ID'].nunique()

Salida:

5891
data['User_ID'].nunique()

Salida:

3623

Ahora exploremos el Occupation categoría. los Occupation número es el número de identificación del tipo de ocupación de cada cliente. Podemos ver que existen alrededor de 20 ocupaciones diferentes. Pero realicemos un análisis exacto. Primero, necesitamos crear la función que extraerá todos los elementos únicos de una columna (para extraer todas las diferentes ocupaciones).

Usaremos el unique función para eso, desde el numpy Biblioteca de Python.

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

Salida:

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]

Como podemos ver, durante el día de compras se registran 21 identificaciones de ocupación diferentes.

El número de Ocupación podría representar diferentes profesiones de los clientes: por ejemplo, el número 1 podría ser un ingeniero, el número 2 – un médico, el número 3 un artista, etc.

También sería interesante ver cuánto dinero gastó cada grupo de clientes (agrupados por ID de ocupación). Para hacer eso, podemos usar un bucle for y sumar el dinero gastado para cada ID de ocupación individual:

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

spent_money

Salida:

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

Hemos creado la lista spent_money, que incluye cantidades sumadas de dólares para el Occupations ID: de 0 a 20. Puede parecer extraño en los resultados que se gasten cientos de millones de dólares. Pero tenga en cuenta que nuestro conjunto de datos incluye 500.000 observaciones, por lo que es muy probable. O tal vez la tienda minorista sea en realidad un gran centro comercial. Otra explicación de las enormes sumas de dinero gastadas por cada ocupación es que estos datos pueden representar las transacciones de varias noches de Black Friday, y no solo una.

Ahora, tenemos información sobre cuánto dinero se gasta por categoría de ocupación. Tracemos ahora gráficamente esta información.

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()

Se puede observar fácilmente que las personas con ocupaciones 0 y 4 gastaron más dinero durante las ventas del Black Friday. Por otro lado, las personas pertenecientes a las ocupaciones con DNI 18, 19, y especialmente la ocupación 8, han gastado la menor cantidad de dinero. Puede implicar que estos grupos son los más pobres, o al contrario, las personas más ricas a las que no les gusta comprar en ese tipo de tiendas minoristas. Tenemos una deficiencia de información para responder a esa pregunta, y por eso, nos detendríamos aquí con el análisis de la Occupation categoría.

City_Category variable es la siguiente. Esta categoría nos da información sobre las ciudades de las que son nuestros clientes. Primero, veamos cuántas ciudades diferentes tenemos.

data['City_Category'].nunique()

Salida:

3

Ahora, será interesante ver en porcentajes, cuál es el ratio de clientes de cada ciudad. Esta información se presentará en forma de un gráfico circular de colores. Podemos hacerlo en 5 líneas de código. Todopoderoso Python, ¡gracias! 🙂

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()

Es evidente en el gráfico circular que las tres ciudades están representadas casi por igual en la tienda minorista durante los viernes negros. Quizás la tienda se encuentre en algún lugar entre estas tres ciudades, sea de fácil acceso y tenga buenas conexiones por carretera desde estas ciudades.

Preprocesamiento de datos para algoritmos ML

Hemos cubierto hasta ahora algunas técnicas básicas para analizar datos sin procesar. Antes de que podamos aplicar algoritmos de Machine Learning a nuestro conjunto de datos, debemos convertirlo en una forma determinada en la que puedan operar los algoritmos de Machine Learning. La tarea de los algoritmos de aprendizaje será predecir el valor de la Purchase variable, dada la información del cliente como entrada.

Lo primero que debemos hacer es lidiar con los datos faltantes en las columnas. Product_Category_2 y Product_Category_3. Tenemos solo el 30% de los datos adentro Product_Category_3 y el 69% de los datos dentro Product_Category_2. El 30% de los datos reales es una proporción pequeña, podríamos completar los valores faltantes dentro de esta categoría con la media de los valores existentes, pero eso significa que el 70% de los datos serán artificiales, lo que podría arruinar nuestro futuro modelo de Machine Learning. La mejor alternativa para este problema es eliminar esta columna de un análisis más detallado. Usaremos drop función para hacer eso:

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

La columna Product_Category_2 posee alrededor del 30% de los datos faltantes. Aquí tiene sentido completar los valores faltantes y usar esta columna para ajustar un modelo de Machine Learning. Resolveremos este problema insertando un valor medio de los valores existentes en esta columna en los campos faltantes:

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

Ahora revisemos nuestro marco de datos nuevamente:

data.info()

Salida:

<class 'pandas.core.frame.DataFrame'>
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

El problema de los valores perdidos está resuelto. A continuación, eliminaremos las columnas que no ayudan en la predicción.

User_ID Este es el número asignado automáticamente a cada cliente y no es útil para fines de predicción.

los Product_ID La columna contiene información sobre el producto adquirido. No es una característica del cliente. Por lo tanto, también lo eliminaremos.

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

Salida:

<class 'pandas.core.frame.DataFrame'>
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

Nuestra selección final se basa en 9 columnas, una variable que queremos predecir (la Purchase columna) y 8 variables que usaremos para entrenar nuestro modelo de Machine Learning.

Como podemos ver en la tabla de información, estamos tratando con 4 columnas categóricas. Sin embargo, los modelos básicos de Machine Learning son capaces de procesar valores numéricos. Por lo tanto, necesitamos convertir las columnas categóricas en numéricas.

Podemos usar un get_dummies Función de Python que convierte valores categóricos en vectores codificados one-hot. ¿Como funciona? Tenemos 3 ciudades en nuestro conjunto de datos: A, B y C. Digamos que un cliente es de la ciudad B. get_dummies La función devolverá un vector codificado one-hot para ese registro que se ve así: [0 1 0]. Para un cliente de la ciudad A: [1 0 0] y de C: [0 0 1]. En resumen, para cada ciudad se crea una nueva columna, que se llena con todos los ceros excepto las filas donde el cliente pertenece a esa ciudad en particular. Tales filas contendrán 1.

El siguiente script crea vectores codificados one-hot para Gender, Age, Cityy Stay_In_Current_City_Years columna.

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()

En la siguiente captura de pantalla, se presentan las columnas ficticias recién creadas. Como puede ver, todas las variables categóricas se transforman en numéricas. Por lo tanto, si un cliente tiene entre 0 y 17 años (por ejemplo), solo el valor de la columna será igual a 1, otras, las columnas de otros grupos de edad tendrán un valor de 0. De manera similar, si es un cliente masculino, el la columna denominada ‘M’ será igual a 1 y la columna ‘F’ será 0.

Ahora tenemos los datos que se pueden usar fácilmente para entrenar un modelo de Machine Learning.

Predecir la cantidad gastada

En este artículo, usaremos uno de los modelos de Machine Learning más simples, es decir, el modelo de regresión lineal, para predecir la cantidad gastada por el cliente en el Black Friday.

La regresión lineal representa un método muy simple para el aprendizaje supervisado y es una herramienta eficaz para predecir respuestas cuantitativas. Puede encontrar información básica al respecto aquí mismo: Regresión lineal en Python

Este modelo, como la mayoría de los algoritmos de Machine Learning supervisados, hace una predicción basada en las características de entrada. Los valores de salida predichos se utilizan para realizar comparaciones con las salidas deseadas y se calcula un error. La señal de error se propaga de regreso a través del modelo y los parámetros del modelo se actualizan para minimizar el error. Finalmente, se considera que el modelo está completamente entrenado si el error es lo suficientemente pequeño. Esta es una explicación muy básica y vamos a analizar todos estos procesos en detalle en futuros artículos.

Suficiente con la teoría, ¡construyamos un sistema ML real! Primero, necesitamos crear vectores de entrada y salida para nuestro modelo:

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']

Ahora, importaremos el train_test_split función para dividir todos nuestros datos en dos conjuntos: conjunto de entrenamiento y prueba. El conjunto de entrenamiento se utilizará para adaptarse a nuestro modelo. Los datos de entrenamiento siempre se utilizan para aprender, ajustar los parámetros de un modelo y minimizar un error en la salida. El resto de los datos (el conjunto de prueba) se utilizará para evaluar el rendimiento.

El siguiente script divide nuestro conjunto de datos en un conjunto de entrenamiento del 60% y un conjunto de prueba del 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)

Ahora es el momento de importar nuestro modelo de regresión lineal y entrenarlo en nuestro conjunto de entrenamiento:

from sklearn.linear_model import LinearRegression

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

Salida:

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

¡Felicidades gente! Nuestro modelo está entrenado. Ahora podemos imprimir el valor del parámetro de intersección y los valores de todos los coeficientes de nuestro modelo, después del procedimiento de aprendizaje:

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

Salida:

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

Como puede ver, cada categoría de nuestro conjunto de datos ahora se define con un coeficiente de regresión. El proceso de formación buscó los mejores valores de estos coeficientes durante la fase de aprendizaje. Los valores presentados en el resultado anterior son los valores más óptimos para los coeficientes de nuestro modelo de Machine Learning.

Es hora de usar los datos de prueba como entradas del modelo para ver qué tan bien funciona nuestro modelo.

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

Salida:

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

Estimación de rendimiento del modelo ML

Al final, siempre es bueno estimar nuestros resultados encontrando el error absoluto medio (MAE) y error cuadrático medio (MSE) de nuestras predicciones. Puede encontrar cómo calcular estos errores aquí: Cómo seleccionar la métrica de evaluación adecuada para modelos de Machine Learning.

Para encontrar estos valores, podemos usar métodos del metrics clase de sklearn biblioteca.

from sklearn import metrics

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

Salida:

MAE: 3874.1898429849575
MSE: 23810661.195583127

Conclusión

El Machine Learning se puede utilizar para una variedad de tareas. En este artículo, utilizamos un algoritmo de Machine Learning para predecir la cantidad que es probable que un cliente gaste en el Black Friday. También realizamos análisis de datos exploratorios para encontrar tendencias interesantes en el conjunto de datos. En aras de la práctica, sugeriré que intente predecir el Producto que es más probable que el cliente compre, según su sexo, edad y ocupación.

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad