0 Introducción:
Tenemos los datos de marketing de una compañía de alimentación llamada iFood cuya principal actividad es la entrega de alimentos en Brasil. La empresa vende alimentos en diversas categorías y busca mejorar el rendimiento de las actividades de marketing. La nueva campaña comercial, sexta, tiene como objetivo vender un nuevo gadget a la base de datos de clientes. Se llevó a cabo una campaña piloto en la que participaron 2.240 clientes. Los clientes fueron seleccionados al azar y contactados por teléfono para la adquisición del gadget. El conjunto de datos de está practica se denomina marketing.csv. Las variables que contiene son:
- ID: Número identificativo
- Year_Birth: Año de nacimiento
- Education: El nivel educativo del cliente (factor con 5 niveles)
- Marital_Status: El estado civil del cliente (factor con 8 niveles)
- Income: Ingresos anuales del cliente
- Kidhome: Número de niños que habitan con el cliente
- Teenhome: Número de adolescentes que habitan con el cliente
- Dt_Customer: Fecha de alta del cliente en la empresa
- Recency: Número de días desde la última compra
- MntWines: Cantidad gastada en vino en los últimos 2 años
- MntFruits: Cantidad gastada en fruta en los últimos 2 años
- MntMeatProducts: Cantidad gastada en carne en los últimos 2 años
- MntFishProducts: Cantidad gastada en pescado en los últimos 2 años
- MntSweetProducts: Cantidad gastada en dulces en los últimos 2 años
- MntGoldProds: Cantidad gastada en productos “gold” en los últimos 2 años
- NumDealsPurchases: Número de compras hechas con descuento
- NumWebPurchases: Número de compras hechas a través de la Web
- NumCatalogPurchases: Número de compras hechas usando el catálogo
- NumStorePurchases: Número de compras hechas directamente en tiendas
- NumWebVisitsMonth: Número de visitas a la Web en el último mes
- AcceptedCmp3: 1 si el cliente acepta la oferta en la 3ª campaña, 0 si no
- AcceptedCmp4: 1 si el cliente acepta la oferta en la 4ª campaña, 0 si no
- AcceptedCmp5: 1 si el cliente acepta la oferta en la 5ª campaña, 0 si no
- AcceptedCmp1: 1 si el cliente acepta la oferta en la 1ª campaña, 0 si no
- AcceptedCmp2: 1 si el cliente acepta la oferta en la 2ª campaña, 0 si no
- Complain: 1 si el cliente formaliza una queja en el último año
- Z_CostContact: Variable control (se debe excluir del análisis)
- Z_Revenue: Variable control (se debe excluir del análisis)
- Response: 1 si el cliente acepta la oferta en la última campaña, 0 si no
El conjunto de datos original se encuentra disponible en el siguiente enlace El objetivo final es desarrollar un modelo que permita identificar a los clientes según sus características. En este proyecto se analizará si los ingresos de los clientes están determinados por el nivel educativo y otras características.
1 Preprocesado:
En esta sección vamos a cargar y analizar el conjunto de datos y prepararlo con unas transformaciones iniciales para todo el análisis posterior.
1.1 Variables Income y Year_Birth:
Cargamos el conjunto de datos:
Consultamos los tipos de datos de las variables:
## 'data.frame': 2240 obs. of 29 variables:
## $ ID : int 5524 2174 4141 6182 5324 7446 965 6177 4855 5899 ...
## $ Year_Birth : int 1957 1954 1965 1984 1981 1967 1971 1985 1974 1950 ...
## $ Education : chr "Graduation" "Graduation" "Graduation" "Graduation" ...
## $ Marital_Status : chr "Single" "Single" "Together" "Together" ...
## $ Income : int 58138 46344 71613 26646 58293 62513 55635 33454 30351 5648 ...
## $ Kidhome : int 0 1 0 1 1 0 0 1 1 1 ...
## $ Teenhome : int 0 1 0 0 0 1 1 0 0 1 ...
## $ Dt_Customer : chr "2012-09-04" "2014-03-08" "2013-08-21" "2014-02-10" ...
## $ Recency : int 58 38 26 26 94 16 34 32 19 68 ...
## $ MntWines : int 635 11 426 11 173 520 235 76 14 28 ...
## $ MntFruits : int 88 1 49 4 43 42 65 10 0 0 ...
## $ MntMeatProducts : int 546 6 127 20 118 98 164 56 24 6 ...
## $ MntFishProducts : int 172 2 111 10 46 0 50 3 3 1 ...
## $ MntSweetProducts : int 88 1 21 3 27 42 49 1 3 1 ...
## $ MntGoldProds : int 88 6 42 5 15 14 27 23 2 13 ...
## $ NumDealsPurchases : int 3 2 1 2 5 2 4 2 1 1 ...
## $ NumWebPurchases : int 8 1 8 2 5 6 7 4 3 1 ...
## $ NumCatalogPurchases: int 10 1 2 0 3 4 3 0 0 0 ...
## $ NumStorePurchases : int 4 2 10 4 6 10 7 4 2 0 ...
## $ NumWebVisitsMonth : int 7 5 4 6 5 6 6 8 9 20 ...
## $ AcceptedCmp3 : int 0 0 0 0 0 0 0 0 0 1 ...
## $ AcceptedCmp4 : int 0 0 0 0 0 0 0 0 0 0 ...
## $ AcceptedCmp5 : int 0 0 0 0 0 0 0 0 0 0 ...
## $ AcceptedCmp1 : int 0 0 0 0 0 0 0 0 0 0 ...
## $ AcceptedCmp2 : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Complain : int 0 0 0 0 0 0 0 0 0 0 ...
## $ Z_CostContact : int 3 3 3 3 3 3 3 3 3 3 ...
## $ Z_Revenue : int 11 11 11 11 11 11 11 11 11 11 ...
## $ Response : int 1 0 0 0 0 0 0 0 1 0 ...
Tranformamos y codificamos las variables Education y Marital_status:
# Transformar las variables adecuadas
data$Education <- as.factor(data$Education)
data$Marital_Status <- as.factor(data$Marital_Status)
Comprobamos si tenemos inconsistencias en las variables Income y Year_Birth y las corregimos:
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 1730 35303 51382 52247 68522 666666 24
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1893 1959 1970 1969 1977 1996
Vemos varios NA’s en la variable Income que vamos a resolver en el siguiente apartado. Pero nos llama la atención el máximo 666666, haremos un plot de los datos para ver si se trata un outlier o no:
Tal y como sospechabamos, se trata de un outlier. Estableceremos un umbral para que aquellos valores superiores a 200000 los impute como un valor perdido NA:
Ahora nos haremos cargo de la variable Year_Birth en la que vemos que el mínimo es el año 1893 (algo absurdo). Vamos a filtrar aquellos datos por debajo de 1924 (100 años) y los declararemos como NA’s ya que es muy difícil que una persona logre cumplir 100 años. Quizá estamos siendo demasiado prudentes estableciendo ese umbral de 100 años, pero tampoco queremos ser estrictos imponiendo otra edad más limitada (como los 70 u 80 años) y perder información:
1.2 Valores ausentes:
Tratamos los valores ausentes de la variable Income mediante el método KNN usando la distancia Gower con las variables de gasto (de la 10 a la 15).
Cargamos la librería VIM:
## Loading required package: VIM
## Loading required package: colorspace
## Loading required package: grid
## VIM is ready to use.
## Suggestions and bug-reports can be submitted at: https://github.com/statistikat/VIM/issues
##
## Attaching package: 'VIM'
## The following object is masked from 'package:datasets':
##
## sleep
# Necesitaremos también la librería cluster para el cálculo
# de la distancia gower (daisy)
if (!require('cluster')) install.packages('cluster'); library('cluster')
## Loading required package: cluster
Definimos un conjunto de datos auxiliar para las variables de gasto (de la 10 a la 15):
# Definimos las variables de gasto como aquellas de la 10 a la 15
variables_gasto <- data[, 10:15]
# Comprobamos
colnames(variables_gasto)
## [1] "MntWines" "MntFruits" "MntMeatProducts" "MntFishProducts"
## [5] "MntSweetProducts" "MntGoldProds"
Imputamos:
# Imputación por vecinos más cercanos para la variable Income
data <- kNN(data, variable = "Income", dist_var = colnames(variables_gasto),
k = 5)
Comprobamos:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1730 35303 51301 51947 68468 162397
No tenemos valores perdidos en la variable Income. Pasemos ahora a la variable Year_Birth, veamos antes de imputar cuantos NA’s tenemos:
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 1940 1959 1970 1969 1977 1996 3
Imputamos mediante la mediana de la variable Year_Birth entre aquellas muestras con el valor widow en la variable Marital_Status:
# Imputación por mediana para Year_Birth en estado civil "Viudo/a"
median_year_birth <- median(data$Year_Birth[data$Marital_Status == "Widow"],
na.rm = TRUE)
# Omitimos los NA
data$Year_Birth[is.na(data$Year_Birth)] <- median_year_birth
Comprobamos de nuevo:
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1940 1959 1970 1969 1977 1996
Finalmente omitimos todos los valores ausentes en un nuevo dataframe llamado markclean:
Comprobamos:
## [1] 0
Comprobamos cuanta información hemos perdido:
## [1] 2240
## [1] 2240
No tenemos valores ausentes en ninguna variable, y tampoco hemos visto una pérdida en el número de filas del conjunto de datos después de realizar las imputaciones en Income y Year_Birth por lo que ya no supone ningún problema y podemos trabajar con este dataframe.
2 Estadística descriptiva:
En esta sección vamos a estudiar el coeficiente de variación para comprobar si la media de una variable es representativa en el conjunto de datos o no, en este caso lo haremos para la variable Income. Luego para la variable Education, mostaremos una tabla de datos estadísticos descriptivos de los ingresos (Income) según el nivel educativo Education.
2.1 Income:
Calculamos el coeficiente de variación:
# Calcular el coeficiente de variación
mean_income <- mean(markclean$Income, na.rm = TRUE)
sd_income <- sd(markclean$Income, na.rm = TRUE)
cv_income <- sd_income / mean_income
# Mostrar el resultado
cv_income
## [1] 0.4159884
El valor del coeficiente de variación obtenido es \(\approx 0.42\), el cual es menor que \(1\) por lo que el valor medio de la variable Income es representativo en este conjunto de datos. Vamos a representar los datos en un histograma para analizar visualmente la distribución de los datos:
Los datos siguen una distribución normal, centrada en torno al valor 50000 ya que la curva envolvente de las barra de nuestro hidtograma se asemeja a la curva que define una campana de Gauss.
Otra forma de comprobar si los datos tienen una distribución normal, es mediante una representación Q-Q:
Vemos que el grueso de los datos se ajusta a la recta que define una distribución normal.
2.2 Education:
Cargamos la librería dplyr y la ggplot2:
## Loading required package: dplyr
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
## Loading required package: ggplot2
Mostramos las estadisticas descriptivas para la variable Education:
# Reordenamos el factor Education de mayor a menor nivel educativo
markclean$Education <- factor(markclean$Education,
levels = c("PhD", "Master",
"Graduation", "2n Cycle",
"Basic"))
# Calculamos las estadísticas descriptivas por nivel educativo
summary_by_education <- markclean %>%
group_by(Education) %>%
summarize(mean_income = mean(Income, na.rm = TRUE),
sd_income = sd(Income, na.rm = TRUE),
count = n()) %>%
arrange(Education)
# Mostramos la tabla
summary_by_education
## # A tibble: 5 × 4
## Education mean_income sd_income count
## <fct> <dbl> <dbl> <int>
## 1 PhD 56061. 20544. 486
## 2 Master 53014. 20082. 370
## 3 Graduation 52040. 21376. 1127
## 4 2n Cycle 48051. 23298. 203
## 5 Basic 20306. 6235. 54
Vemos como era de esperar que a mayor nivel de estudios mayor nivel de ingresos promedio. La diferencia más significativa es con nivel de estudios Basic donde la siguiente categoría (2n Cycle) es más del doble, por otro lado son minoría (sólo 54 personas cuentan con ese nivel de estudios básico).
La mayoría de personas tienen un graduado universitario Graduation y la diferencia del nivel de ingresos promedio es sólo de mil dólares aproximadamente… Podríamos decir que “casi no merece la pena” invertir tiempo y dinero en hacer un máster (Master) sino tienes intención de continuar hacía un doctorado (PhD) si tu objetivo es tener un nivel de ingresos mayor basándonos sólo en el promedio, no podemos perder de vista que el promedio es algo orientativo y siempre debemos tener en cuenta la variabildiad.
Mostraremos ahora un boxplot:
# Boxplot de ingresos por nivel educativo
ggplot(markclean, aes(x = Education, y = Income)) +
geom_boxplot() +
labs(title = "Ingresos por Nivel Educativo", x = "Nivel Educativo",
y = "Ingresos")
Con el boxplot vemos que la variabilidad de los ingresos promedio en las categorías PhD y Master son similares (altura de la caja similar), Luego para Graduation y 2nd Cycle la variabilidad es mayor. Lo más destacable es que las personas con un nivel de estudios básico (Basic) su promedio de ingresos está muy por debajo del resto como ya vimos en la tabla anterior, pero además no vemos outliers ninguno y su variabilidad (la altura de su caja) ni siquiera alcanza la cota inferior de las otras categorías.
La categoría que presenta mayor número de outliers es PhD por lo que a pesar de que el promedio de Income en esa categoría se sitúa en torno a los 56000 dólares. Otro punto a destacar es que todos los outliers en todas las categorías son al alza respecto a la caja (destacan por encima) y entre todas las categorías, excepto en un caso para PhD obtienen ingresos similares (por encima de 150000 dólares).
3 Estadística inferencial:
En esta sección vamos a realizar un contraste de hipótesis.
3.1 Contraste de hipótesis para la diferencia de medias:
3.1.1 Hipótesis nula y alternativa:
La hipótesis nula (\(H_{0}\)) será que las personas sin estudios universitarios tienen un nivel de ingresos igual o superior al de las personas con estudios universitarios:
\[H_{0}:\mu_{sin\ estudios\ universitarios} \ge \mu_{con\ estudios\ universitarios}\] Por otro lado la hipótesis alternativa (\(H_{1}\)) dice lo contraio:
\[H_{1}:\mu_{sin\ estudios\ universitarios} < \mu_{con\ estudios\ universitarios}\]
3.1.2 Justificación del test a aplicar:
Vamos a utilizar una prueba t de Welch debido a que esta prueba está diseñada para comparar la media de dos grupos de datos cuando los tamaños de las muestras o sus varianzas no son comparables. En nuestro caso la muestra depersoans sin estudios universitarios (Basic y 2n Cycle) es de 257 personas (ver tabla de la sección 2.2) y el conjunto de personas con estudios universitarios es próximo a las 2000 personas (Graduation, Master y PhD), casí 10 veces más.
Este test t de Welch es apropiado para este tipo de situaciones porque a pesar de seguir asumiendo una distribución normal de los datos (como es nuestro caso), no asume varianzas iguales entre las dos categorías de datos. Además, los grados de libertad se ajustan de manera más precisa tomando en cuenta las varianzas y tamaños de muestras en cada caso.
3.1.3 Cálculos:
# Dividimos los datos en dos subconjuntos según el nivel de estudios
grupo_sin_uni <- markclean %>% filter(Education == "Basic" |
Education == "2n Cycle")
grupo_con_uni <- markclean %>% filter(Education == "Graduation" |
Education == "Master" |
Education == "PhD")
# Calculamos las medias y desviaciones estándar en cada caso
mean_sin_uni <- mean(grupo_sin_uni$Income, na.rm = TRUE)
mean_con_uni <- mean(grupo_con_uni$Income, na.rm = TRUE)
sd_sin_uni <- sd(grupo_sin_uni$Income, na.rm = TRUE)
sd_con_uni <- sd(grupo_con_uni$Income, na.rm = TRUE)
# Definimos el tamaño de muestra de cada subconjunto
n_sin_uni <- nrow(grupo_sin_uni)
n_con_uni <- nrow(grupo_con_uni)
# Calculamos el estadístico de contraste
se_diff <- sqrt((sd_sin_uni^2 / n_sin_uni) + (sd_con_uni^2 / n_con_uni))
t_stat <- (mean_sin_uni - mean_con_uni) / se_diff
# Definimos el umbral para un nivel de confianza del 99%
alpha <- 0.01
df <- min(n_sin_uni - 1, n_con_uni - 1)
t_crit <- qt(1 - alpha, df)
# Calculamos el p-valor
p_value <- pt(t_stat, df)
# Mostramos los resultados
list(t_stat = t_stat, t_crit = t_crit, p_value = p_value)
## $t_stat
## [1] -7.063255
##
## $t_crit
## [1] 2.341002
##
## $p_value
## [1] 7.661834e-12
3.1.4 Interpretación del test:
El valor estadístico es significativamente menor (\(-7.06\)) que el valor crítico (\(2.34\)). Esto nos indica que la diferencia observada entre las medidas es lo suficientemente grande como para no poder ser atribuida al azar, en otras palabras, esto confirma la hipótesis alternativa \(H_{1}\) que dice que las personas con estudios universitarios tienen un nivel de ingresos promedio mayor que el de aquellas personas sin estudios universitarios.
Por otro lado, el p-valor es \(-7.66\times10^{-12}\) que es muchísimo menor que el nivel de significancia que impusimos, es decir, el parámetro \(\alpha=0.01\) en nuestro código de la sección anterior, que es el \(1\%\), que falta del umbral de confianza que se nos pidió (\(99\%\)). Esto nos dice que la probabilidad de que la diferencia entre las medidas osbservadas tiene una probabilidad extremadamente baja de que sea debido al azar.
4 Modelo de regresión:
En esta sección vamos a estudiar el conjunto con un modelo de regresión lineal múltiple y también analizaremos la posible multicolinealidad de las variables.
4.1 Regresión lineal múltiple:
Vamos a definir un modelo de regresión lineal múltiple teniendo en cuenta las variables explicativas: Year_Birth, Kidhome, Teenhome, Education, MntWines, MntFruits, MntMeatProducts, MntFishProducts, MntSweetProducts, MntGoldProds, NumDealsPurchases, NumCatalogPurchases, NumStorePurchases y NumWebVisitsMonth.
# Establecemos la categoría "Basic" de la variable "Education" como referencia
markclean$Education <- relevel(markclean$Education, ref = "Basic")
# Definimos el modelo de regresión lineal múltiple
modelo_lm_multi <- lm(Income ~ Year_Birth + Kidhome + Teenhome + Education +
MntWines + MntFruits + MntMeatProducts +
MntFishProducts + MntSweetProducts + MntGoldProds +
NumDealsPurchases + NumCatalogPurchases +
NumStorePurchases + NumWebVisitsMonth, data = markclean)
# Resumen de los resultados del modelo
summary(modelo_lm_multi)
##
## Call:
## lm(formula = Income ~ Year_Birth + Kidhome + Teenhome + Education +
## MntWines + MntFruits + MntMeatProducts + MntFishProducts +
## MntSweetProducts + MntGoldProds + NumDealsPurchases + NumCatalogPurchases +
## NumStorePurchases + NumWebVisitsMonth, data = markclean)
##
## Residuals:
## Min 1Q Median 3Q Max
## -94999 -5933 102 5719 110527
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.054e+05 4.287e+04 2.458 0.01406 *
## Year_Birth -3.572e+01 2.171e+01 -1.645 0.10010
## Kidhome 1.093e+03 5.678e+02 1.925 0.05434 .
## Teenhome 6.281e+03 5.204e+02 12.070 < 2e-16 ***
## EducationPhD 1.343e+04 1.591e+03 8.437 < 2e-16 ***
## EducationMaster 1.222e+04 1.602e+03 7.629 3.48e-14 ***
## EducationGraduation 1.170e+04 1.525e+03 7.669 2.57e-14 ***
## Education2n Cycle 1.155e+04 1.658e+03 6.963 4.37e-12 ***
## MntWines 1.803e+01 1.059e+00 17.017 < 2e-16 ***
## MntFruits 1.910e+01 7.905e+00 2.416 0.01578 *
## MntMeatProducts 2.319e+01 1.679e+00 13.807 < 2e-16 ***
## MntFishProducts 9.580e+00 5.991e+00 1.599 0.10997
## MntSweetProducts 3.055e+01 7.465e+00 4.093 4.42e-05 ***
## MntGoldProds 4.573e-01 5.217e+00 0.088 0.93016
## NumDealsPurchases -4.461e+02 1.481e+02 -3.013 0.00262 **
## NumCatalogPurchases 6.870e+02 1.328e+02 5.175 2.49e-07 ***
## NumStorePurchases 6.146e+02 1.043e+02 5.892 4.40e-09 ***
## NumWebVisitsMonth -2.638e+03 1.313e+02 -20.093 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 10680 on 2222 degrees of freedom
## Multiple R-squared: 0.7574, Adjusted R-squared: 0.7555
## F-statistic: 408 on 17 and 2222 DF, p-value: < 2.2e-16
El valor de \(R^{2}\) de nuestro ajuste es de \(0.75\), es decir, aproximadamente el \(75\%\) de la variabilidad en los ingresos, se explica por este modelo el cual presenta un buen ajuste.
Intercept: El intercepto nos indica el valor estimado de la variable de estudio cuando todas las variables independientes son 0. En nuestro caso la estimación es de \(105400\), en algún caso podríamos utilizar este valor como referencia.
Year_Birth: Cada año adicional en el año de nacimiento (es decir, personas más jóvenes) disminuyen aproximadamente en \(35.72\) (\(estimate=-3.57\times10^{1}\)) unidades el nivel de ingresos. Este coeficient tiene mucha significancia (\(Pr(>|t|)=0.10\)).
Kidhome: Por cada hijo pequeño adicional en casa, el ingreso aumenta aproximadamente en \(1093\) unidades (\(estimate=1.093\times10^{3}\)) su nivel de ingresos. Este coeficiente tiene una significancia alta (\(Pr(>|t|)=0.05\)).
Teenhome: Por cada adolescente adicional en casa, el ingreso aumenta aproximadamente en \(6281\) unidades (\(estimate=6.281\times10^{3}\)) su nivel de ingresos. Este coeficiente tiene una significancia muy alta (\(Pr(>|t|)<2\times10^{-16}\)).
Education (PhD): Los individuos con doctorado, tienen ingresos que en promedio son \(13430\) unidades (\(estimate=1.343\times10^{4}\)) más altos que aquellos con titulación básica (Education=Basic). Este coeficiente tiene una significancia muy alta (\(Pr(>|t|)<2\times10^{-16}\)).
Education (Master): Los individuos con máster universitario, tienen ingresos que en promedio son \(12220\) unidades (\(estimate=1.222\times10^{4}\)) más altos que aquellos con titulación básica (Education=Basic). Este coeficiente tiene una significancia muy alta (\(Pr(>|t|)=3.48\times10^{-14}\)).
Education (Graduation): Los individuos con graduado universitario, tienen ingresos que en promedio son \(11700\) unidades (\(estimate=1.170\times10^{4}\)) más altos que aquellos con titulación básica (Education=Basic). Este coeficiente tiene una significancia muy alta (\(Pr(>|t|)=2.57\times10^{-14}\)).
Education (2n Cycle): Los individuos con estudios de segundo ciclo, tienen ingresos que en promedio son \(11550\) unidades (\(estimate=1.155\times10^{4}\)) más altos que aquellos con titulación básica (Education=Basic). Este coeficiente tiene una significancia muy alta (\(Pr(>|t|)=4.37\times10^{-12}\)).
MntWines: Cada unidad adicional gastada en vinos aumenta el ingreso en \(19.01\) unidades (\(estimate=1.910\times10\)). Este coeficiente tiene una significancia muy alta (\(Pr(>|t|)<2\times10^{-16}\)).
MntFruits: Cada unidad adicional gastada en fruta aumenta el ingreso en \(18.03\) unidades (\(estimate=1.803\times10\)). Este coeficiente tiene una significancia alta ($Pr(>|t|)=0.01578 $).
MntMeatProducts: Cada unidad adicional gastada en carne aumenta el ingreso en \(23.19\) unidades (\(estimate=2.319\times10\)). Este coeficiente tiene una significancia muy alta (\(Pr(>|t|)<2\times10^{-16}\)).
MntFishProducts: Cada unidad adicional gastada en pescado aumenta el ingreso en \(9.580\) unidades (\(estimate=9.580\)). Este coeficiente no tiene mucha significancia (\(Pr(>|t|)=0.10\)).
MntGoldProducts: Cada unidad adicional gastada en oro aumenta el ingreso en \(0.46\) unidades (\(estimate=4.573\times10^{-1}\)). Este coeficiente no tiene significancia (\(Pr(>|t|)=0.93016\)).
NumDealsPurchases: Cada compra con descuento adicional realizada por el individuo disminuye el ingreso en \(446.10\) unidades (\(estimate=-4.461\times10^{2}\)). Este coeficiente tiene una significancia alta (\(Pr(>|t|)=0.00262\)).
NumCatalogPurchases: Cada compra adicional por catalogo realizada por el individuo aumenta el ingreso en \(687\) unidades (\(estimate=6.870\times10^{2}\)). Este coeficiente tiene una significancia muy alta (\(Pr(>|t|)=2.49\times10^{-7}\)).
NumCatalogPurchases: Cada compra adicional en tienda realizada por el individuo aumenta el ingreso en \(614.60\) unidades (\(estimate=6.146\times10^{2}\)). Este coeficiente tiene una significancia muy alta (\(Pr(>|t|)=4.40\times10^{-9}\)).
NumWebVisitsMonth: Cada visita adicional realizada a la web en el último mes del individuo disminuye el ingreso en \(2638\) unidades (\(estimate=-2.638\times10^{3}\)). Este coeficiente tiene una significancia muy alta (\(Pr(>|t|)<2\times10^{-16}\)).
4.1.1 Multicolinealidad:
En este apartado, vamos a trabajar con la función vif de la librería car:
## Loading required package: car
## Loading required package: carData
##
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
##
## recode
Vamos a calcular el factor de inflación de la varianza (vif) para analizar la presencia o no de multicolinealidad interpretando dicho valor:
## GVIF Df GVIF^(1/(2*Df))
## Year_Birth 1.265872 1 1.125110
## Kidhome 1.833236 1 1.353970
## Teenhome 1.574872 1 1.254939
## Education 1.238617 4 1.027110
## MntWines 2.493927 1 1.579217
## MntFruits 1.938817 1 1.392414
## MntMeatProducts 2.818138 1 1.678731
## MntFishProducts 2.100976 1 1.449474
## MntSweetProducts 1.862501 1 1.364735
## MntGoldProds 1.452514 1 1.205203
## NumDealsPurchases 1.605039 1 1.266901
## NumCatalogPurchases 2.953736 1 1.718644
## NumStorePurchases 2.255633 1 1.501877
## NumWebVisitsMonth 1.990912 1 1.410997
En nuestro caso todos los valores vif son bajos (inferiores a 5), por lo que podemos afirmar que en nuestro dataset no hay indicios de multicolinealidad entre las variables explicativas.
4.2 Regresión logística:
En este apartado vamos a definir un modelo predictivo basado en la regresión logística.
4.2.1 Modelo predictivo:
Definimos un modelo de regresión logística que intentará predecir la probabilidad de aceptar o no la oferta de la sexta campaña publicitaria de iFood basándose en el número de compras con descuento (NumDealsPurchases), el número de visitas a la página web en el último mes (NumWebVisitsMonth), y basándose también en si el cliente ha aceptado o no las ofertas de campñas publicitarias anteriores (AcceptedCmp1, AcceptedCmp2, AcceptedCmp3, AcceptedCmp4 y AcceptedCmp5):
# Definimos el modelo de regresión logística
modelo_log <- glm(Response ~ NumDealsPurchases + NumWebVisitsMonth +
AcceptedCmp1 + AcceptedCmp2 + AcceptedCmp3 +
AcceptedCmp4 + AcceptedCmp5,
data = markclean, family = binomial)
# Resumimos los resultados del modelo
summary(modelo_log)
##
## Call:
## glm(formula = Response ~ NumDealsPurchases + NumWebVisitsMonth +
## AcceptedCmp1 + AcceptedCmp2 + AcceptedCmp3 + AcceptedCmp4 +
## AcceptedCmp5, family = binomial, data = markclean)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -3.14012 0.19610 -16.013 < 2e-16 ***
## NumDealsPurchases 0.08116 0.03356 2.418 0.01559 *
## NumWebVisitsMonth 0.09583 0.03114 3.078 0.00209 **
## AcceptedCmp1 1.49663 0.22679 6.599 4.13e-11 ***
## AcceptedCmp2 0.91645 0.49651 1.846 0.06492 .
## AcceptedCmp3 1.83486 0.18906 9.705 < 2e-16 ***
## AcceptedCmp4 0.56992 0.22946 2.484 0.01300 *
## AcceptedCmp5 1.98210 0.22824 8.684 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 1886.8 on 2239 degrees of freedom
## Residual deviance: 1539.5 on 2232 degrees of freedom
## AIC: 1555.5
##
## Number of Fisher Scoring iterations: 5
Intercept: El intercepto nos indica el valor estimado de la variable de estudio cuando todas las variables independientes son 0. En nuestro caso la estimación es de \(-3.14\). Este tiene sentido ya que si el potencial cliente no no ve las campañas, ni compra previamente ninguna oferta ni visita la página web, es casi seguro que no aceptara ninguna oferta.
NumDealsPurchase: Cada compra con descuento adicional del individuo aumenta la probabilidad de que acepte la oferta en \(0.08\) unidades (\(estimate=0.08116\)). Este coeficiente tiene una significancia moderada (\(Pr(>|t|)=0.01559\)).
NumWebVisitsMonth: Cada visita adicional a la web en el último mes por parte del individuo aumenta la probabilidad de que acepte la oferta en \(0.09\) unidades (\(estimate=0.09583\)). Este coeficiente tiene una significancia alta (\(Pr(>|t|)=0.00209\)).
AcceptedCmp1: Haber aceptado la primera campaña de marketing, aumenta la probabilidad de que acepte la oferta en \(1.5\) unidades (\(estimate=1.49663\)). Este coeficiente tiene una significancia muy alta (\(Pr(>|t|)=4.13\times10^{-11}\)).
AcceptedCmp2: Haber aceptado la segunda campaña de marketing, aumenta la probabilidad de que acepte la oferta en \(0.9\) unidades (\(estimate=0.91645\)). Este coeficiente tiene una significancia moderada (\(Pr(>|t|)=0.06492\)).
AcceptedCmp3: Haber aceptado la tercera campaña de marketing, aumenta la probabilidad de que acepte la oferta en \(1.83\) unidades (\(estimate=1.83486\)). Este coeficiente tiene una significancia muy alta (\(Pr(>|t|)<2\times10^{-16}\)).
AcceptedCmp4: Haber aceptado la cuarta campaña de marketing, aumenta la probabilidad de que acepte la oferta en \(0.56\) unidades (\(estimate=0.56992\)). Este coeficiente tiene una significancia moderada (\(Pr(>|t|)=0.013\)).
AcceptedCmp5: Haber aceptado la quinta campaña de marketing, aumenta la probabilidad de que acepte la oferta en \(1.98210\) unidades (\(estimate=0.56992\)). Este coeficiente tiene una significancia muy alta (\(Pr(>|t|)<2\times10^{-16}\)).
4.2.2 Matriz de confusión:
Instalamos y cargamos la librería caret:
## Loading required package: caret
## Loading required package: lattice
Vamos a evaluar la precisión del modelo mediante la matriz de confusión:
# Hacemos las predicciones
pred_log <- predict(modelo_log, type = "response")
# Definimos que la predicción del modelo es un acierto (1) si la probabilidad
# es superior a 0.5 y 0 en caso contrario
pred_clas <- ifelse(pred_log >= 0.5, 1, 0)
# Calculamos la matriz de confusión
conf_matrix <- confusionMatrix(as.factor(pred_clas), as.factor(markclean$Response))
# Mostramos la matriz de confusión y las métricas adicionales
conf_matrix
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 1872 263
## 1 34 71
##
## Accuracy : 0.8674
## 95% CI : (0.8527, 0.8812)
## No Information Rate : 0.8509
## P-Value [Acc > NIR] : 0.01418
##
## Kappa : 0.2715
##
## Mcnemar's Test P-Value : < 2e-16
##
## Sensitivity : 0.9822
## Specificity : 0.2126
## Pos Pred Value : 0.8768
## Neg Pred Value : 0.6762
## Prevalence : 0.8509
## Detection Rate : 0.8357
## Detection Prevalence : 0.9531
## Balanced Accuracy : 0.5974
##
## 'Positive' Class : 0
##
Tenemos para la matriz de confusión:
- Verdaderos negativos (True Negative, TN): 1872
- Falsos positivos (False Positive, FP): 263
- Falsos negativos (False Negative, FN): 34
- Verdaderos positivos (True Positive, TP): 71
El modelo parece estar sesgado hacia el lado de los clientes que no aceptan la oferta (que es la clase mayoritaria con \(1872+263=2135\) individuos) frente aquellos que si aceptaron la oferta (solo \(34+71=105\) individuos).
Para la precisión del modelo tenemos una precisión alta, exactamente del \(86.74\%\) (\(Accuracy=0.8674\)). A pesar de que el modelo (aparentemente) tiene un sesgo hacia la clase mayoritaria (no aceptan la oferta), el modelo sigue representando un valor añadido ya que la precisión (\(Accuracy=0.8674\)) es superior al NIR (\(no\ information\ rate = 0.8509\)), de hecho vemos el \(p-value\ [Acc\ >\ NIR]=0.014418\) que viene a decir en cuanto supera un parámetro al otro.
En cuanto a la sensibilidad y especificidad tenemos:
- Sensibilidad o tasa de verdaderos positivos (sensitivity, recall): \(0.9822\approx98.22\%\)
- Especificidad o tasa de verdaderos negativos (Specificity, recall): \(0.2126\approx21.26\%\)
Estos datos confirman que el modelo tiene un sesgo ya que una sensibilidad alta (\(98.22\%\)) implica que el modelo es muy eficaz para identificar a los clientes que no aceptarán la oferta, por otro lado, una especificidad baja (\(21.26\%\))nos sugiere que tendrá dificultades para identificar a los individuos que si aceptarían la oferta.
4.2.3 Predicción:
Hacemos el cálculo manual para un supuesto cliente que ha comprado 5 veces con descuento, ha visitado la web 10 veces y ha aceptado todas las ofertas de camapñas previas:
# Cálculo manual
coef_log <- coef(modelo_log)
new_data <- data.frame(NumDealsPurchases = 5, NumWebVisitsMonth = 10,
AcceptedCmp1 = 1, AcceptedCmp2 = 1,
AcceptedCmp3 = 1, AcceptedCmp4 = 1, AcceptedCmp5 = 1)
prob <- 1 / (1 + exp(-(coef_log[1] + coef_log[2]*5 + coef_log[3]*10 +
coef_log[4]*1 + coef_log[5]*1 + coef_log[6]*1 +
coef_log[7]*1 + coef_log[8]*1)))
Cálculamos ahora con la función predict:
Comprobamos y comparamos resultados:
## $prob_manual
## (Intercept)
## 0.9934639
##
## $prob_predict
## 1
## 0.9934639
Nuestro modelo funciona correctamente y devuelve la misma predicción que la calculada “manualmente”.
5 ANOVA unifactorial:
En esta sección vamos a realizar un estudio de análisis de varianza (ANOVA).
5.1 Visualización gráfica:
Vamos a mostrar gráficamente la distribución de la variable Income según Education:
# Primero necesitamos la librería ggpubr
if (!require('ggpubr')) install.packages('ggpubr'); library('ggpubr')
## Loading required package: ggpubr
# Mostramos el gráfico de distribución de variables descrito anteriormente
ggline(markclean, x = "Education", y = "Income", add = c("mean_se", "jitter"))
Vemos que si existen diferencias en cuanto a la distribución de los niveles de ingreso (Income) respecto al nivel educativo (Education). En concreto, como ya afirmamos en la sección 2.2 con el boxplot, las personas en el nivel educativo básico (Basic) tienen una variabilidad mucho menor en cuanto a niveles de ingresos (digamos que su espectro de nivel de ingresos está más “enjaulado” o “encasillado” en un rango más estrecho y/o ajustado).
5.2 Hipótesis nula y alternativa:
Vamos a escribir la hipótesis nula que afirmaría que los niveles de ingresos son similares entre todos los posibles niveles educativos de las personas: \[H_{0}:\mu_{Basic}=\mu_{2n\ Cycle}=\mu_{Graduation}=\mu_{Master}=\mu_{PhD}\] Y la hipótesis alternativa: \[H_{1}:Al\ menos\ una\ de\ las\ medidas\ es\ diferente\ del\ resto\ (\neq)\]
5.3 Modelo:
Definimos el modelo ANOVA y analizamos la varianza:
## Df Sum Sq Mean Sq F value Pr(>F)
## Education 4 6.580e+10 1.645e+10 37.53 <2e-16 ***
## Residuals 2235 9.797e+11 4.384e+08
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Tenemos un valor “p” extremadamente bajo (\(Pr(>F)<2\times10^{-16}\)), lo cual nos indica que la variabilidad entre los niveles de ingresos (Income) de las muestras debida a la diferencia en niveles de educación (Education) es estadísticamente muy significativa.
5.4 Efectos de los niveles del factor y fuerza de relación:
Queremos estimar el efecto de los niveles de la variable Education y la fuerza de relación:
## Tables of means
## Grand mean
##
## 51946.91
##
## Education
## Basic PhD Master Graduation 2n Cycle
## 20306 56061 53014 52040 48051
## rep 54 486 370 1127 203
# Fuerza de relación
SSB <- sum(anova(anova_model)[["Sum Sq"]][1])
SST <- sum(anova(anova_model)[["Sum Sq"]])
eta_squared <- SSB / SST
eta_squared
## [1] 0.06293556
Vemos que los ingresos (Income) promedio varían con el nivel educativo (Education), sobre todo para el nivel de estudios básico (Basic).
Por otro lado vemos que: \(\eta^{2}=\frac{SSB}{SST}=0.06293556\approx6.29\%\), es decir, aproximadamente el \(6.29\%\) de la variabilidad de los niveles de ingreso se explica por el nivel educativo. Este resultado nos indica que existen otros factores no incluidos en el modelo que también influyen en el promedio de la variable Income.
No debemos perder de vista que este análsis tiene muchas variables y existe cierto contexto diferente cada uno en la vida de cada persona y que también está relacionado al nivel de estudios o el propio contexto influye al nivel de estudios en sí.
5.5 Normalidad de los residuos:
Repetimos el gráfico Q-Q similar al de la sección 2.1, pero en este caso para los residuos del nuestro modelo en lugar de para la variable Income como en el caso anterior:
Vemos que la distribución de los residuos del modelo se ajusta a una distribución normal.
Ahora realizaremos el test de Shapiro-Wilk para evaluar la normalidad de los residuos:
##
## Shapiro-Wilk normality test
##
## data: residuals(anova_model)
## W = 0.97507, p-value < 2.2e-16
Tenemos un valor \(W=0.97507\approx97.5\%\) muy cercano a \(1\) (\(100\%\)), lo que refuerza que los residuos del modelo \(ANOVA\) siguen una distribución normal.
Por último analizamos la homocedasticidad mediante una representación gráfica del modelo:
Claramente el conjunto de datos no presenta homocedasticidad ya que vemos claros patrones y que la varianza no es constante.
6 Comparaciones múltiples:
Haremos uso de la función pairwise.t.test de R para realizar las comparaciones múltiples con corrección Bonferroni
##
## Pairwise comparisons using t tests with pooled SD
##
## data: markclean$Income and markclean$Education
##
## Basic PhD Master Graduation
## PhD < 2e-16 - - -
## Master < 2e-16 0.3498 - -
## Graduation < 2e-16 0.0041 1.0000 -
## 2n Cycle < 2e-16 4.9e-05 0.0670 0.1253
##
## P value adjustment method: bonferroni
Todas las comparaciones entre el nivel educativo Basic y el resto de niveles educativos son significativamente diferentes (\(<2\times10^{-16}\)), lo que indica que las personas con educación básica tienden a tener ingresos muy inferiores en comparación con aquellos que cuentan con una educación superior.
Entre los niveles educativos superiores (PhD, Master, Graduation y 2n Cycle) hay algunas diferencias significativas entre PhD y Graduation y también entre PhD y 2n Cycle.
7 ANOVA multifactorial:
Repetiremos el análisis de varianza de la sección 5 pero en este caso combinando las variables Income, Education y Response al mismo tiempo en el análisis.
7.1 Análsis visual de los efectos principales y posibles interacciones:
Agrupamos los datos según Education y Response y calculamos la media de ingresos para cada grupo:
# Agrupar y calcular la media de ingresos
mean_income_by_group <- markclean %>%
group_by(Education, Response) %>%
summarize(mean_income = mean(Income, na.rm = TRUE))
## `summarise()` has grouped output by 'Education'. You can override using the
## `.groups` argument.
Mostramos los datos en formato tabla bajo la agrupación de ingresos promedio y la respuesta a la última oferta para cada nivel educativo:
## # A tibble: 10 × 3
## # Groups: Education [5]
## Education Response mean_income
## <fct> <int> <dbl>
## 1 Basic 0 20377.
## 2 Basic 1 18456
## 3 PhD 0 54614.
## 4 PhD 1 61581.
## 5 Master 0 51880.
## 6 Master 1 59241.
## 7 Graduation 0 50656.
## 8 Graduation 1 60920.
## 9 2n Cycle 0 47103.
## 10 2n Cycle 1 55849.
En todos los casos, el nivel de ingresos promedio (mean_income) es superior en aquellos que aceptan la oferta (\(Response=1\)) a excepción del caso de las personas con nivel de educación básico (\(Education=Basic\)) que ocurre lo contrario. Este resultado para \(Education=Basic\) es algo contraintuitivo, ya que por educación tienen un promedio de ingresos más bajo entre todos los demás, y de entre aquellos con \(Education=Basic\), los que tienen aún menos recursos (menor mean_income), son estos últimos los que aceptan la oferta. Esto podría sugerir que, las personas que cuentan con menos ingresos y menos educación, en promedio son más imprudentes financieramente hablando.
Mostramos el gráfico de interacción:
# Gráfico de interacción
ggplot(markclean, aes(x = Education, y = Income,
color = as.factor(Response))) +
geom_point(stat = "summary", fun.y = "mean") +
geom_line(stat = "summary", fun.y = "mean", aes(group = Response))
## Warning in geom_point(stat = "summary", fun.y = "mean"): Ignoring unknown
## parameters: `fun.y`
## Warning in geom_line(stat = "summary", fun.y = "mean", aes(group = Response)):
## Ignoring unknown parameters: `fun.y`
## No summary function supplied, defaulting to `mean_se()`
## No summary function supplied, defaulting to `mean_se()`
Vemos una clara relación en que el nivel educativo influye en el nivel de ingresos y por tanto aquellos con más ingresos son más propensos en conjunto de aceptar una oferta publicitaria.
7.2 Cálculo del modelo:
Definimos el nuevo modelo ANOVA multifactorial para comprobar si existe o no la interacción entre los factores de las variables Education y Response en relación a la variable Income:
anova_multifactor <- aov(Income ~ Education * Response, data = markclean)
summary(anova_multifactor)
## Df Sum Sq Mean Sq F value Pr(>F)
## Education 4 6.580e+10 1.645e+10 38.298 < 2e-16 ***
## Response 1 2.099e+10 2.099e+10 48.878 3.59e-12 ***
## Education:Response 4 8.649e+08 2.162e+08 0.503 0.733
## Residuals 2230 9.579e+11 4.295e+08
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
7.3 Interpretación de los resultados:
Como llevamos viendo a lo largo de todo el proyecto, el nivel educativo tiene un impacto significativo en el nivel de ingresos de los individuos.
La respuesta a la oferta también tiene un impacto significativo en los niveles de ingresos, en concreto, aceptar la oferta está asociado con ingresos diferentes en comparación con no aceptarla.
Sin embargo, no vemos una interacción significativa entre los niveles educativos y la respuesta a la oferta surgiriendo así que el efecto del nivel educativo en los ingresos es consistene independientemente de si aceptan la oferta o no y viceversa.
8 Resumen ejecutivo:
En este estudio, analizamos cómo la educación y la respuesta a ofertas de campañas publicitarias previas influyen en los niveles de ingresos de los individuos. A continuación, presentamos los hallazgos más importantes de nuestro análisis:
Impacto de la Educación en los Ingresos
- Encontramos que el nivel educativo tiene un impacto significativo en los ingresos de las personas.
- Las personas con niveles educativos más altos, como un doctorado (PhD), tienden a ganar significativamente más que aquellas con educación básica.
- Esto sugiere que invertir en educación puede llevar a mayores ingresos a lo largo del tiempo.
Efecto de las Ofertas de Campañas
- Encontramos que la respuesta a las ofertas de campañas de marketing afecta significativamente los ingresos.
- Aquellos que aceptaron las ofertas generalmente tienen ingresos más altos.
- Esto indica que las campañas de marketing son más efectivas entre los clientes con mayores ingresos.
Relación entre Educación y Aceptación de Ofertas
- Analizamos si la combinación de nivel educativo y aceptación de ofertas tiene un efecto adicional sobre los ingresos.
- Aunque tanto la educación como la aceptación de ofertas influyen en los ingresos, no encontramos evidencia de que su combinación tenga un efecto extra significativo. Es decir, cada factor actúa de manera independiente sobre los ingresos.
Distribución y Consistencia de los Resultados
- Observamos que los ingresos son más altos en todos los niveles educativos para aquellos que aceptaron las ofertas en comparación con los que no las aceptaron. A excepción de las personas con nivel educativo básico, donde esta tendencia se revierte (en esta categoría, son aquellos con menos ingresos los que tienden a aceptar la oferta).
- Sin embargo, la diferencia de ingresos es más notable en los niveles educativos más altos.
Conclusiones
- Importancia de la Educación: Fomentar y facilitar el acceso a niveles educativos más altos puede ser una estrategia efectiva para incrementar los ingresos de la población.
- Estrategias de Marketing: Las campañas de marketing deben enfocarse en clientes con mayores ingresos y niveles educativos superiores, ya que son más propensos a aceptar las ofertas y generar mayores ingresos.
En resumen, la educación y la respuesta a las campañas de marketing son factores clave que influyen en los ingresos. Comprender y aprovechar estas relaciones puede ser de ayuda a la empresa para diseñar estrategias más efectivas y dirigidas a mejorar el alcance y éxito comercial.
9 Propuestas de mejora:
Hemos observado que el conjunto de datos del que partimos era un conjunto de datos desbalanceado en términos de nivel educativo (Education), si atendemos al gráfico de la sección 5.1 o hacemos el recuento explícito:
##
## Basic PhD Master Graduation 2n Cycle
## 54 486 370 1127 203
Vemos que el dataset contiene muy pocas muestras de individuos con nivel educativo básico (\(Education=Basic\)).
Podríamos haber hecho una partición aleatoria por cada uno de los otros niveles educativos y así obtener aproximadamente el mismo número de muestras para cada categoría de Education y repetir todo el análsis previo para comprobar si existen (o no) diferencias en los resultados.
Por último sólo quedaría probar el modelo frente a conjuntos de datos similares o adaptarlo un poco para replicar el estudio con datos de empresas de alimentación similares a iFood o incluso empresas de venta de otro tipo de artículos y/o servicios.