Este informe presenta un análisis estadístico descriptivo de la base de clientes de una empresa. El objetivo es caracterizar el comportamiento de los clientes y la calidad de los datos para la construcción de un modelo predictivo que optimice la rentabilidad de una próxima campaña de marketing directo. Para lograrlo, se realizó un proceso riguroso de limpieza de datos, incluyendo la detección y tratamiento de duplicados, valores atípicos, e imputación de datos faltantes. La meta es diferenciar e interpretar los rasgos distintivos de los clientes que aceptaron la oferta del nuevo producto durante una campaña piloto. Los hallazgos se documentan con tablas, indicadores estadísticos (porcentajes, medidas de tendencia y dispersión) y gráficos que respaldan las interpretaciones, sirviendo como la base para una segmentación de clientes efectiva.
Describir con rigor estadístico las características de los clientes y la calidad de los datos, aplicando limpieza, tratamiento de valores atípicos e imputación de faltantes, para obtener resultados confiables que sustenten la toma de decisiones.
1) Identificar y eliminar registros duplicados, documentando el criterio utilizado y su impacto.
2) Detectar valores atípicos e inconsistencias por variable, decidir su tratamiento y comparar indicadores antes/después.
3) Cuantificar y visualizar los datos faltantes por variable, determinar el mecanismo (MCAR u otro) y aplicar imputación justificada.
El primer paso consiste en cargar la base de datos y examinar la dimensión, cantidad y nombre de las variables disponibles del dataset.
## [1] 2220 37
## [1] "Income" "Kidhome" "Teenhome"
## [4] "Recency" "MntWines" "MntFruits"
## [7] "MntMeatProducts" "MntFishProducts" "MntSweetProducts"
## [10] "MntGoldProds" "NumDealsPurchases" "NumWebPurchases"
## [13] "NumCatalogPurchases" "NumStorePurchases" "NumWebVisitsMonth"
## [16] "AcceptedCmp3" "AcceptedCmp4" "AcceptedCmp5"
## [19] "AcceptedCmp1" "AcceptedCmp2" "Complain"
## [22] "Response" "Age" "Customer_Days"
## [25] "marital_Divorced" "marital_Married" "marital_Single"
## [28] "marital_Together" "marital_Widow" "education_2n Cycle"
## [31] "education_Basic" "education_Graduation" "education_Master"
## [34] "education_PhD" "MntTotal" "MntRegularProds"
## [37] "AcceptedCmpOverall"
Una técnica clave para optimizar las estrategias de marketing es la segmentación, la cúal implica dividir la base de datos de clientes en grupos homogéneos, basándose en características comunes como comportamientos de compra, atributos demográficos y otras variables relevantes. Esta estrategia permite una comprensión más profunda de las necesidades de cada perfil de cliente y, por ende, una orientación más precisa y rentable de los mensajes de marketing.
El procesamiento de datos de la base de clientes comienza con una fase de preparación y exploración. Primero, se realiza una limpieza exhaustiva para asegurar la calidad de la información. Una vez limpios, los datos se someten a un análisis descriptivo inicial para obtener una visión general de la información.
| Variable_name | Description | Classification |
|---|---|---|
| Income | Customer’s yearly household income | Continuous quantitative |
| Kidhome | Number of small children in customer’s household | Discrete quantitative |
| Teenhome | Number of teenagers in customer’s household | Discrete quantitative |
| Recency | Number of days since the last purchase | Discrete quantitative |
| MntWines | Amount spent on wine products in the last 2 years | Continuous quantitative |
| MntFruits | Amount spent on fruit products in the last 2 years | Continuous quantitative |
| MntMeatProducts | Amount spent on meat products in the last 2 years | Continuous quantitative |
| MntFishProducts | Amount spent on fish products in the last 2 years | Continuous quantitative |
| MntSweetProducts | Amount spent on sweet products in the last 2 years | Continuous quantitative |
| MntGoldProds | Amount spent on gold products in the last 2 years | Continuous quantitative |
| NumDealsPurchases | Number of purchases made with discount | Discrete quantitative |
| NumWebPurchases | Number of purchases made through company’s website | Discrete quantitative |
| NumCatalogPurchases | Number of purchases made using catalog | Discrete quantitative |
| NumStorePurchases | Number of purchases made directly in stores | Discrete quantitative |
| NumWebVisitsMonth | Number of visits to company’s website in the last month | Discrete quantitative |
| AcceptedCmp3 | 1 if customer accepted the offer in the 3rd campaign, 0 otherwise | Binary nominal qualitative |
| AcceptedCmp4 | 1 if customer accepted the offer in the 4th campaign, 0 otherwise | Binary nominal qualitative |
| AcceptedCmp5 | 1 if customer accepted the offer in the 5th campaign, 0 otherwise | Binary nominal qualitative |
| AcceptedCmp1 | 1 if customer accepted the offer in the 1st campaign, 0 otherwise | Binary nominal qualitative |
| AcceptedCmp2 | 1 if customer accepted the offer in the 2nd campaign, 0 otherwise | Binary nominal qualitative |
| Complain | 1 if customer complained in the last 2 years | Binary nominal qualitative |
| Response | 1 if customer accepted the offer in the last campaign, 0 otherwise | Binary nominal qualitative |
| Age | Age of customer | Discrete quantitative |
| Customer_Days | Number of days since registration as a customer | Discrete quantitative |
| marital_Divorced | 1 if customer is divorced, 0 otherwise | Binary nominal qualitative |
| marital_Married | 1 if customer is married, 0 otherwise | Binary nominal qualitative |
| marital_Single | 1 if customer is single, 0 otherwise | Binary nominal qualitative |
| marital_Together | 1 if customer is in relationship, 0 otherwise | Binary nominal qualitative |
| marital_Widow | 1 if customer is a widow/widower, 0 otherwise | Binary nominal qualitative |
| education_2n Cycle | Customer has secondary education | Binary nominal qualitative |
| education_Basic | Customer has basic education | Binary nominal qualitative |
| education_Graduation | Customer has a bachelor degree | Binary nominal qualitative |
| education_Master | Customer has a masters degree | Binary nominal qualitative |
| education_PhD | Customer has a PhD | Binary nominal qualitative |
| MntTotal | Total amount spent on all the products | Continuous quantitative |
| MntRegularProds | Total amount spent on regular products | Continuous quantitative |
| AcceptedCmpOverall | Overall number of accepted campaigns | Discrete quantitative |
La Tabla 1 presenta las 37 variables originales del dataset, acompañadas de su descripción y tipo de clasificación.
Se observa que algunas variables binarias representan categorías mutuamente excluyentes, como el estado civil o el nivel educativo. Para simplificar y mejorar la estructura del dataset, estas variables se agruparon en categorías únicas, reduciendo la dimensionalidad sin pérdida de información.
| Variable_name | Description | Classification |
|---|---|---|
| Income | Customer’s yearly household income | Continuous quantitative |
| Kidhome | Number of small children in customer’s household | Discrete quantitative |
| Teenhome | Number of teenagers in customer’s household | Discrete quantitative |
| Recency | Number of days since the last purchase | Discrete quantitative |
| MntWines | Amount spent on wine products in the last 2 years | Continuous quantitative |
| MntFruits | Amount spent on fruit products in the last 2 years | Continuous quantitative |
| MntMeatProducts | Amount spent on meat products in the last 2 years | Continuous quantitative |
| MntFishProducts | Amount spent on fish products in the last 2 years | Continuous quantitative |
| MntSweetProducts | Amount spent on sweet products in the last 2 years | Continuous quantitative |
| MntGoldProds | Amount spent on gold products in the last 2 years | Continuous quantitative |
| NumDealsPurchases | Number of purchases made with discount | Discrete quantitative |
| NumWebPurchases | Number of purchases made through company’s website | Discrete quantitative |
| NumCatalogPurchases | Number of purchases made using catalog | Discrete quantitative |
| NumStorePurchases | Number of purchases made directly in stores | Discrete quantitative |
| NumWebVisitsMonth | Number of visits to company’s website in the last month | Discrete quantitative |
| AcceptedCmp3 | 1 if customer accepted the offer in the 3rd campaign, 0 otherwise | Binary nominal qualitative |
| AcceptedCmp4 | 1 if customer accepted the offer in the 4th campaign, 0 otherwise | Binary nominal qualitative |
| AcceptedCmp5 | 1 if customer accepted the offer in the 5th campaign, 0 otherwise | Binary nominal qualitative |
| AcceptedCmp1 | 1 if customer accepted the offer in the 1st campaign, 0 otherwise | Binary nominal qualitative |
| AcceptedCmp2 | 1 if customer accepted the offer in the 2nd campaign, 0 otherwise | Binary nominal qualitative |
| Complain | 1 if customer complained in the last 2 years | Binary nominal qualitative |
| Response | 1 if customer accepted the offer in the last campaign, 0 otherwise | Binary nominal qualitative |
| Age | Age of customer | Discrete quantitative |
| Customer_Days | Number of days since registration as a customer | Discrete quantitative |
| MntTotal | Total amount spent on all the products | Continuous quantitative |
| MntRegularProds | Total amount spent on regular products | Continuous quantitative |
| AcceptedCmpOverall | Overall number of accepted campaigns | Discrete quantitative |
| Education | Customer’s education level (e.g., Basic, Graduation, Master, PhD, Secondary) | Ordinal qualitative |
| Marital_Status | Customer’s marital status (e.g., Single, Married, Divorced, Widow, Together) | Nominal qualitative |
La Tabla 2 presenta las 29 variables actualizadas del dataset, acompañadas de su descripción y tipo de clasificación.
Luego de la agrupación, la base quedó conformada por 29 variables. En esta versión depurada, el estado civil y el nivel educativo se representan como variables categóricas únicas, lo que facilita el análisis e interpretación.
Ademas se identificaron y eliminaron registros duplicados con el fin de evitar sesgos en el análisis. La Tabla 3 muestra el conteo de registros repetidos encontrados antes de su depuración.
| Income | Kidhome | Teenhome | Recency | MntWines | MntFruits | MntMeatProducts | MntFishProducts | MntSweetProducts | MntGoldProds | NumDealsPurchases | NumWebPurchases | NumCatalogPurchases | NumStorePurchases | NumWebVisitsMonth | AcceptedCmp3 | AcceptedCmp4 | AcceptedCmp5 | AcceptedCmp1 | AcceptedCmp2 | Complain | Response | Age | Customer_Days | MntTotal | MntRegularProds | AcceptedCmpOverall | Education | Marital_Status | Frecuencia |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 867180 | 0 | 0 | 20 | 344 | 189 | 482 | 50 | 33 | 172 | 1 | 5 | 6 | 5 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 66 | 2687 | 1098 | 926 | 0 | bachelor degree | Married | 4 |
| 189290 | 0 | 0 | 15 | 32 | 0 | 8 | 23 | 4 | 18 | 1 | 1 | 0 | 4 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 30 | 2657 | 67 | 49 | 0 | bachelor degree | Married | 3 |
| 344210 | 1 | 0 | 81 | 3 | 3 | 7 | 6 | 2 | 9 | 1 | 1 | 0 | 2 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 46 | 2522 | 21 | 12 | 0 | bachelor degree | Married | 3 |
| 399220 | 1 | 0 | 30 | 29 | 12 | 59 | 19 | 1 | 36 | 2 | 3 | 0 | 4 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 37 | 2659 | 120 | 84 | 0 | bachelor degree | Married | 3 |
| 405900 | 1 | 1 | 30 | 154 | 0 | 50 | 6 | 11 | 37 | 5 | 3 | 4 | 3 | 6 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 51 | 2429 | 221 | 184 | 1 | bachelor degree | Widow/Widower | 3 |
| 638410 | 0 | 1 | 64 | 635 | 15 | 100 | 20 | 7 | 131 | 1 | 9 | 3 | 9 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 52 | 2593 | 777 | 646 | 0 | Masters degree | Divorced | 3 |
| 640140 | 2 | 1 | 56 | 406 | 0 | 30 | 0 | 0 | 8 | 7 | 8 | 2 | 5 | 7 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 74 | 2178 | 436 | 428 | 1 | PhD | In Relationship | 3 |
| 674450 | 0 | 1 | 63 | 757 | 80 | 217 | 29 | 80 | 11 | 5 | 9 | 6 | 12 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 46 | 2845 | 1163 | 1152 | 0 | bachelor degree | Married | 3 |
| 838440 | 0 | 0 | 57 | 901 | 31 | 345 | 75 | 31 | 191 | 1 | 4 | 4 | 11 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 68 | 2572 | 1383 | 1192 | 1 | bachelor degree | In Relationship | 3 |
| 109790 | 0 | 0 | 34 | 8 | 4 | 10 | 2 | 2 | 4 | 2 | 3 | 0 | 3 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 31 | 2197 | 26 | 22 | 0 | Masters degree | Divorced | 2 |
| 152870 | 1 | 0 | 60 | 1 | 2 | 8 | 4 | 3 | 13 | 2 | 1 | 1 | 2 | 7 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 41 | 2786 | 18 | 5 | 1 | bachelor degree | Divorced | 2 |
| 160050 | 1 | 0 | 69 | 1 | 3 | 2 | 20 | 30 | 47 | 3 | 2 | 1 | 2 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 40 | 2843 | 56 | 9 | 0 | Basic education | Married | 2 |
| 171440 | 1 | 1 | 96 | 18 | 2 | 19 | 0 | 2 | 6 | 5 | 3 | 0 | 4 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 60 | 2293 | 41 | 35 | 0 | Masters degree | In Relationship | 2 |
| 186900 | 0 | 0 | 77 | 6 | 1 | 7 | 23 | 4 | 19 | 1 | 1 | 1 | 2 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 61 | 2707 | 41 | 22 | 0 | bachelor degree | Married | 2 |
| 187010 | 1 | 1 | 95 | 12 | 4 | 2 | 10 | 6 | 10 | 4 | 2 | 0 | 4 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 56 | 2549 | 34 | 24 | 0 | bachelor degree | Single | 2 |
| 199860 | 1 | 0 | 74 | 3 | 6 | 5 | 0 | 2 | 6 | 1 | 0 | 0 | 3 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 35 | 2386 | 16 | 10 | 0 | bachelor degree | Married | 2 |
| 201300 | 0 | 0 | 99 | 0 | 6 | 3 | 7 | 6 | 12 | 1 | 1 | 0 | 3 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 46 | 2263 | 22 | 10 | 0 | Secondary education | Married | 2 |
| 201800 | 0 | 0 | 27 | 18 | 42 | 24 | 15 | 20 | 18 | 1 | 2 | 1 | 4 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 44 | 2653 | 119 | 101 | 0 | bachelor degree | Single | 2 |
| 204250 | 1 | 0 | 5 | 4 | 12 | 5 | 3 | 16 | 17 | 2 | 2 | 0 | 3 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 34 | 2767 | 40 | 23 | 0 | Basic education | Married | 2 |
| 205870 | 1 | 0 | 39 | 2 | 3 | 6 | 4 | 1 | 9 | 1 | 1 | 1 | 2 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 50 | 2208 | 16 | 7 | 0 | bachelor degree | Single | 2 |
| 219940 | 0 | 1 | 4 | 9 | 0 | 6 | 3 | 1 | 3 | 1 | 0 | 0 | 3 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 63 | 2711 | 19 | 16 | 0 | bachelor degree | In Relationship | 2 |
| 224190 | 0 | 0 | 74 | 30 | 3 | 47 | 19 | 21 | 42 | 1 | 3 | 2 | 2 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 57 | 2596 | 120 | 78 | 0 | bachelor degree | Married | 2 |
| 225740 | 2 | 1 | 28 | 25 | 0 | 8 | 2 | 0 | 2 | 2 | 2 | 0 | 3 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 53 | 2403 | 35 | 33 | 0 | bachelor degree | Married | 2 |
| 226340 | 0 | 0 | 47 | 2 | 23 | 11 | 8 | 6 | 46 | 1 | 2 | 1 | 2 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 54 | 2688 | 50 | 4 | 0 | Basic education | In Relationship | 2 |
| 228040 | 1 | 0 | 75 | 14 | 1 | 7 | 2 | 1 | 1 | 1 | 2 | 0 | 2 | 9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 49 | 2492 | 25 | 24 | 0 | bachelor degree | Single | 2 |
| 245940 | 1 | 0 | 94 | 1 | 3 | 6 | 10 | 0 | 9 | 1 | 1 | 0 | 3 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 41 | 2360 | 20 | 11 | 0 | Basic education | In Relationship | 2 |
| 248820 | 1 | 0 | 52 | 1 | 4 | 10 | 29 | 0 | 36 | 1 | 1 | 1 | 2 | 6 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 42 | 2817 | 44 | 8 | 1 | Basic education | In Relationship | 2 |
| 252930 | 1 | 0 | 51 | 15 | 0 | 11 | 0 | 2 | 9 | 1 | 1 | 1 | 2 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 51 | 2446 | 28 | 19 | 0 | bachelor degree | Married | 2 |
| 255090 | 1 | 0 | 15 | 40 | 3 | 30 | 10 | 7 | 11 | 3 | 3 | 0 | 3 | 9 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 46 | 2808 | 90 | 79 | 0 | PhD | Divorced | 2 |
| 260910 | 1 | 1 | 84 | 15 | 10 | 19 | 8 | 17 | 20 | 3 | 2 | 1 | 3 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 63 | 2283 | 69 | 49 | 0 | bachelor degree | In Relationship | 2 |
| 268160 | 0 | 0 | 50 | 5 | 1 | 6 | 3 | 4 | 3 | 1 | 0 | 0 | 3 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 34 | 2840 | 19 | 16 | 0 | bachelor degree | Single | 2 |
| 269070 | 1 | 1 | 10 | 9 | 1 | 7 | 0 | 3 | 2 | 2 | 1 | 0 | 3 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 44 | 2472 | 20 | 18 | 0 | Secondary education | In Relationship | 2 |
| 271000 | 1 | 0 | 64 | 12 | 0 | 13 | 2 | 0 | 10 | 1 | 1 | 0 | 3 | 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 37 | 2609 | 27 | 17 | 0 | Masters degree | Married | 2 |
| 282490 | 0 | 0 | 80 | 1 | 9 | 7 | 2 | 14 | 10 | 1 | 2 | 0 | 3 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 59 | 2173 | 33 | 23 | 0 | Basic education | Married | 2 |
| 286910 | 1 | 0 | 56 | 5 | 4 | 13 | 8 | 0 | 4 | 1 | 1 | 0 | 3 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 31 | 2519 | 30 | 26 | 0 | bachelor degree | Married | 2 |
| 296720 | 1 | 1 | 6 | 9 | 1 | 3 | 0 | 4 | 8 | 1 | 0 | 0 | 3 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 55 | 2633 | 17 | 9 | 0 | bachelor degree | In Relationship | 2 |
| 297600 | 1 | 0 | 87 | 64 | 4 | 68 | 7 | 5 | 17 | 4 | 3 | 1 | 4 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 35 | 2828 | 148 | 131 | 0 | bachelor degree | Single | 2 |
Nota: Durante la fase de exploración inicial de los datos, se identificaron valores negativos en la variable MntRegularProds, lo cual es lógicamente inconsistente. Estos errores se detectaron al generar un resumen estadístico del conjunto de datos.
## Income Kidhome Teenhome Recency
## Min. : 17300 Min. :0.0000 Min. :0.0000 Min. : 0.00
## 1st Qu.: 352460 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:24.00
## Median : 514120 Median :0.0000 Median :0.0000 Median :49.00
## Mean : 516809 Mean :0.4415 Mean :0.5076 Mean :48.91
## 3rd Qu.: 681480 3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.:74.00
## Max. :1137340 Max. :2.0000 Max. :2.0000 Max. :99.00
## NA's :68
## MntWines MntFruits MntMeatProducts MntFishProducts
## Min. : 0.0 Min. : 0.00 Min. : 0 Min. : 0.00
## 1st Qu.: 24.0 1st Qu.: 2.00 1st Qu.: 16 1st Qu.: 3.00
## Median : 174.0 Median : 8.00 Median : 68 Median : 12.00
## Mean : 301.5 Mean : 26.34 Mean : 166 Mean : 37.58
## 3rd Qu.: 499.0 3rd Qu.: 33.00 3rd Qu.: 230 3rd Qu.: 50.00
## Max. :1493.0 Max. :199.00 Max. :1725 Max. :259.00
## NA's :20
## MntSweetProducts MntGoldProds NumDealsPurchases NumWebPurchases
## Min. : 0.00 Min. : 0.00 Min. : 0.000 Min. : 0.000
## 1st Qu.: 1.00 1st Qu.: 9.00 1st Qu.: 1.000 1st Qu.: 2.000
## Median : 8.00 Median : 24.00 Median : 2.000 Median : 4.000
## Mean : 27.34 Mean : 43.88 Mean : 2.323 Mean : 4.114
## 3rd Qu.: 34.00 3rd Qu.: 56.00 3rd Qu.: 3.000 3rd Qu.: 6.000
## Max. :262.00 Max. :321.00 Max. :15.000 Max. :27.000
##
## NumCatalogPurchases NumStorePurchases NumWebVisitsMonth AcceptedCmp3
## Min. : 0.000 Min. : 0.000 Min. : 0.00 Min. :0.00000
## 1st Qu.: 0.000 1st Qu.: 3.000 1st Qu.: 3.00 1st Qu.:0.00000
## Median : 2.000 Median : 5.000 Median : 6.00 Median :0.00000
## Mean : 2.646 Mean : 5.805 Mean : 5.34 Mean :0.07398
## 3rd Qu.: 4.000 3rd Qu.: 8.000 3rd Qu.: 7.00 3rd Qu.:0.00000
## Max. :28.000 Max. :13.000 Max. :20.00 Max. :1.00000
##
## AcceptedCmp4 AcceptedCmp5 AcceptedCmp1 AcceptedCmp2
## Min. :0.00000 Min. :0.00000 Min. :0.00000 Min. :0.00000
## 1st Qu.:0.00000 1st Qu.:0.00000 1st Qu.:0.00000 1st Qu.:0.00000
## Median :0.00000 Median :0.00000 Median :0.00000 Median :0.00000
## Mean :0.07741 Mean :0.07349 Mean :0.06565 Mean :0.01323
## 3rd Qu.:0.00000 3rd Qu.:0.00000 3rd Qu.:0.00000 3rd Qu.:0.00000
## Max. :1.00000 Max. :1.00000 Max. :1.00000 Max. :1.00000
##
## Complain Response Age Customer_Days
## Min. :0.000000 Min. :0.0000 Min. : 25.00 Min. :2159
## 1st Qu.:0.000000 1st Qu.:0.0000 1st Qu.: 43.00 1st Qu.:2337
## Median :0.000000 Median :0.0000 Median : 50.00 Median :2510
## Mean :0.009309 Mean :0.1538 Mean : 51.35 Mean :2511
## 3rd Qu.:0.000000 3rd Qu.:0.0000 3rd Qu.: 61.00 3rd Qu.:2688
## Max. :1.000000 Max. :1.0000 Max. :240.00 Max. :2858
##
## MntTotal MntRegularProds AcceptedCmpOverall Education
## Min. : 4.0 Min. :-283.0 Min. :0.0000 Length:2041
## 1st Qu.: 55.0 1st Qu.: 42.0 1st Qu.:0.0000 Class :character
## Median : 343.0 Median : 288.0 Median :0.0000 Mode :character
## Mean : 564.5 Mean : 520.6 Mean :0.3038
## 3rd Qu.: 965.0 3rd Qu.: 886.0 3rd Qu.:0.0000
## Max. :2491.0 Max. :2458.0 Max. :4.0000
##
## Marital_Status
## Length:2041
## Class :character
## Mode :character
##
##
##
##
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.0 42.0 289.5 521.7 886.8 2458.0
Para asegurar la integridad del análisis, se procedió a la eliminación de dichos registros en la variable MntRegularProds, como una medida necesaria para garantizar la calidad y precisión del conjunto de datos, lo cual es fundamental para cualquier análisis estadístico robusto y la construcción de modelos confiables.
Para detectar valores atípicos se generaron resúmenes estadísticos
(tabla4)y gráficos de caja (boxplots)
de cada variable continua.
En estos gráficos, los valores atípicos aparecen resaltados en color
rojo.
| Variable | media | mediana | sd | min | Q1 | Q3 | max | IQR |
|---|---|---|---|---|---|---|---|---|
| Income | 5.175041e+05 | 514985.0 | 2.067427e+05 | 17300 | 353520.00 | 682425.00 | 1137340 | 328905.00 |
| Kidhome | 4.421001e-01 | 0.0 | 5.357462e-01 | 0 | 0.00 | 1.00 | 2 | 1.00 |
| Teenhome | 5.068695e-01 | 0.0 | 5.460636e-01 | 0 | 0.00 | 1.00 | 2 | 1.00 |
| Recency | 4.893768e+01 | 49.0 | 2.891136e+01 | 0 | 24.00 | 74.00 | 99 | 50.00 |
| MntWines | 3.018855e+02 | 174.5 | 3.329801e+02 | 0 | 24.00 | 501.25 | 1493 | 477.25 |
| MntFruits | 2.636997e+01 | 8.0 | 3.982598e+01 | 0 | 2.00 | 33.00 | 199 | 31.00 |
| MntMeatProducts | 1.662031e+02 | 68.0 | 2.198610e+02 | 0 | 16.00 | 230.00 | 1725 | 214.00 |
| MntFishProducts | 3.763003e+01 | 12.0 | 5.483636e+01 | 0 | 3.00 | 50.00 | 259 | 47.00 |
| MntSweetProducts | 2.737586e+01 | 8.0 | 4.165516e+01 | 0 | 1.00 | 34.00 | 262 | 33.00 |
| MntGoldProds | 4.352012e+01 | 24.0 | 5.089635e+01 | 0 | 9.00 | 56.00 | 249 | 47.00 |
| NumDealsPurchases | 2.326300e+00 | 2.0 | 1.887094e+00 | 0 | 1.00 | 3.00 | 15 | 2.00 |
| NumWebPurchases | 4.096173e+00 | 4.0 | 2.681520e+00 | 0 | 2.00 | 6.00 | 27 | 4.00 |
| NumCatalogPurchases | 2.649166e+00 | 2.0 | 2.797551e+00 | 0 | 0.00 | 4.00 | 28 | 4.00 |
| NumStorePurchases | 5.812071e+00 | 5.0 | 3.227355e+00 | 0 | 3.00 | 8.00 | 13 | 5.00 |
| NumWebVisitsMonth | 5.338567e+00 | 6.0 | 2.409724e+00 | 0 | 3.00 | 7.00 | 20 | 4.00 |
| Age | 5.136016e+01 | 50.0 | 1.305093e+01 | 25 | 43.00 | 61.00 | 240 | 18.00 |
| Customer_Days | 2.511545e+03 | 2511.0 | 2.026835e+02 | 2159 | 2336.25 | 2688.00 | 2858 | 351.75 |
| MntTotal | 5.651747e+02 | 344.5 | 5.779776e+02 | 4 | 55.00 | 966.50 | 2491 | 911.50 |
| MntRegularProds | 5.216546e+02 | 289.5 | 5.555954e+02 | 0 | 42.00 | 886.75 | 2458 | 844.75 |
| AcceptedCmpOverall | 3.042198e-01 | 0.0 | 6.834116e-01 | 0 | 0.00 | 0.00 | 4 | 0.00 |
La tabla revela que la base de datos no sigue una distribución normal y está fuertemente influenciada por valores extremos. Esta asimetría y la presencia de valores atípicos significan que un proceso de limpieza de datos es esencial antes de construir cualquier modelo. Las medidas de tendencia central como la mediana y el rango intercuartílico (IQR) son más representativas del comportamiento típico del cliente que la media y el rango total.
Graficos para mejorar el analisis de los datos atipicos
El análisis evidenció que 9 variables presentan datos atípicos. Para cuantificar este fenómeno, se construyó la Tabla 5, en la cual se detalla la cantidad de outliers identificados en cada variable.
| Variable | Outliers | Total_Outliers | |
|---|---|---|---|
| Income | Income | NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA | 68 |
| Kidhome | Kidhome | 0 | |
| Teenhome | Teenhome | 0 | |
| Recency | Recency | 0 | |
| MntWines | MntWines | NA, NA, 1332, 1349, NA, NA, 1218, 1241, NA, 1285, 1248, 1239, 1396, 1288, 1379, NA, 1478, 1492, NA, NA, NA, NA, 1308, NA, NA, 1253, 1394, 1296, 1285, 1230, 1315, 1224, NA, NA, 1298, NA, NA, NA, NA, 1449, 1259, NA, NA, 1252, 1459, 1493, 1218, 1324, 1285, 1462, 1276, 1245, 1486, 1311 | 54 |
| MntFruits | MntFruits | 88, 80, 100, 164, 120, 107, 111, 105, 172, 81, 106, 194, 115, 99, 90, 133, 106, 162, 189, 138, 86, 114, 153, 134, 148, 84, 162, 129, 98, 183, 129, 147, 153, 104, 80, 91, 163, 134, 152, 105, 114, 137, 190, 96, 162, 138, 83, 92, 134, 155, 151, 85, 129, 153, 129, 183, 127, 91, 107, 103, 89, 105, 181, 80, 112, 159, 81, 134, 102, 86, 123, 81, 166, 142, 133, 80, 178, 93, 107, 97, 115, 168, 91, 148, 174, 122, 123, 91, 199, 138, 101, 92, 99, 111, 80, 86, 98, 85, 107, 137, 138, 168, 93, 114, 80, 98, 172, 81, 96, 83, 117, 114, 178, 108, 130, 80, 161, 138, 124, 126, 105, 80, 80, 83, 120, 142, 104, 83, 106, 81, 185, 147, 112, 162, 86, 108, 161, 129, 93, 172, 87, 168, 151, 102, 84, 97, 127, 89, 172, 161, 104, 197, 111, 98, 194, 82, 184, 88, 99, 120, 160, 107, 108, 185, 115, 133, 140, 107, 102, 117, 131, 91, 126, 129, 147, 97, 132, 86, 120, 138, 169, 84, 92, 169, 142, 172, 114, 107, 100, 153, 86, 183, 193, 137, 108, 83, 193, 105, 149, 80, 151, 143, 80, 122, 112, 82, 90, 154, 89, 161, 159, 178, 120, 102, 132, 144, 155, 142, 80, 124, 129, 194 | 222 |
| MntMeatProducts | MntMeatProducts | 1725, 801, 780, 925, 779, 568, 690, 812, 951, 590, 921, 756, 813, 553, 554, 740, 757, 768, 565, 573, 561, 570, 832, 785, 818, 815, 786, 591, 716, 792, 974, 594, 613, 670, 925, 761, 940, 797, 635, 592, 572, 732, 713, 653, 758, 711, 838, 559, 597, 706, 617, 742, 689, 898, 706, 597, 747, 804, 774, 929, 845, 569, 685, 873, 674, 890, 704, 606, 790, 925, 651, 708, 640, 733, 961, 568, 780, 678, 555, 842, 843, 711, 818, 864, 750, 731, 604, 915, 689, 913, 946, 672, 611, 687, 842, 622, 717, 573, 984, 694, 595, 672, 553, 573, 601, 731, 553, 687, 815, 706, 724, 827, 560, 701, 915, 639, 573, 625, 649, 575, 599, 768, 673, 850, 835, 936, 935, 853, 558, 751, 693, 629, 981, 586, 565, 697, 736, 602, 590, 899, 816, 603, 754, 835, 612, 753, 654, 567, 653, 951, 815, 553, 797, 592, 746, 932, 735, 650, 607, 968, 883, 849, 614, 818, 689, 749, 655, 845, 860, 631 | 170 |
| MntFishProducts | MntFishProducts | 172, 225, 150, 160, 227, 156, 180, 121, 201, 189, 137, 185, 151, 123, 173, 149, 134, 173, 140, 147, 224, 254, 180, 186, 218, 133, 150, 220, 205, 162, 188, 150, 166, 216, 219, 151, 172, 212, 129, 151, 137, 156, 179, 179, 149, 197, 220, 199, 169, 240, 146, 224, 127, 136, 168, 132, 147, 231, 202, 125, 175, 179, 133, 121, 172, 164, 177, 138, 138, 175, 247, 127, 150, 227, 159, 153, 123, 134, 202, 234, 210, 168, 160, 194, 250, 138, 146, 220, 237, 250, 145, 167, 160, 150, 168, 192, 180, 137, 130, 232, 132, 125, 168, 145, 184, 134, 240, 186, 125, 219, 237, 123, 138, 158, 216, 259, 168, 219, 151, 145, 133, 137, 207, 210, 172, 182, 141, 182, 124, 171, 193, 160, 130, 242, 175, 180, 246, 188, 197, 210, 197, 219, 149, 149, 185, 142, 140, 253, 169, 258, 134, 123, 258, 179, 207, 198, 153, 168, 138, 223, 151, 188, 145, 224, 150, 216, 160, 159, 150, 181, 177, 184, 158, 129, 130, 151, 205, 173, 128, 123, 153, 145, 179, 208, 180, 208, 201, 210, 121, 212, 250, 136, 199, 229, 133, 192, 193, 224, 130, 199, 145, 202, 182, 149 | 204 |
| MntSweetProducts | MntSweetProducts | 88, 112, 178, 167, 120, 120, 122, 105, 133, 132, 98, 103, 89, 91, 89, 113, 173, 87, 176, 102, 87, 138, 163, 124, 172, 84, 149, 92, 130, 114, 141, 147, 97, 118, 153, 189, 107, 128, 163, 133, 134, 91, 150, 137, 91, 103, 172, 95, 156, 194, 96, 191, 192, 129, 108, 107, 123, 185, 134, 121, 163, 127, 125, 198, 115, 98, 106, 101, 110, 134, 102, 160, 138, 122, 166, 136, 106, 116, 133, 120, 182, 91, 148, 161, 161, 157, 153, 123, 133, 143, 92, 169, 103, 149, 86, 146, 123, 137, 92, 91, 178, 152, 112, 115, 133, 116, 138, 92, 95, 161, 93, 160, 115, 112, 137, 172, 151, 99, 144, 151, 122, 147, 115, 195, 91, 189, 98, 175, 145, 162, 105, 96, 187, 126, 97, 108, 143, 147, 105, 160, 114, 194, 148, 85, 98, 89, 109, 151, 152, 137, 197, 125, 176, 165, 97, 121, 144, 174, 151, 112, 112, 163, 196, 107, 102, 107, 97, 88, 95, 174, 107, 118, 118, 92, 126, 107, 89, 150, 86, 169, 138, 139, 188, 142, 107, 88, 105, 94, 165, 143, 138, 95, 262, 185, 108, 84, 91, 141, 85, 179, 86, 94, 143, 100, 101, 93, 194, 129, 101, 102, 98, 151, 192, 89, 102, 192, 93, 92, 111, 133, 125, 118, 118 | 223 |
| MntGoldProds | MntGoldProds | 176, 174, 241, 190, 169, 145, 223, 168, 172, 216, 130, 141, 172, 192, 182, 181, 152, 172, 148, 241, 146, 162, 131, 135, 203, 139, 173, 218, 142, 233, 157, 159, 172, 191, 134, 130, 153, 175, 224, 165, 190, 163, 144, 147, 207, 146, 151, 141, 154, 242, 191, 147, 174, 155, 249, 151, 183, 170, 191, 152, 227, 205, 134, 198, 139, 177, 133, 145, 141, 187, 171, 130, 205, 170, 142, 129, 175, 242, 135, 241, 174, 182, 166, 144, 172, 133, 139, 131, 195, 231, 182, 182, 158, 145, 218, 200, 187, 178, 200, 147, 149, 190, 133, 142, 168, 153, 134, 192, 132, 210, 241, 144, 210, 154, 138, 134, 176, 205, 168, 140, 246, 138, 130, 196, 144, 153, 197, 196, 133, 199, 215, 127, 134, 161, 180, 187, 195, 191, 149, 128, 183, 150, 153, 162, 232, 166, 192, 176, 183, 219, 203, 153, 133, 174, 137, 185, 224, 145, 160, 143, 204, 143, 232, 145, 149, 196, 245, 185, 154, 229, 163, 128, 153, 241, 129, 248, 129, 227, 163, 174, 152, 247, 247 | 183 |
| NumDealsPurchases | NumDealsPurchases | 15, 7, 9, 7, 7, 7, 8, 10, 9, 7, 13, 7, 9, 9, 15, 7, 7, 7, 7, 7, 7, 7, 8, 8, 7, 7, 7, 8, 8, 7, 7, 7, 15, 11, 8, 7, 7, 12, 10, 15, 10, 8, 7, 11, 8, 7, 7, 10, 7, 7, 13, 9, 12, 7, 11, 7, 7, 9, 8, 9, 13, 8, 11, 15, 11, 8, 7, 8, 10, 8, 7, 7, 7, 8 | 74 |
| NumWebPurchases | NumWebPurchases | 27 | 1 |
| NumCatalogPurchases | NumCatalogPurchases | 28, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11 | 19 |
| NumStorePurchases | NumStorePurchases | 0 | |
| NumWebVisitsMonth | NumWebVisitsMonth | 20, 20, 14, 19, 20, 14, 19 | 7 |
| Age | Age | 240, 240 | 2 |
| Customer_Days | Customer_Days | 0 | |
| MntTotal | MntTotal | 2429, 2491, 2429 | 3 |
| MntRegularProds | MntRegularProds | 2333, 2259, 2458, 2333 | 4 |
| AcceptedCmpOverall | AcceptedCmpOverall | 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 3, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 1, 2, 1, 1, 1, 3, 4, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 2, 2, 1, 3, 2, 4, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 4, 3, 1, 3, 1, 2, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 3, 1, 2, 1, 2, 1, 3, 2, 1, 2, 1, 2, 1, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 3, 2, 1, 2, 1, 1, 2, 3, 4, 1, 1, 1, 2, 2, 2, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 4, 1, 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 3, 1, 1, 1, 2, 4, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 3, 1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 2, 1, 1, 2, 1, 1, 4, 3, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 2, 2, 1, 3, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1, 1, 2, 2, 4, 1, 3, 1, 1, 3, 1, 2, 1, 1, 1, 2, 1, 1, 2, 3, 1, 1, 1, 3, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 3, 1, 1, 1, 2, 1, 1, 1, 1, 4, 3, 1, 3, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1 | 431 |
Posteriormente, se utilizaron histogramas para observar el comportamiento de la distribución de estas variables. En dichos gráficos se incluyen los cuartiles y los límites de detección de outliers (1.5 * IQR) representados con líneas punteadas, lo que permite un análisis más detallado de los extremos de la distribución.
Tras identificar la distribución y comportamiento de las variables, se aplicaron técnicas de depuración a aquellas que presentaban valores atípicos anómalos o inconsistentes. En particular:
Age y NumWebPurchases mostraron valores claramente fuera de rango, probablemente producto de errores de digitación o registros poco plausibles.
NumCatalogPurchases y NumWebVisitsMonth presentaron saltos abruptos en la secuencia de valores, lo que afectaba la homogeneidad de la distribución.
Para estas variables se implementaron dos estrategias de tratamiento de outliers:
Se utilizó el método basado en el rango intercuartílico (IQR), definiendo como atípicos aquellos valores que caían por debajo de Q1 – 1.5·IQR o por encima de Q3 + 1.5·IQR.
Los registros que incumplían este criterio fueron descartados.
La comparación mediante diagramas de caja (boxplots) evidenció una reducción de la dispersión extrema, manteniendo la forma general de la distribución pero eliminando los casos irregulares.
Las gráficas de comparación lado a lado (antes y después) para cada variable evidenciaron que:
En Age se eliminaron valores fuera de rango que distorsionaban la representación central de la población.
En NumWebPurchases desaparecieron registros atípicos que generaban colas largas en la distribución.
Para estas variables no se eliminaron registros completos, sino que se ajustaron los valores extremos al límite superior o inferior permitido por el criterio IQR.
Esto permitió mantener la cantidad total de observaciones, evitando pérdida de información, pero suavizando el efecto de valores extremos.
Los boxplots comparativos antes y después del ajuste mostraron una mayor simetría y una reducción notable en los saltos abruptos de la distribución.
Las gráficas de comparación lado a lado (antes y después) para cada variable evidenciaron que:
En NumCatalogPurchases y NumWebVisitsMonth, el recorte permitió conservar las tendencias originales, pero reduciendo el impacto de valores desproporcionados.
Posteriormente, se recalcularon las medidas estadísticas para las variables numéricas (exceptuando las binarias). La nueva tabla resume las métricas de tendencia central (media, mediana), dispersión (desviación estándar, IQR), y valores extremos (mínimo, máximo).
| Variable | media | mediana | sd | min | Q1 | Q3 | max | IQR |
|---|---|---|---|---|---|---|---|---|
| Income | 5.176037e+05 | 515180 | 2.060142e+05 | 17300 | 354145 | 682110 | 1054710 | 327965 |
| Kidhome | 4.427518e-01 | 0 | 5.358718e-01 | 0 | 0 | 1 | 2 | 1 |
| Teenhome | 5.076167e-01 | 0 | 5.461188e-01 | 0 | 0 | 1 | 2 | 1 |
| Recency | 4.895381e+01 | 49 | 2.890509e+01 | 0 | 24 | 74 | 99 | 50 |
| MntWines | 3.023305e+02 | 176 | 3.330280e+02 | 0 | 24 | 502 | 1493 | 478 |
| MntFruits | 2.639902e+01 | 8 | 3.984694e+01 | 0 | 2 | 33 | 199 | 31 |
| MntMeatProducts | 1.664388e+02 | 68 | 2.199372e+02 | 0 | 16 | 230 | 1725 | 214 |
| MntFishProducts | 3.767617e+01 | 12 | 5.486309e+01 | 0 | 3 | 50 | 259 | 47 |
| MntSweetProducts | 2.727518e+01 | 8 | 4.135615e+01 | 0 | 1 | 34 | 198 | 33 |
| MntGoldProds | 4.355430e+01 | 24 | 5.091964e+01 | 0 | 9 | 56 | 249 | 47 |
| NumDealsPurchases | 2.327764e+00 | 2 | 1.887492e+00 | 0 | 1 | 3 | 15 | 2 |
| NumWebPurchases | 4.086978e+00 | 4 | 2.633982e+00 | 0 | 2 | 6 | 11 | 4 |
| NumCatalogPurchases | 2.634889e+00 | 2 | 2.720486e+00 | 0 | 0 | 4 | 10 | 4 |
| NumStorePurchases | 5.818182e+00 | 5 | 3.225446e+00 | 0 | 3 | 8 | 13 | 5 |
| NumWebVisitsMonth | 5.321867e+00 | 6 | 2.329556e+00 | 0 | 3 | 7 | 13 | 4 |
| Age | 5.116315e+01 | 50 | 1.163075e+01 | 25 | 43 | 61 | 80 | 18 |
| Customer_Days | 2.511690e+03 | 2511 | 2.025768e+02 | 2159 | 2337 | 2688 | 2858 | 351 |
| MntTotal | 5.658339e+02 | 345 | 5.781319e+02 | 4 | 55 | 968 | 2491 | 913 |
| MntRegularProds | 5.222796e+02 | 290 | 5.557461e+02 | 0 | 42 | 887 | 2458 | 845 |
| AcceptedCmpOverall | 3.041769e-01 | 0 | 6.836748e-01 | 0 | 0 | 0 | 4 | 0 |
Interpretación de los cambios:
La media y el máximo de las variables tratadas disminuyeron de forma significativa, lo cual confirma que los outliers inflaban artificialmente estas medidas.
La mediana y los cuartiles se mantuvieron más estables, lo que sugiere que la estructura central de los datos no se vio afectada.
El IQR se redujo, evidenciando un rango intercuartílico más representativo del comportamiento real de los clientes.
Se procedió a identificar la presencia de valores faltantes en el conjunto de datos ya depurado de outliers. Para ello, se calcularon tanto el número de observaciones ausentes por variable como el porcentaje respecto al total de registros.
El análisis gráfico mediante un barchart del porcentaje de datos faltantes por variable permitió visualizar cuáles variables eran más problemáticas, mientras que el mapa de calor (heatmap) mostró la distribución de los valores ausentes a lo largo del dataset. Estas visualizaciones confirmaron que la proporción de faltantes era baja y no se concentraba en una sola variable crítica.
Para entender el mecanismo detrás de los valores faltantes, se aplicó el test MCAR de Little. Este procedimiento evalúa si los datos son Missing Completely At Random (MCAR), es decir, si las ausencias no dependen de otras variables ni de los valores en sí mismos.
Previo a la prueba, se realizó una depuración de las variables numéricas para evitar redundancia (eliminando columnas con varianza cero, de baja variabilidad y con correlación alta). De esta manera se garantizó la robustez del test.
## # A tibble: 1 × 4
## statistic df p.value missing.patterns
## <dbl> <dbl> <dbl> <int>
## 1 137. 46 6.43e-11 3
El test de Little reveló un valor p extremadamente bajo (p<0.001), lo que nos lleva a rechazar la hipótesis nula de que los datos faltantes son completamente aleatorios (MCAR). Este resultado sugiere que la ausencia de datos no es fortuita, sino que está potencialmente relacionada con otras variables. A pesar de esto, se optó por una imputación simple debido al bajo porcentaje de valores ausentes, lo cual no compromete la representatividad de la base de datos. Esta decisión se justifica porque, en un análisis principalmente descriptivo y exploratorio, los beneficios de una imputación más compleja no compensarían su alto costo computacional y metodológico. Para un análisis predictivo más riguroso, se recomendarían métodos de imputación avanzados que tengan en cuenta la estructura de los datos..
Dado que la proporción de datos ausentes fue de aproximadamente 4%, se optó por una estrategia de imputación simple, evitando la eliminación de registros para no reducir el tamaño de la muestra.
Para las variables numéricas, los valores faltantes se imputaron con la mediana, lo que permite reducir la influencia de valores extremos y mantener la representatividad de la tendencia central.
Para las variables categóricas, se utilizó la moda, asegurando que el valor más frecuente sustituyera las ausencias.
La verificación posterior a la imputación, a través de un gráfico de valores faltantes, confirmó que el dataset quedó completo y libre de valores NA, garantizando mayor consistencia para los análisis posteriores.
Para identificar y comprender relaciones de fuerza entre variables numéricas, se genera una matriz de correlación. Además, es crucial para detectar multicolinealidad, un problema común en el modelado predictivo, donde variables predictoras están fuertemente correlacionadas entre sí, lo que puede inestabilizar el modelo.
La matriz de correlación muestra la relación lineal entre las variables numéricas del conjunto de datos. En el gráfico de calor se observan tonalidades más intensas en algunos pares de variables, lo que indica correlaciones fuertes. Por ejemplo, el monto total de gasto (MntTotal) presenta una correlación positiva considerable con los ingresos (Income), lo cual es esperable, ya que a mayor ingreso los clientes tienden a gastar más. Otras correlaciones aparecen débiles o casi nulas, lo que evidencia independencia entre varias de las variables numéricas.
Ingresos vs Monto total (Income ~ MntTotal): El gráfico de dispersión revela una relación positiva clara. La línea de tendencia ajustada por regresión lineal confirma que a medida que aumentan los ingresos, también crece el gasto total. Sin embargo, se observa cierta dispersión en niveles altos de ingreso, lo que indica que no todos los clientes con altos ingresos necesariamente gastan proporcionalmente más.
Número de visitas web vs Ingreso (NumWebVisitsMonth ~ Income): En este caso, el gráfico no refleja una relación lineal fuerte. Aunque la recta ajustada muestra una leve tendencia, los puntos se distribuyen de manera dispersa, lo que sugiere que el número de visitas web mensuales no depende directamente del nivel de ingresos.
Edad vs Ingreso (Age ~ Income): El gráfico de densidad 2D muestra áreas con mayor concentración de observaciones. Se evidencia que los ingresos se concentran más en un rango intermedio de edad, mientras que en edades extremas (muy jóvenes o muy mayores) la dispersión es mayor. Esto indica un patrón de ingresos asociado a la edad, aunque no estrictamente lineal.
## Df Sum Sq Mean Sq F value Pr(>F)
## factor(Education) 4 5.458e+12 1.364e+12 35.52 <2e-16 ***
## Residuals 2030 7.798e+13 3.842e+10
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Ingresos según nivel educativo (Income ~ Education): El boxplot indica que existen diferencias en los ingresos entre los distintos niveles de educación. En particular, los niveles más altos de formación presentan medianas más elevadas en comparación con los niveles básicos. El análisis de varianza (ANOVA) confirma que estas diferencias son estadísticamente significativas, lo que sugiere que la educación influye en el nivel de ingresos de las personas.
## Df Sum Sq Mean Sq F value Pr(>F)
## factor(Education) 4 147 36.76 6.851 1.78e-05 ***
## Residuals 2030 10891 5.37
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Número de visitas web mensuales según nivel educativo (NumWebVisitsMonth ~ Education): El boxplot muestra variabilidad en el número de visitas según la educación, aunque las diferencias no son tan claras como en el caso de los ingresos. La prueba ANOVA respalda este resultado, indicando diferencias leves o menos consistentes. Esto sugiere que la educación podría estar más relacionada con los ingresos que con el comportamiento de visitas en la web.
Los gráficos confirman que las variables de ingreso y gasto total están fuertemente correlacionadas, un hallazgo esperado y fundamental para el modelo predictivo. La matriz de correlación visualiza esta relación, y el gráfico de dispersión de Income vs. MntTotal la detalla, mostrando una tendencia positiva que valida la premisa de que clientes con mayores ingresos tienden a gastar más. No obstante, la dispersión en los puntos de datos indica que el modelo no puede depender únicamente de esta relación; otros factores también influyen en el gasto, lo que subraya la necesidad de un enfoque multivariado.
Por otro lado, los análisis de NumWebVisitsMonth vs. Income y Age vs. Income demuestran la complejidad del comportamiento del cliente. El número de visitas a la web no tiene una relación lineal clara con los ingresos, lo que sugiere que este comportamiento de navegación está impulsado por otros factores no relacionados con la capacidad de gasto. De igual manera, aunque existe una concentración de ingresos en edades intermedias, la relación no es estrictamente lineal, lo que indica que la edad por sí sola no es un predictor perfecto de los ingresos.
Finalmente, los boxplots y las pruebas ANOVA ofrecen una visión crucial de las variables categóricas. La educación tiene un impacto estadísticamente significativo en los ingresos, con niveles de formación más altos asociados a mayores ganancias. Este es un hallazgo clave para la segmentación. Sin embargo, este mismo análisis muestra que el nivel educativo tiene una relación mucho más débil con el número de visitas a la web, lo que refuerza la idea de que la navegación en línea no está tan fuertemente ligada a factores demográficos como los ingresos.
Los análisis gráficos y estadísticos revelan patrones claros que validan varias hipótesis iniciales y descartan otras, sirviendo como una base sólida para la construcción del modelo predictivo y la segmentación de clientes. 1. Validación de premisas clave: Existe una relación positiva y significativa entre el ingreso y el gasto total, lo que confirma que el ingreso es una variable predictora fundamental. 2. Identificación de variables clave para segmentación: El nivel educativo es un factor determinante en el nivel de ingresos. Este hallazgo es crucial para la segmentación, permitiendo agrupar a los clientes no solo por su capacidad de gasto, sino también por su perfil educativo, lo cual puede ser utilizado para mensajes de marketing más efectivos. 3. Comportamiento heterogéneo: variables como el número de visitas web mensuales no están directamente relacionadas con los ingresos o el nivel educativo. Esto sugiere que el comportamiento de navegación es complejo y debe ser analizado con otras variables de comportamiento para ser correctamente interpretado. 4. Necesidad de un modelo multivariado: La dispersión observada en los gráficos y las correlaciones débiles entre algunas variables refuerzan la necesidad de construir un modelo que considere múltiples factores para predecir el comportamiento del cliente de manera efectiva. Esto evitará depender de una única variable y capturará la complejidad real de la base de datos.
Llinás Solano, H. (s.f.). Estadística matemática (teoría con R). Departamento de Matemáticas y Estadística, Universidad del Norte. Recuperado de https://rpubs.com/hllinas/MgEst_Hipotesis_teoriaR
Bruce, P., & Bruce, A. (2017). Practical Statistics for Data Scientists: 50 Essential Concepts. O’Reilly Media.
James, G., Witten, D., Hastie, T., & Tibshirani, R. (2021). An Introduction to Statistical Learning: with Applications in R. Springer.
Provost, F., & Fawcett, T. (2013). Data Science for Business: What You Need to Know about Data Mining and Data-Analytic Thinking. O’Reilly Media.
A continuación se presenta todo el código utilizado:
#####activacion de paquetes#####
#librerias utilizadas durante el procesamiento y analisis del dataset
library(devtools)
library(dplyr)
library(ggplot2)
library(readxl)
library(tidyr)
library(naniar)
library(VIM)
library(mice)
library(caret)
library(corrplot)
###### Trabajo en base de datos######
###### Limpiezade datos######
#Cargue de base de datos
setwd('C:/Users/dolli/Documents/ESTUDIO/Maestria ciencia de datos/Primer_semestre')
datos <- read_excel("data_actividad1 (3).xlsx")
head(datos)
dim(datos) # para conocer la dimension de la base de datos
colnames(datos) # para conocer las variables que tiene la base de datos
summary(datos)
###### tabla descriptiva de las variables de la base de datos ######
variable_name <- colnames(datos)
description <- c("Customer’s yearly household income","Number of small children in customer’s household", "Number of teenagers in customer’s household","Number of days since the last purchase","Amount spent on wine products in the last 2 years",
"Amount spent on fruit products in the last 2 years","Amount spent on meat products in the last 2 years","Amount spent on fish products in the last 2 years","Amount spent on sweet products in the last 2 years","Amount spent on gold products in the last 2 years",
"Number of purchases made with discount","Number of purchases made through company’s website","Number of purchases made using catalog","Number of purchases made directly in stores",
"Number of visits to company’s website in the last month","1 if customer accepted the offer in the 3rd campaign, 0 otherwise","1 if customer accepted the offer in the 4th campaign, 0 otherwise","1 if customer accepted the offer in the 5th campaign, 0 otherwise",
"1 if customer accepted the offer in the 1st campaign, 0 otherwise","1 if customer accepted the offer in the 2nd campaign, 0 otherwise","1 if customer complained in the last 2 years","1 if customer accepted the offer in the last campaign, 0 otherwise",
"Age of customer","Number of days since registration as a customer","1 if customer is divorced, 0 otherwise","1 if customer is married, 0 otherwise","1 if customer is single, 0 otherwise",
"1 if customer is in relationship, 0 otherwise","1 if customer is a widow/widower, 0 otherwise","Customer has secondary education","Customer has basic education",
"Customer has a bachelor degree","Customer has a masters degree","Customer has a PhD","Total amount spent on all the products",
"Total amount spent on regular products","Overall number of accepted campaigns")
classification <- c("Continuous quantitative","Discrete quantitative","Discrete quantitative","Discrete quantitative","Continuous quantitative",
"Continuous quantitative","Continuous quantitative","Continuous quantitative","Continuous quantitative","Continuous quantitative",
"Discrete quantitative","Discrete quantitative","Discrete quantitative","Discrete quantitative",
"Discrete quantitative","Binary nominal qualitative","Binary nominal qualitative","Binary nominal qualitative",
"Binary nominal qualitative","Binary nominal qualitative","Binary nominal qualitative","Binary nominal qualitative",
"Discrete quantitative","Discrete quantitative","Binary nominal qualitative","Binary nominal qualitative","Binary nominal qualitative",
"Binary nominal qualitative","Binary nominal qualitative","Binary nominal qualitative","Binary nominal qualitative",
"Binary nominal qualitative","Binary nominal qualitative","Binary nominal qualitative","Continuous quantitative",
"Continuous quantitative","Discrete quantitative")
tabla_descriptiva <- data.frame(
Variable_name = variable_name,
Description = description,
Classification = classification
)
tabla_descriptiva
#imprimiendo en tabla la tabla descriptiva
knitr::kable(head(tabla_descriptiva, 37), caption = "Las 37 variables de la base de datos con su descripción")
#agrupar variables tipo categorico como educacion, estdo civil
datos_1 <- datos %>%
mutate(Education = case_when(
`education_2n Cycle` == 1 ~ "Secondary education",
education_Basic == 1 ~ "Basic education",
education_Graduation == 1 ~ "bachelor degree",
education_Master == 1 ~ "Masters degree",
education_PhD == 1 ~ "PhD",
TRUE ~ "None"
))
datos_1 <- datos_1 %>%
mutate(Marital_Status = case_when(
marital_Divorced == 1 ~ "Divorced",
marital_Married == 1 ~ "Married",
marital_Single == 1 ~ "Single",
marital_Together == 1 ~ "In Relationship",
marital_Widow == 1 ~ "Widow/Widower",
TRUE ~ "None"
))
#borramos las columnas que derivaron en educacion, estado civil
datos_1 <- datos_1 %>%
select(-`education_2n Cycle`,-education_Basic,-education_Graduation,
-education_Master,-education_PhD,-marital_Divorced,-marital_Married,
-marital_Single,-marital_Together,-marital_Widow)
#tabla actualizada de la descricion de variables
variable_name <- colnames(datos_1)
description <- c("Customer’s yearly household income","Number of small children in customer’s household", "Number of teenagers in customer’s household","Number of days since the last purchase","Amount spent on wine products in the last 2 years",
"Amount spent on fruit products in the last 2 years","Amount spent on meat products in the last 2 years","Amount spent on fish products in the last 2 years","Amount spent on sweet products in the last 2 years","Amount spent on gold products in the last 2 years",
"Number of purchases made with discount","Number of purchases made through company’s website","Number of purchases made using catalog","Number of purchases made directly in stores",
"Number of visits to company’s website in the last month","1 if customer accepted the offer in the 3rd campaign, 0 otherwise","1 if customer accepted the offer in the 4th campaign, 0 otherwise","1 if customer accepted the offer in the 5th campaign, 0 otherwise",
"1 if customer accepted the offer in the 1st campaign, 0 otherwise","1 if customer accepted the offer in the 2nd campaign, 0 otherwise","1 if customer complained in the last 2 years","1 if customer accepted the offer in the last campaign, 0 otherwise",
"Age of customer","Number of days since registration as a customer","Total amount spent on all the products",
"Total amount spent on regular products","Overall number of accepted campaigns","Customer’s education level (e.g., Basic, Graduation, Master, PhD, Secondary)","Customer’s marital status (e.g., Single, Married, Divorced, Widow, Together)")
classification <- c("Continuous quantitative","Discrete quantitative","Discrete quantitative","Discrete quantitative","Continuous quantitative",
"Continuous quantitative","Continuous quantitative","Continuous quantitative","Continuous quantitative","Continuous quantitative",
"Discrete quantitative","Discrete quantitative","Discrete quantitative","Discrete quantitative",
"Discrete quantitative","Binary nominal qualitative","Binary nominal qualitative","Binary nominal qualitative",
"Binary nominal qualitative","Binary nominal qualitative","Binary nominal qualitative","Binary nominal qualitative",
"Discrete quantitative","Discrete quantitative",
"Continuous quantitative",
"Continuous quantitative","Discrete quantitative","Ordinal qualitative",
"Nominal qualitative")
tabla_descriptiva_1 <- data.frame(
Variable_name = variable_name,
Description = description,
Classification = classification
)
#imprimiendo la tabla actualizada
tabla_descriptiva_1
knitr::kable(head(tabla_descriptiva_1, 29), caption = "Tabla actualizada con las 29 variables de la base de datos con su descripción")
######identificacion de elementos duplicados ######
#me muestra cuales son los datos que estan duplicados en datalle
detalle_duplicados <- datos_1 %>%
group_by(across(everything())) %>%
filter(n() > 1) %>%
ungroup()
#funcion para detectar duplicados
# Detectar y contar registros duplicados exactos
duplicados_conteo <- datos_1 %>%
group_by(across(everything())) %>% # Agrupa por TODAS las columnas
summarise(Frecuencia = n(), .groups = "drop") %>% # Cuenta repeticiones
filter(Frecuencia > 1) %>% # Filtra solo los que tienen duplicados
arrange(desc(Frecuencia)) # Ordena de mayor a menor
# Mostrar resultado
knitr::kable(head(duplicados_conteo, 37), caption = "Tabla con el conteo de registros duplicados")
# Eliminar duplicados exactos y dejar solo la primera aparición
datos_sin_duplicados <- datos_1 %>%
distinct()
#resumen estadistico de los datos para una revision general
summary(datos_sin_duplicados)
#se borra los numeros negativos observados en el resumen estadistico
datos_sin_duplicados <- datos_sin_duplicados %>% filter(MntRegularProds >= 0)
summary(datos_sin_duplicados$MntRegularProds)
###### identificacion de valores atipicos ######
# Seleccionar solo variables numéricas
numeric_vars <- datos_sin_duplicados[, sapply(datos_sin_duplicados, is.numeric)]
# selecciono solo variables cuantitativas continuas
binaria <- sapply(numeric_vars, function(x) all(x %in% c(0,1)))
var_continua <- numeric_vars[,!binaria]
# Crear tabla con estadísticos descriptivos
tabla_estadistica <- var_continua %>%
dplyr::summarise(across(
everything(),
list(
media = ~mean(.x, na.rm = TRUE),
mediana = ~median(.x, na.rm = TRUE),
sd = ~sd(.x, na.rm = TRUE),
min = ~min(.x, na.rm = TRUE),
Q1 = ~quantile(.x, 0.25, na.rm = TRUE),
Q3 = ~quantile(.x, 0.75, na.rm = TRUE),
max = ~max(.x, na.rm = TRUE),
IQR = ~IQR(.x, na.rm = TRUE)
),
.names = "{.col}__{.fn}" # doble guion bajo para evitar conflictos
)) %>%
pivot_longer(
cols = everything(),
names_to = c("Variable", "Estadistico"),
names_sep = "__", # usar doble guion bajo
values_to = "Valor"
) %>%
distinct(Variable, Estadistico, .keep_all = TRUE) %>% # eliminar duplicados
pivot_wider(
names_from = Estadistico,
values_from = Valor
)
knitr::kable(head(tabla_estadistica,68), caption = "Tabla con el estadistico de variables con outlier")
# Bucle para graficar cada variable en boxplot y diferenciar visualmente los outlier
for (var in names(var_continua)) {
p <- ggplot(var_continua, aes_string(y = var)) +
geom_boxplot(fill = "skyblue", outlier.colour = "red") +
theme_minimal() +
labs(title = paste("Boxplot of", var),
y = var)
print(p)
}
# Función para detectar outliers con IQR
detect_outliers <- function(x) {
Q1 <- quantile(x, 0.25, na.rm = TRUE)
Q3 <- quantile(x, 0.75, na.rm = TRUE)
IQR_val <- Q3 - Q1
lower <- Q1 - 1.5 * IQR_val
upper <- Q3 + 1.5 * IQR_val
outliers <- x[x < lower | x > upper]
return(outliers)
}
#aplicamos la funcion de detectar outlier a el dataset continuo para crear la tabla outlier
tabla_outlier <- lapply(var_continua, detect_outliers)
# Convertimos a data.frame para verlo como tabla
tabla_outlier <- data.frame(
Variable = names(tabla_outlier),
Outliers = sapply(tabla_outlier, function(x) paste(x, collapse = ", ")),
Total_Outliers = sapply(tabla_outlier, length)
)
#observar a detalle aquellas variables que me muestran outlier superiores al 10 %
ggplot(datos_sin_duplicados, aes(x = Income)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$Income, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$Income, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$Income, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$Income, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$Income, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$Income, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$Income, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 21. Distribución de Income con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = MntWines)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntWines, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntWines, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntWines, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntWines, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$MntWines, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntWines, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$MntWines, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 22. Distribución de MntWines con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = MntFruits)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntFruits, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntFruits, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntFruits, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntFruits, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$MntFruits, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntFruits, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$MntFruits, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 23. Distribución de MntFruits con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = MntMeatProducts)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntMeatProducts, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntMeatProducts, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntMeatProducts, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntMeatProducts, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$MntMeatProducts, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntMeatProducts, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$MntMeatProducts, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 24. Distribución de MntMeatProducts con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = MntFishProducts)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntFishProducts, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntFishProducts, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntFishProducts, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntFishProducts, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$MntFishProducts, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntFishProducts, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$MntFishProducts, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 25 Distribución de MntFishProducts con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = MntSweetProducts)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntSweetProducts, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntSweetProducts, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntSweetProducts, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntSweetProducts, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$MntSweetProducts, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntSweetProducts, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$MntSweetProducts, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 26. Distribución de MntSweetProducts con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = MntGoldProds)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntGoldProds, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntGoldProds, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntGoldProds, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntGoldProds, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$MntGoldProds, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntGoldProds, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$MntGoldProds, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 27. Distribución de MntGoldProds con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = NumDealsPurchases)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumDealsPurchases, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumDealsPurchases, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumDealsPurchases, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumDealsPurchases, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$NumDealsPurchases, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumDealsPurchases, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$NumDealsPurchases, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 28. Distribución de NumDealsPurchases con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = NumWebPurchases)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumWebPurchases, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumWebPurchases, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumWebPurchases, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumWebPurchases, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$NumWebPurchases, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumWebPurchases, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$NumWebPurchases, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 29. Distribución de NumWebPurchases con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = NumCatalogPurchases)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumCatalogPurchases, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumCatalogPurchases, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumCatalogPurchases, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumCatalogPurchases, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$NumCatalogPurchases, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumCatalogPurchases, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$NumCatalogPurchases, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 30. Distribución de NumCatalogPurchases con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = NumWebVisitsMonth)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumWebVisitsMonth, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumWebVisitsMonth, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumWebVisitsMonth, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumWebVisitsMonth, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$NumWebVisitsMonth, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$NumWebVisitsMonth, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$NumWebVisitsMonth, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 31. Distribución de NumWebVisitsMonth con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = Age)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$Age, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$Age, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$Age, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$Age, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$Age, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$Age, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$Age, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 32. Distribución de Age con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = MntTotal)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntTotal, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntTotal, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntTotal, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntTotal, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$MntTotal, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntTotal, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$MntTotal, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 33. Distribución de MntTotal con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = MntRegularProds)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntRegularProds, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntRegularProds, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntRegularProds, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntRegularProds, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$MntRegularProds, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$MntRegularProds, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$MntRegularProds, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 34. Distribución de MntRegularProds con cuartiles y límites de outliers"))
ggplot(datos_sin_duplicados, aes(x = AcceptedCmpOverall)) +
geom_histogram(bins = 30, fill = "skyblue", color = "black", alpha = 0.7) +
geom_vline(xintercept = quantile(datos_sin_duplicados$AcceptedCmpOverall, 0.25, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$AcceptedCmpOverall, 0.5, na.rm = TRUE),color = "blue", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$AcceptedCmpOverall, 0.75, na.rm = TRUE),color = "red", linetype = "dashed") +
geom_vline(xintercept = quantile(datos_sin_duplicados$AcceptedCmpOverall, 0.25, na.rm = TRUE) - 1.5 * IQR(datos_sin_duplicados$AcceptedCmpOverall, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
geom_vline(xintercept = quantile(datos_sin_duplicados$AcceptedCmpOverall, 0.75, na.rm = TRUE) + 1.5 * IQR(datos_sin_duplicados$AcceptedCmpOverall, na.rm = TRUE), color = "darkgreen", linetype = "dotted") +
labs(title = paste("Gráfico 35. Distribución de AcceptedCmpOveralls con cuartiles y límites de outliers"))
###tratamiento de outlier #####
#Vamos a utilizar dos tecnicas dependiendo de la variable y los outlier, vamos a eliminar y vamos a recortar
#primero eliminacion de outlier variables numwebpurchases y age
# Función para eliminar outliers con IQR
eliminar_outliers <- function(x) {
q1 <- quantile(x, 0.25, na.rm = TRUE)
q3 <- quantile(x, 0.75, na.rm = TRUE)
iqr <- q3 - q1
lim_inf <- q1 - 1.5 * iqr
lim_sup <- q3 + 1.5 * iqr
x >= lim_inf & x <= lim_sup
}
# eliminando outliers en "NumWebPurchases y "age" y recortar numcatalogopurchases y numwebvisitsmonth
datos_sin_outlier <- datos_sin_duplicados %>%
filter(eliminar_outliers(NumWebPurchases)) %>%
filter(eliminar_outliers(Age))
# Crear dos versiones de la variable age
age_original <- datos_sin_duplicados$Age
age_sin_outliers <- datos_sin_outlier$Age
# Construir dos dataframes separados
df_original <- data.frame(
Valor = age_original,
Estado = "Antes"
)
df_sin_outliers <- data.frame(
Valor = age_sin_outliers,
Estado = "Después"
)
# Unirlos
df_box <- rbind(df_original, df_sin_outliers)
# Graficar boxplots lado a lado
ggplot(df_box, aes(x = Estado, y = Valor, fill = Estado)) +
geom_boxplot(outlier.color = "red", alpha = 0.6) +
labs(title = "Comparación de Outliers en 'Age'",
x = "Age",
y = "Valor") +
theme_minimal()
# Crear dos versiones de la variable NumWebPurchases
numweb_original <- datos_sin_duplicados$NumWebPurchases
numweb_sin_outliers <- datos_sin_outlier$NumWebPurchases
# Construir dos dataframes separados
df_original_web <- data.frame(
Valor = numweb_original,
Estado = "Antes"
)
df_sin_outliers_web <- data.frame(
Valor = numweb_sin_outliers,
Estado = "Después"
)
# Unirlos
df_box_1 <- rbind(df_original_web, df_sin_outliers_web)
# Graficar boxplots lado a lado
ggplot(df_box_1, aes(x = Estado, y = Valor, fill = Estado)) +
geom_boxplot(outlier.color = "red", alpha = 0.6) +
labs(title = "Comparación de Outliers en 'NumWebPurchases'",
x = "NumWebPurchases",
y = "Valor") +
theme_minimal()
#TECNICA DOS: RECORTAR
#funcion para recortar los outlier
recortar_outliers <- function(x) {
# Q1 y Q3
q1 <- quantile(x, 0.25, na.rm = TRUE)
q3 <- quantile(x, 0.75, na.rm = TRUE)
iqr <- q3 - q1
# Límites
lim_inf <- q1 - 1.5 * iqr
lim_sup <- q3 + 1.5 * iqr
# Reemplazar valores fuera de rango
x[x < lim_inf] <- lim_inf
x[x > lim_sup] <- lim_sup
return(x)
}
datos_sin_outlier$NumWebVisitsMonth <- recortar_outliers(datos_sin_outlier$NumWebVisitsMonth)
datos_sin_outlier$NumCatalogPurchases <- recortar_outliers(datos_sin_outlier$NumCatalogPurchases)
#creando las graficas de antes y despues NumCatalogPurchases
#Crear dos versiones de la variable NumCatalogPurchases
cat_original <- datos_sin_duplicados$NumCatalogPurchases
cat_sin_outliers <- datos_sin_outlier$NumCatalogPurchases
# Construir dos dataframes separados
df_original <- data.frame(
Valor = cat_original,
Estado = "Antes"
)
df_sin_outliers <- data.frame(
Valor = cat_sin_outliers,
Estado = "Después"
)
# Unirlos
df_box_3 <- rbind(df_original, df_sin_outliers)
#Graficar boxplots lado a lado
ggplot(df_box_3, aes(x = Estado, y = Valor, fill = Estado)) +
geom_boxplot(outlier.color = "red", alpha = 0.6) +
labs(title = "Comparación de Outliers en 'NumCatalogPurchases'",
x = "Numero de catalogo",
y = "Valor") +
theme_minimal()
#creando las graficas de antes y despues variable NumWebVisitsMonth
# Crear dos versiones de la variable age
vist_original <- datos_sin_duplicados$NumWebVisitsMonth
vist_sin_outliers <- datos_sin_outlier$NumWebVisitsMonth
# Construir dos dataframes separados
df_original <- data.frame(
Valor = vist_original,
Estado = "Antes"
)
df_sin_outliers <- data.frame(
Valor = vist_sin_outliers,
Estado = "Después"
)
# Unirlos
df_box_4 <- rbind(df_original, df_sin_outliers)
# Graficar boxplots lado a lado
ggplot(df_box_4, aes(x = Estado, y = Valor, fill = Estado)) +
geom_boxplot(outlier.color = "red", alpha = 0.6) +
labs(title = "Comparación de Outliers en 'NumVisitsMonth'",
x = "Numero de Visitas",
y = "Valor") +
theme_minimal()
#tabla estadistica actualizada, con el manejo de outlier
# Función para detectar si una variable es binaria (solo 0 y 1)
es_binaria <- function(x) {
is.numeric(x) && all(na.omit(x) %in% c(0, 1))
}
tabla_estadistica_1 <- datos_sin_outlier %>%
summarise(across(
where(function(col) is.numeric(col) && !es_binaria(col)), # numéricas pero no binarias
list(
media = ~mean(.x, na.rm = TRUE),
mediana = ~median(.x, na.rm = TRUE),
sd = ~sd(.x, na.rm = TRUE),
min = ~min(.x, na.rm = TRUE),
Q1 = ~quantile(.x, 0.25, na.rm = TRUE),
Q3 = ~quantile(.x, 0.75, na.rm = TRUE),
max = ~max(.x, na.rm = TRUE),
IQR = ~IQR(.x, na.rm = TRUE)
),
.names = "{.col}__{.fn}"
)) %>%
pivot_longer(
cols = everything(),
names_to = c("Variable", "Estadistico"),
names_sep = "__",
values_to = "Valor"
) %>%
distinct(Variable, Estadistico, .keep_all = TRUE) %>%
pivot_wider(
names_from = Estadistico,
values_from = Valor
)
### datos faltantes ###
# identificar que variables le faltan datos en un nuevo dataframe
datos_completos = colSums(is.na(datos_sin_outlier)) %>% as.data.frame()
# Calcular porcentaje de datos faltantes por variable
faltantes_por_variable <- datos_sin_outlier %>%
summarise(across(everything(), ~mean(is.na(.))*100)) %>%
pivot_longer(cols = everything(),
names_to = "Variable",
values_to = "Porcentaje_Faltante")
print(faltantes_por_variable)
# Gráfico 1: porcentaje de valores faltantes por variable
ggplot(faltantes_por_variable, aes(x = reorder(Variable, -Porcentaje_Faltante),
y = Porcentaje_Faltante)) +
geom_col(fill = "steelblue") +
coord_flip() +
labs(title = "Porcentaje de datos faltantes por variable",
x = "Variable", y = "% de datos faltantes") +
theme_minimal()
# Gráfico 2 mapa de calor de faltantes
vis_miss(datos_sin_outlier) +
labs(title = "Mapa de calor de valores faltantes")
### DETERMINACIÓN DEL MECANISMO (MCAR test) ###
# Seleccionar solo numéricas
datos_num <- datos_sin_outlier %>% select(where(is.numeric))
# Filtrar columnas problemáticas
datos_num <- datos_num %>%
select(where(~ var(., na.rm = TRUE) > 0)) # elimina varianza cero
nzv <- nearZeroVar(datos_num) # elimina variables near-zero variance
if (length(nzv) > 0) datos_num <- datos_num[, -nzv]
cor_mat <- cor(datos_num, use = "pairwise.complete.obs") # elimina redundantes
altas_cor <- findCorrelation(cor_mat, cutoff = 0.95)
if (length(altas_cor) > 0) datos_num <- datos_num[, -altas_cor]
# Aplicar Little’s MCAR test (naniar)
resultado_mcar <- mcar_test(datos_num)
print(resultado_mcar)
### IMPUTACIÓN DE DATOS FALTANTES ###
# Decisión: como solo hay ~4% de faltantes, se usa imputación simple (mediana/moda)
# Imputar numéricas con mediana
datos_imputados <- datos_sin_outlier %>%
mutate(across(where(is.numeric),
~ ifelse(is.na(.), median(., na.rm = TRUE), .)))
# Imputar categóricas con la moda
mode_value <- function(x) {
ux <- na.omit(unique(x))
ux[which.max(tabulate(match(x, ux)))]
}
datos_imputados <- datos_imputados %>%
mutate(across(where(is.factor),
~ ifelse(is.na(.), mode_value(.), .)))
# Verificar gráfica ya no hay NA
gg_miss_var(datos_imputados) +
labs(title = "Verificación post-imputación (sin valores faltantes)")
# data limpia
data_limpia <-data.frame(datos_imputados)
#pos analisis
print(head(data_limpia))
print(dim(data_limpia))
#agrupamos las variables numericas y categoricas por aparte para facilitar la graficacion
var_categoricas <- data_limpia %>% select_if(~ is.factor(.) | is.character(.)) # Solo variables categóricas
var_continuas <- data_limpia %>% select_if(is.numeric) # Solo variables numéricas continuas
# Matriz de correlación
cor_matrix <- cor(var_continuas, use = "complete.obs")
print(cor_matrix)
corrplot(cor_matrix, method = "color", type = "upper",
tl.col = "black", tl.srt = 90, tl.cex = 0.4)
#numeral vs numeral
ggplot(data_limpia, aes(x = Income, y = MntTotal)) +
geom_point(color = "blue", alpha = 0.6) +
geom_smooth(method = "lm", se = FALSE, color = "red") +
theme_minimal() +
labs(title = "Gráfico 44. Relación entre ingreso y monto total")
ggplot(data_limpia, aes(x = NumWebVisitsMonth, y = Income)) +
geom_point(color = "blue", alpha = 0.6) +
geom_smooth(method = "lm", se = FALSE, color = "red") +
theme_minimal() +
labs(title = "Gráfico 45. Relación entre numero de visitas al mes y ingresos")
ggplot(data_limpia, aes(x = Age, y = Income)) +
geom_point(alpha = 0.3) +
geom_density_2d(color = "red") +
theme_minimal() +
labs(title = "Gráfico 46. Densidad Age vs Income")
#categoria vs numeral
ggplot(data_limpia, aes(x = factor(Education), y = Income)) +
geom_boxplot(fill = "lightblue") +
theme_minimal() +
labs(title = "Gráfico 47. Ingresos por nivel educativo", x = "Education", y = "Income")
anova_result <- aov(Income ~ factor(Education), data = data_limpia)
summary(anova_result)
ggplot(data_limpia, aes(x = factor(Education), y = NumWebVisitsMonth)) +
geom_boxplot(fill = "lightgreen") +
theme_minimal() +
labs(title = "Gráfico 48. Numero de visitas al mes por educación", x = "Education", y = "NumWebVisitsMonth")
anova_result <- aov(NumWebVisitsMonth ~ factor(Education), data = data_limpia)
summary(anova_result)