Year Latitude Longitude Sea.Surface.Temp
Min. :1993 Min. :-5.000 Min. :-110.0 Min. :21.60
1st Qu.:1993 1st Qu.:-2.000 1st Qu.:-110.0 1st Qu.:23.50
Median :1995 Median :-1.000 Median :-102.5 Median :26.55
Mean :1995 Mean :-1.375 Mean :-102.5 Mean :25.86
3rd Qu.:1997 3rd Qu.: 0.000 3rd Qu.: -95.0 3rd Qu.:28.21
Max. :1997 Max. : 0.000 Max. : -95.0 Max. :30.17
NA's :3
Air.Temp Humidity UWind VWind
Min. :21.42 Min. :71.60 Min. :-8.100 Min. :-6.200
1st Qu.:23.26 1st Qu.:81.30 1st Qu.:-5.100 1st Qu.: 1.500
Median :24.52 Median :85.20 Median :-3.900 Median : 2.900
Mean :25.03 Mean :84.43 Mean :-3.716 Mean : 2.636
3rd Qu.:27.08 3rd Qu.:88.10 3rd Qu.:-2.600 3rd Qu.: 4.100
Max. :28.50 Max. :94.80 Max. : 4.300 Max. : 7.300
NA's :81 NA's :93
Realicemos ahora un diagnóstico simple de datos perdidos usando las funciones básicas de R:
#Para ver que columnas tienen valores perdidoscolmiss<-which(colSums(is.na(tao))!=0)colmiss
Sea.Surface.Temp Air.Temp Humidity
4 5 6
#Para ver el porcentaje de valores perdidos en las columnasper.miss.col=100*colSums(is.na(tao[,colmiss]))/dim(tao)[1]per.miss.col
Variables sorted by number of missings:
Variable Count
Humidity 0.126358696
Air.Temp 0.110054348
Sea.Surface.Temp 0.004076087
Year 0.000000000
Latitude 0.000000000
Longitude 0.000000000
UWind 0.000000000
VWind 0.000000000
########################################################## Mecanismo: ¿MCAR o MAR? ########################################################### Matrix plotmatrixplot(tao)
#Parallel boxplotsVIM::pbox(tao[4:6], pos=1)
Cuando la cantidad de datos perdidos es trivial es posible eliminar los datos perdidos con la función na.omit():
########################################################## Eliminación de casos: Complete Case Analysis ########################################################### solo si es trivial y MCAR tao.cl=na.omit(tao)
En caso de tener hasta una cantidad manejable de datos perdidos y un mecanismo MCAR, se puede usar una medida de tendencia central como una alternativa de imputación (reemplazo) de datos perdidos:
########################################################## Imputación ###########################################################----------------------------------------## Usando una medida de Tendencia Central ##----------------------------------------#library(DMwR2)tao.c<-centralImputation(tao)summary(tao.c)
Year Latitude Longitude Sea.Surface.Temp
Min. :1993 Min. :-5.000 Min. :-110.0 Min. :21.60
1st Qu.:1993 1st Qu.:-2.000 1st Qu.:-110.0 1st Qu.:23.52
Median :1995 Median :-1.000 Median :-102.5 Median :26.55
Mean :1995 Mean :-1.375 Mean :-102.5 Mean :25.87
3rd Qu.:1997 3rd Qu.: 0.000 3rd Qu.: -95.0 3rd Qu.:28.21
Max. :1997 Max. : 0.000 Max. : -95.0 Max. :30.17
Air.Temp Humidity UWind VWind
Min. :21.42 Min. :71.60 Min. :-8.100 Min. :-6.200
1st Qu.:23.38 1st Qu.:81.70 1st Qu.:-5.100 1st Qu.: 1.500
Median :24.52 Median :85.20 Median :-3.900 Median : 2.900
Mean :24.97 Mean :84.53 Mean :-3.716 Mean : 2.636
3rd Qu.:26.99 3rd Qu.:87.70 3rd Qu.:-2.600 3rd Qu.: 4.100
Max. :28.50 Max. :94.80 Max. : 4.300 Max. : 7.300
Year Latitude Longitude Sea.Surface.Temp
Min. :1993 Min. :-5.000 Min. :-110.0 Min. :21.60
1st Qu.:1993 1st Qu.:-2.000 1st Qu.:-110.0 1st Qu.:23.52
Median :1995 Median :-1.000 Median :-102.5 Median :26.55
Mean :1995 Mean :-1.375 Mean :-102.5 Mean :25.87
3rd Qu.:1997 3rd Qu.: 0.000 3rd Qu.: -95.0 3rd Qu.:28.21
Max. :1997 Max. : 0.000 Max. : -95.0 Max. :30.17
Air.Temp Humidity UWind VWind
Min. :21.42 Min. :71.60 Min. :-8.100 Min. :-6.200
1st Qu.:23.38 1st Qu.:81.70 1st Qu.:-5.100 1st Qu.: 1.500
Median :24.52 Median :85.20 Median :-3.900 Median : 2.900
Mean :24.97 Mean :84.53 Mean :-3.716 Mean : 2.636
3rd Qu.:26.99 3rd Qu.:87.70 3rd Qu.:-2.600 3rd Qu.: 4.100
Max. :28.50 Max. :94.80 Max. : 4.300 Max. : 7.300
Por otro lado, si se tiene una cantidad manejable de datos perdidos y un mecanismo MAR, se puede utilizar un modelo simple de aprendizaje supervisado para la imputación:
#----------------------------------------## Usando Modelos de Regresión ##----------------------------------------#library(simputation)## Considerando otras variables como predictorastao.i <-impute_lm(tao, Air.Temp + Humidity ~ Sea.Surface.Temp + UWind + VWind | Year)tao[c(108:110, 463,551:552),]
Year Latitude Longitude Sea.Surface.Temp Air.Temp Humidity UWind VWind
108 1997 0 -95 27.69 NA 79.8 -0.6 4.2
109 1997 0 -95 27.63 NA 74.5 -3.9 5.8
110 1997 0 -95 27.51 NA 76.3 -2.8 5.3
463 1993 0 -95 NA NA NA -5.6 3.1
551 1993 0 -95 24.78 24.76 NA -1.8 2.3
552 1993 0 -95 24.79 24.49 NA -1.4 3.4
Cuando el mecanismo es NMAR o la cantidad de datos perdidos es grande, se requiere de usar métodos más sofisticados.
Ejemplo 2: Exploración de Datos
El archivo MarketingDirecto.csv contiene datos de un vendedor de marketing directo el cuál vende sus productos sólo a través de correos electrónicos personalizados. El vendedor envía catálogos a los clientes con las características de los productos, y estos ordenan directamente de los catálogos.
El responsable de marketing ha desarrollado registros de clientes para aprender qué hace que algunos clientes gasten más que otros. El conjunto de datos incluye \(n = 1000\) clientes y las siguientes variables:
Edad: Grupo etario del cliente (Adulta/Media/Joven).
Genero: Género del cliente (Masculino/Femenino).
Vivienda: Si el cliente es dueño de su casa (Propia/Alquilada)
Ecivil: Estado civil (Soltero/Casado).
Ubicacion: Ubicación de un negocio que vende productos similares en términos de distancia (Lejos/Cerca).
Salario: Sueldo anual de los clientes (en dólares)
Hijos: Número de hijos (0-3).
Historial: Historial del volumen de compra anterior (Bajo/Medio/Alto/NA). NA significa que este cliente aún no ha adquirido ningún producto.
Catalogos: Número de catálogos enviados.
Monto: Gasto en dólares
Preparando el entorno:
Primero cargamos las librerías de R que usaremos en este laboratorio:
Ahora importamos la base de datos y realizamos un preprocesamiento básico para poder realizar el análisis exploratorio de los datos.
# Lectura de datosDMark <-read.csv("MarketingDirecto.csv")# Remover valores distintosDMark <-distinct(DMark)# Remover valores perdidosDMark <-na.omit(DMark)# Inspeccionar el contenido y estructura de los datos importadoshead(DMark)
Edad Genero Vivienda Ecivil Ubicacion Salario Hijos Historial
1 Adulta Femenino Propia Soltero Lejos 47500 0 Alto
2 Media Masculino Alquilada Soltero Cerca 63600 0 Alto
3 Joven Femenino Alquilada Soltero Cerca 13500 0 Bajo
4 Media Masculino Propia Casado Cerca 85600 1 Alto
5 Media Femenino Propia Soltero Cerca 68400 0 Alto
6 Joven Masculino Propia Casado Cerca 30400 0 Bajo
Catalogos Monto
1 6 755
2 6 1318
3 18 296
4 18 2436
5 12 1304
6 6 495
# Tabla de Frecuencia# -------------------ni<-table(DMark$Edad)fi<-prop.table(table(DMark$Edad))pi<-prop.table(table(DMark$Edad))*100edad.tabla<-t(rbind(ni,fi,pi))edad.tabla
ni fi pi
Joven 287 0.287 28.7
Media 508 0.508 50.8
Adulta 205 0.205 20.5
Visualicemos ahora la distribución de frecuencias obtenida usando gráficas adecuadas. Por ejemplo, podemos usar una gráfica de barra obtenida con las funciones básicas que nos brinda R:
barplot(pi, main="Distribución de las edades de los clientes", xlab="Grupo Etario", col =1,ylab="Porcentaje de Clientes")
Es recomendable usar la librería ggplot2 para obtener visualizaciones con mejor presentación:
ggplot(freq_table, aes(x = Edad, y = Frecuencia)) +geom_bar(stat ="identity", fill ="steelblue") +labs(title ="Distribución de frecuencia de cliente por grupo etario",x ="Grupo Etario", y ="Número de Clientes") +theme_bw()
También se puede usar una gráfica de barras agrupadas:
# Gráfico de Sectores Circulares# ------------------------------## Colocar porcentajeslbls1 <-paste(names(table(DMark$Edad)), "\n",prop.table(table(DMark$Edad))*100,"%", sep="")pie(pi, labels = lbls1,main="Distribución de la Edad de los Clientes")
Comentarios:
Del gráfico se desprende que el grupo de edad con mayor frecuencia de clientes es el de “Edad Media”, seguido del de “Jóvenes” y del de “Adulta”. Esta información podría ser útil para orientar las campañas de marketing hacia estos grupos de edad.
Analice la asociación entre el grupo etario del cliente y el historial del volumen de compra anterior.
Presentemos primero la tabla de contingencia:
tabla1=table(DMark$Edad,DMark$Historial)tabla1
Bajo Medio Alto
Joven 123 35 7
Media 69 127 167
Adulta 38 50 81
La tabla de contingencia muestra la distribución de frecuencias del grupo de edad del cliente y el historial de volumen de compras anteriores. Cada fila representa un grupo de edad diferente y cada columna representa un grupo diferente del historial de volumen de compras anteriores. Los números de las celdas representan la frecuencia de clientes de cada grupo de edad que entran en cada clase de historial de volumen de compra anterior. Esta información podría ser útil para comprender el comportamiento de compra de los clientes de diferentes grupos de edad y dirigir las campañas de marketing a clientes con patrones de compra específicos.
Para poder estudiar una posible asociación entre las variables en estudio es necesario obtener la distribución condicional del historial de compra dado el grupo etario.
tabla2=prop.table(tabla1,margin=1)tabla2
Bajo Medio Alto
Joven 0.74545455 0.21212121 0.04242424
Media 0.19008264 0.34986226 0.46005510
Adulta 0.22485207 0.29585799 0.47928994
A partir de esta distribución, podemos utilizar una gráfica de barras componentes para visualizar la información obtenida:
# Barras Componentespar(mar=c(5.1, 4.1, 4.1, 8.1), xpd=TRUE) #Adicionar espacio extrabarplot(t(tabla2),col=2:4,xlab="Grupo Etario",ylab="Proporción de Clientes",main="Distribución del historial de compra según grupo etario")legend("topright", inset=c(-0.27,0),legend=levels(DMark$Historial),col=2:4,pch=15,title="Historial de Compra")
#Usando ggplot2ggplot(data =na.omit(DMark), aes(x = Edad, y = ..count.., fill = Historial)) +geom_bar(position ="fill") +labs(y ="% de clientes", title ="Distribución del historial de compra según grupo etario") +theme_bw() +theme(legend.position ="bottom")
Otra gráfica interesante que permite estudiar la asociación y al mismo tiempo presentar la distribución marginal de la variable condicional es la gráfica de mosaico:
library(vcd)mosaicplot(~ Edad+Historial, data = DMark, color =2:4, main="Distribución del historial de compra según grupo etario")
Si bien es posible sospechar que existe asociación entre las variables estudiadas, es recomendable complementar el análisis con una medida estadística que cuantifique el grado de asociación entre las variables (y como estudiaremos más adelante realizar un prueba estadística de independencia \(\chi2\)).
#Coeficiente Tau-b de Kendalllibrary(DescTools)KendallTauB(tabla1)
[1] 0.3546042
Presente una tabla de distribución de frecuencias para el número de hijos. Construya una gráfica adecuada.
# Representación de Datos Cuantitativos Discretos # Tabla de Frecuenciasni<-table(DMark$Hijos)fi<-prop.table(table(DMark$Hijos))pi<-prop.table(table(DMark$Hijos))*100hijos.tabla<-t(rbind(ni,fi,pi))hijos.tabla
ni fi pi
0 462 0.462 46.2
1 267 0.267 26.7
2 146 0.146 14.6
3 125 0.125 12.5
# Visualización de la Distribución de la Variable# ------------------------------------------------#Gráfico de líneas verticalesplot(pi, type="h", lwd=2,xlab="Número de hijos",ylab="Porcentaje de clientes",main="Distribución del número de hijos por cliente")points(x =as.numeric(row.names(pi)),y =as.numeric(pi),pch=19,cex=1.5)
Presente la tabla de distribución de frecuencias para el gasto y represente visualmente la distribución para las frecuencias acumuladas y sin acumular. Interprete sus resultados.
# Representación de Datos Cuantitativos Continuos #------------------------------------------------------------------# Tabla de Frecuencias (usando la regla de Sturges)library(DescTools)Freq(DMark$Monto, breaks =nclass.Sturges(DMark$Monto), right =FALSE)
# Visualización de la Distribución de la Variable# ------------------------------------------------# Histograma y polígono de frecuenciah1<-hist(DMark$Monto,breaks ="Sturges",xlab="Monto",ylab="Número de clientes", main ="Histograma var. Monto")polygon.freq(h1,frequency=1,col="red")
# Polígono de Frecuencias (solo)h1<-hist(DMark$Monto,border=FALSE,col ="white")polygon.freq(h1,frequency=1,col="red")
# Usando ggplot2ggplot(data=DMark, aes(Monto)) +geom_histogram(aes(y =..count..),#col="blue", fill="black", alpha = .75) +geom_density(col=2) +labs(title="Monto de Crédito") +labs(x="Monto", y="# de clientes")+xlim(c(0, 6300))
#Histograma y Densidadhist(DMark$Monto,prob=TRUE)lines(density(DMark$Monto))
Edad Genero Vivienda Ecivil
Joven :287 Length:1000 Length:1000 Length:1000
Media :508 Class :character Class :character Class :character
Adulta:205 Mode :character Mode :character Mode :character
Ubicacion Salario Hijos Historial
Length:1000 Min. : 10100 Min. :0.000 Bajo :230
Class :character 1st Qu.: 29975 1st Qu.:0.000 Medio:212
Mode :character Median : 53700 Median :1.000 Alto :255
Mean : 56104 Mean :0.934 NA's :303
3rd Qu.: 77025 3rd Qu.:2.000
Max. :168800 Max. :3.000
Catalogos Monto
Min. : 6.00 Min. : 38.0
1st Qu.: 6.00 1st Qu.: 488.2
Median :12.00 Median : 962.0
Mean :14.68 Mean :1216.8
3rd Qu.:18.00 3rd Qu.:1688.5
Max. :24.00 Max. :6217.0
summary(DMark$Monto)
Min. 1st Qu. Median Mean 3rd Qu. Max.
38.0 488.2 962.0 1216.8 1688.5 6217.0
# Definir funciones con medidas estadísticas# Función para calcular CVCV <-function(x){ (sd(x)/mean(x))*100}# Función para calcular asimetria (Pearson)A3 <-function(x){3*(mean(x)-median(x))/sd(x)}# Función para calcular el rangorango <-function(x){diff(range(x))}# Función para calcular el rango intercuartílicoRIC <-function(x){quantile(x,probs =0.75,type =6)-quantile(x,probs =0.25,type =6)}me<-mean(DMark$Monto)med<-median(DMark$Monto)q1<-quantile(x = DMark$Monto,probs =0.25,type =6)q3<-quantile(x = DMark$Monto,probs =0.75,type =6)r<-rango(DMark$Monto)ric<-RIC(DMark$Monto)s<-sd(DMark$Monto)cv<-CV(DMark$Monto)as3<-A3(DMark$Monto)resumen<-as.matrix(rbind(me,med,q1,q3,r,ric,s,cv,as3))colnames(resumen)<-c("Valor")resumen
Valor
me 1216.770000
med 962.000000
q1 486.750000
q3 1689.500000
r 6179.000000
ric 1202.750000
s 961.068613
cv 78.985232
as3 0.795271
vars n mean sd median trimmed mad min max range skew kurtosis
X1 1 1000 1216.77 961.07 962 1085.41 827.29 38 6217 6179 1.46 2.94
se
X1 30.39
library(fBasics)basicStats(DMark$Monto)
X..DMark.Monto
nobs 1.000000e+03
NAs 0.000000e+00
Minimum 3.800000e+01
Maximum 6.217000e+03
1. Quartile 4.882500e+02
3. Quartile 1.688500e+03
Mean 1.216770e+03
Median 9.620000e+02
Sum 1.216770e+06
SE Mean 3.039166e+01
LCL Mean 1.157131e+03
UCL Mean 1.276409e+03
Variance 9.236529e+05
Stdev 9.610686e+02
Skewness 1.464872e+00
Kurtosis 2.941372e+00
skewness(DMark$Monto)
[1] 1.464872
attr(,"method")
[1] "moment"
kurtosis(DMark$Monto)
[1] 2.941372
attr(,"method")
[1] "excess"
Para la variable gasto, el valor de curtosis es de 2,941372. Se trata de un valor positivo muy alto, que indica que la distribución del gasto tiene mayor apuntalamiento y colas gruesas en comparación con la distribución normal. Esto significa que hay muchos valores atípicos de gasto elevado en los datos, que pueden sesgar la media y la desviación típica. Es importante tener esto en cuenta a la hora de interpretar los resultados de cualquier análisis que utilice el gasto como variable.
Para la variable gasto, el valor de asimetría es 1.464872, que es positivo, lo que indica que la distribución está sesgada a la derecha. Esto no es inusual en un contexto empresarial, ya que a menudo ocurre que unos pocos clientes que gastan mucho representan una gran proporción del gasto total. En este caso, es importante identificar y dirigirse a estos clientes que gastan mucho en campañas de marketing o programas de fidelización, ya que pueden tener un impacto significativo en los ingresos generales y la rentabilidad de la empresa.
Realice una análisis descriptivo comparativo completo para el gasto por estado civil.
# A tibble: 2 × 12
Ecivil Media Mediana Q1 Q3 Min Max Rango RIC S CV Asimetria
<chr> <dbl> <dbl> <dbl> <dbl> <int> <int> <int> <dbl> <dbl> <dbl> <dbl>
1 Casado 1672. 1515 865. 2246 93 6217 6124 1388. 1038. 62.1 0.454
2 Solte… 758. 576 322. 1011. 38 4182 4144 692. 592. 78.1 0.921
# Usando libreríaspsych::describeBy(x = DMark$Monto, group = DMark$Ecivil)
Descriptive statistics by group
group: Casado
vars n mean sd median trimmed mad min max range skew kurtosis
X1 1 502 1672.07 1037.68 1515 1570.4 1008.91 93 6217 6124 1.13 1.93
se
X1 46.31
------------------------------------------------------------
group: Soltero
vars n mean sd median trimmed mad min max range skew kurtosis
X1 1 498 757.81 592.2 576 672.3 471.47 38 4182 4144 1.64 3.82
se
X1 26.54
Construya un diagrama de cajas para el gasto por estado civil del cliente. Realice un análisis comparativo.
# Análisis comparativo usando visualización de datos# ---------------------------------------------------boxplot(DMark$Monto ~ DMark$Ecivil,xlab="Estado Civil",ylab="Gasto",main="Comparacion del gasto por estado civil")
De acuerdo con los diagramas de cajas, el gasto del cliente presenta muchos potenciales outliers. Un problema que tiene el diagrama de cajas para detectar outliers es que la regla utilizada funciona bien con distribuciones simétricas, pero cuando la distribución presentra una asimetría positiva suele detectar más outliers de lo que debería. Una alternativa de diagnóstico es usar un diagrama de cajas ajustado para distribuciones asimétricas propuesta por Hubert y Vandervieren (2018):
The default of 'doScale' is FALSE now for stability;
set options(mc_doScale_quiet=TRUE) to suppress this (once per session) message
par(mfrow=c(1,1))
Cómo se aprecia en la gráfica comparativa, la distribución presenta menos outliers que los que inicialmente aparentaba. Por otro lado, en caso de que para la construcción de algún modelo predictivo la presencia de outliers afectara la construcción del modelo, una alternativa es aplicar alguna transformación a la variable con la finalidad de minimizar el impacto de las observaciones inusuales. Se debe tener en cuenta que luego de realizar la transformación, la variable muy probablemente ya no podrá ser interpretada. A continuación un ejemplo de la aplicación de una transformación softmax (los datos se comprimen y se reescalan entre 0 y 1):
library(reshape)
Attaching package: 'reshape'
The following object is masked from 'package:lubridate':
stamp
The following object is masked from 'package:dplyr':
rename
The following objects are masked from 'package:tidyr':
expand, smiths
Si tuvieramos que determinar cuál es la principal variable asociadda con el historial del volumen de compra anterior, ¿qué pasos se pueden seguir?
Si tuviera que elegir una medida de tendencia central para representar el gasto que realiza un cliente. ¿Cuál elegiría? Justifique su respuesta e interprete el valor elegido.
En general:
¿Cómo se empieza a explorar un conjunto de datos?
¿Qué pasos se pueden seguir para analizar las posibles relaciones entre las características de interés?