Análisis de las tendencias de compras del Black friday a través del aprendizaje automático

Introducción

Wikipedia define el Viernes Negro 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 es] 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 Viernes Negro. Extraeremos información útil que responderá a preguntas tales como: ¿qué género hace más las compras el viernes negro? ¿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 aprendizaje automático simple que predice la cantidad de dinero que una persona probablemente gastará en el Viernes Negro según 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 Viernes Negro, que se realizan en una tienda minorista. El archivo se puede descargar en el siguiente enlace de Kaggle: Black Friday Case Study .

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  
Mirando los datos, podemos concluir que nuestro conjunto posee 12 parámetros diferentes: 7 variables numéricas (enteras y flotantes) y 5 variables de objeto. Además, el conjunto de datos contiene dos variables de tipo corto: Product_Category_2Product_Category_3Veremos más adelante cómo manejar este problema.
Bien, ahora tenemos una imagen general de los datos, imprimamos información sobre los primeros cinco clientes (primeras cinco filas de nuestro DataFrame):
data.head()  
La primera pregunta que quiero formular desde el comienzo de este estudio, ¿es cierto que las clientas son muy dominantes en comparación con los clientes masculinos? Usaremos la seabornbiblioteca y la countplotfunció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 masculinos que femeninos. ¿Porqué es eso? Tal vez los visitantes varones tengan más probabilidades de salir y comprar algo para sus damas cuando haya más ofertas presentes.
Vamos a explorar la Gendercategoría un poco más. Queremos ver ahora la distribución de la variable de género, pero teniendo en cuenta la Agecategoría. Una vez más se countplotusará la función, pero ahora con el hueparámetro definido .
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 años, para ambos sexos. La población más joven y mayor está mucho menos representada en el Viernes Negro. Sobre la base de estos resultados, la tienda minorista debería vender la mayoría de los productos que se dirigen a las personas entre los 20 y los 30 años. Para aumentar las ganancias, se puede aumentar la cantidad de productos dirigidos a personas de alrededor de los treinta, mientras que se puede reducir la cantidad de productos dirigidos a la población mayor o menor.
A continuación, utilizaremos la función describir para analizar nuestras categorías, en términos de valores medios, valores mínimos y máximos, desviaciones estándar, etc.
data.describe()  
Además, a continuación analizamos la User_IDcolumna utilizando el nuniquemétodo. De esto podemos concluir que en esta tienda minorista específica, durante el Viernes Negro, 5,891 clientes diferentes han comprado algo en la tienda. Además, de la Product_IDcategoría podemos extraer información de que se venden 3,623 productos diferentes.
data['User_ID'].nunique()  
Salida:
5891  
data['User_ID'].nunique()  
Salida:
3623  
Ahora vamos a explorar la Occupationcategoría. El Occupationnú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 vamos a realizar el análisis exacto. Primero, debemos crear la función que extraerá todos los elementos únicos de una columna (para extraer todas las ocupaciones diferentes).
Usaremos la uniquefunción para eso, desde la numpybiblioteca 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, se registran 21 ID de ocupaciones diferentes durante el día de compras.
El número de Ocupación podría representar diferentes profesiones de 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 (agrupado 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 las OccupationsID, 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 esto es realmente muy probable. O tal vez la tienda minorista es 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 Viernes Negro y no solo una.
Ahora, tenemos información sobre cuánto dinero se gasta por categoría de ocupación. Ahora vamos a graficar 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 que tienen ocupaciones 0 y 4 gastan más dinero durante las ventas del Viernes Negro. Por otro lado, las personas que pertenecen a las ocupaciones con ID 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, por el contrario, las personas más ricas a las que no les gusta comprar en ese tipo de tiendas minoristas. Tenemos una deficiencia en la información para responder a esa pregunta, y debido a eso, nos detendríamos aquí con el análisis de la Occupationcategoría.
City_CategoryLa variable es la siguiente. Esta categoría nos da información sobre las ciudades desde donde están nuestros clientes. Primero, veamos cuántas ciudades diferentes tenemos.
data['City_Category'].nunique()  
Salida:
3  
Ahora, será interesante ver en porcentajes, cuál es la proporción de clientes de cada ciudad. Esta información se presentará en forma de un gráfico circular de color. 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 esté en algún lugar entre estas tres ciudades, sea de fácil acceso y tenga buenas conexiones de carreteras desde estas ciudades.

Preprocesamiento de datos para algoritmos ML

Hemos cubierto hasta ahora algunas técnicas básicas para analizar datos en bruto. Antes de poder aplicar algoritmos de aprendizaje automático a nuestro conjunto de datos, debemos convertirlo en una forma determinada en la que puedan funcionar los algoritmos de aprendizaje automático. La tarea de los algoritmos de aprendizaje será predecir el valor de la Purchasevariable, dada la información del cliente como entrada.
Lo primero que debemos hacer es lidiar con los datos faltantes en columnas Product_Category_2Product_Category_3Solo tenemos el 30% de los datos en el interior Product_Category_3y el 69% de los datos en el interior Product_Category_2El 30% de los datos reales es una proporción pequeña. Podríamos llenar 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 aprendizaje automático. La mejor alternativa para este problema es eliminar esta columna de un análisis más detallado. Usaremos la dropfunción para hacer eso:
data = data.drop(['Product_Category_3'], axis=1)  
La columna Product_Category_2posee alrededor del 30% de los datos faltantes. Aquí tiene sentido llenar los valores faltantes y usar esta columna para ajustar un modelo de aprendizaje automático. Resolveremos este problema insertando un valor medio de los valores existentes en esta columna en los campos que faltan:
data['Product_Category_2'].fillna((data['Product_Category_2'].mean()), inplace=True)  
Veamos ahora nuestro marco de datos de nuevo:
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  
Se resuelve el problema de los valores perdidos. 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 propósitos de predicción.
La Product_IDcolumna contiene información sobre el producto comprado. No es una característica del cliente. Por lo tanto, vamos a eliminar eso también.
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 Purchasecolumna) y 8 variables que usaremos para entrenar nuestro modelo de aprendizaje automático.
Como podemos ver en la tabla de información, estamos tratando con 4 columnas categóricas. Sin embargo, los modelos básicos de aprendizaje automático son capaces de procesar valores numéricos. Por lo tanto, necesitamos convertir las columnas categóricas a las numéricas.
Podemos usar una get_dummiesfunción de Python que convierte los valores categóricos en vectores codificados en caliente. ¿Como funciona? Tenemos 3 ciudades en nuestro conjunto de datos: A, B, y C. Supongamos que un cliente es de la ciudad B. La get_dummiesfunción devolverá un vector codificado en caliente uno para ese registro que se parece a esto: [0 1 0]Para un cliente de la ciudad A: [1 0 0]y desde C: [0 0 1]En resumen, para cada ciudad se crea una nueva columna, que se rellena con todos los ceros excepto las filas donde el cliente pertenece a esa ciudad en particular. Tales filas contendrán 1.
La siguiente secuencia de comandos crea uno en caliente vectores codificados para GenderAgeCity, y Stay_In_Current_City_Yearscolumna.
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 ese valor de columna será igual a 1, otras columnas de otros grupos de edad tendrán un valor de 0. Del mismo modo, si es un cliente masculino, 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 aprendizaje automático.

Predecir la cantidad gastada

En este artículo, usaremos uno de los modelos de aprendizaje automático más simples, es decir, el modelo de regresión lineal, para predecir la cantidad gastada por el cliente en el Viernes Negro.
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í: Regresión lineal en Python
Este modelo, como la mayoría de los algoritmos de aprendizaje automático supervisado, realiza una predicción basada en las características de entrada. Los valores de salida predichos se utilizan para comparaciones con las salidas deseadas y se calcula un error. La señal de error se propaga de nuevo a través del modelo y los parámetros del modelo se actualizan de forma que se minimice 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.
Basta con la teoría, ¡construyamos un verdadero sistema de LD! 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 la train_test_splitfunción para dividir todos nuestros datos en dos conjuntos: conjunto de entrenamiento y pruebas. 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 pruebas) se utilizará para evaluar el rendimiento.
El siguiente script divide nuestro conjunto de datos en 60% de entrenamiento y 40% de prueba:
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 a la gente! Nuestro modelo está entrenado. Ahora podemos imprimir el valor del parámetro de intercepció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 capacitación buscaba los mejores valores de estos coeficientes durante la fase de aprendizaje. Los valores presentados en la salida anterior son los valores más óptimos para los coeficientes de nuestro modelo de aprendizaje automático.
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 del rendimiento del modelo ML

Al final, siempre es bueno estimar nuestros resultados al encontrar el error absoluto medio ( MAE ) y el 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 correcta para los modelos de aprendizaje automático .
Para encontrar estos valores, podemos usar métodos de la metricsclase de la sklearnbiblioteca.
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 aprendizaje automático se puede utilizar para una variedad de tareas. En este artículo, utilizamos un algoritmo de aprendizaje automático para predecir la cantidad que un cliente probablemente gastará en el Viernes Negro. También realizamos análisis de datos exploratorios para encontrar tendencias interesantes a partir del conjunto de datos. Por el bien de la práctica, le sugeriré que intente predecir el Producto que es más probable que compre el cliente, dependiendo de su género, edad y ocupación.

Acerca de: Programator

Somos Instinto Programador

0 comentarios:

Publicar un comentario

Dejanos tu comentario para seguir mejorando!

Con tecnología de Blogger.