Asociación e independencia entre variables

Cargar librerías

# Cargamos tidyverse
library("tidyverse")
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

Importar datos

# Cargamos datos
read_delim(
  file = "01_data/programacion/winequality-red.csv",
  delim = ",", 
  locale=locale(decimal_mark = ".")
  ) -> wine_raw
Rows: 1599 Columns: 12
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
dbl (12): fixed acidity, volatile acidity, citric acid, residual sugar, chlo...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Revisar la estructura de los datos
str(wine_raw)
spc_tbl_ [1,599 × 12] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ fixed acidity       : num [1:1599] 7.4 7.8 7.8 11.2 7.4 7.4 7.9 7.3 7.8 7.5 ...
 $ volatile acidity    : num [1:1599] 0.7 0.88 0.76 0.28 0.7 0.66 0.6 0.65 0.58 0.5 ...
 $ citric acid         : num [1:1599] 0 0 0.04 0.56 0 0 0.06 0 0.02 0.36 ...
 $ residual sugar      : num [1:1599] 1.9 2.6 2.3 1.9 1.9 1.8 1.6 1.2 2 6.1 ...
 $ chlorides           : num [1:1599] 0.076 0.098 0.092 0.075 0.076 0.075 0.069 0.065 0.073 0.071 ...
 $ free sulfur dioxide : num [1:1599] 11 25 15 17 11 13 15 15 9 17 ...
 $ total sulfur dioxide: num [1:1599] 34 67 54 60 34 40 59 21 18 102 ...
 $ density             : num [1:1599] 0.998 0.997 0.997 0.998 0.998 ...
 $ pH                  : num [1:1599] 3.51 3.2 3.26 3.16 3.51 3.51 3.3 3.39 3.36 3.35 ...
 $ sulphates           : num [1:1599] 0.56 0.68 0.65 0.58 0.56 0.56 0.46 0.47 0.57 0.8 ...
 $ alcohol             : num [1:1599] 9.4 9.8 9.8 9.8 9.4 9.4 9.4 10 9.5 10.5 ...
 $ quality             : num [1:1599] 5 5 5 6 5 5 5 7 7 5 ...
 - attr(*, "spec")=
  .. cols(
  ..   `fixed acidity` = col_double(),
  ..   `volatile acidity` = col_double(),
  ..   `citric acid` = col_double(),
  ..   `residual sugar` = col_double(),
  ..   chlorides = col_double(),
  ..   `free sulfur dioxide` = col_double(),
  ..   `total sulfur dioxide` = col_double(),
  ..   density = col_double(),
  ..   pH = col_double(),
  ..   sulphates = col_double(),
  ..   alcohol = col_double(),
  ..   quality = col_double()
  .. )
 - attr(*, "problems")=<externalptr> 

Información sobre el conjunto de datos

Información general

Los datos corresponden a una variación de un vino tradicional portugués llamado “Vinho Verde” proveniente de una región llamada Vinho, ubicada muy al norte de Portugal.

Variables

  • fixed acidity: ácidos del vino que no se evaporan fácilmente.
  • volatile acidity: cantidad de ácido acético en el vino, el cual en altas cantidades genera sensaciones no placenteras y un sabor vinagroso.
  • citric acid: cantidad de ácido cítrico en pequeñas cantidades, el cual añade cierta frescura y sabor al vino.
  • residual sugar: cantidad de azucar residual luego del proceso de fermentación. Es raro tener menos de 1g/litro y los vinos con más de 45g/litro se consideran dulces.
  • chlorides: cantidad de sal en el vino.
  • free sulfur dioxide: cantidad de dióxido de azufre (S02) libre, el cual previene el crecimiento de microbios y la oxidación del vino.
  • total sulfur dioxide: cantidad total de dióxido de azufre (S02) en forma libre y fija; en bajas concentraciones es indetectable, en concentraciones superiores a 50ppm el SO2 es evidente para la nariz y el sabor del vino.
  • density: la densidad del vino es cercana a la del agua dependiendo de la cantidad de azucar y alcohol.
  • pH: describe qué tan ácido o básico es un vino en un escala desde cero (muy ácido) hasta 14 (muy básico); la gran mayoría de vinos tienen un pH entre 3-4.
  • sulphates: un aditivo que contribuye a regular los niveles de dióxido de azufre (S02), el cual actúa como antimicrobios y antioxidante.
  • alcohol: porcentaje del alcohol del vino.
  • quality: puntuación del vino basada en datos sensoriales, en una escala entre 0 y 10.

Fuente

Cortez, P., Cerdeira, A., Almeida, F., Matos, T., & Reis, J. (2009). Modeling wine preferences by data mining from physicochemical properties. Decision Support Systems, 47(4), 547-553.

Note que es muy importante tener un contexto sobre el conjunto de datos.

Dimensionalidad de los datos

dim(wine_raw)
[1] 1599   12
  • 1599 individuos - Número de filas
  • 12 variables - Número de columnas

Todos los cálculos y procedimientos matemáticos y estadísticos, a nivel computacional, se realizan mediante operaciones sobre las estructuras de datos vistas en la práctica de programación básica.

## Obtener solo el número de filas
nrow(wine_raw)
[1] 1599
## Obtener solo el número de columnas
ncol(wine_raw)
[1] 12

Limpieza de los datos

En la práctica la calidad de los datos puede estar afectada por los procesos de captura, sistematización y distribución. Siempre hay que verificar la calidad de nuestros datos.

  • Limpieza de tablas (3 principios vistos en clase)
  • Nombrado adecuado de las variables
  • Datos faltantes
  • Datos atípicos
  • Valores duplicados

Para mayor detalle, consulte el material de la practica de limpieza de datos.

En este caso la base de datos proporcionada ya tiene una estructura adecuada para el procesamiento, salvo que los nombres de las columnas tienen espacios y no siguen las convenciones del naming de variavbles, por lo que vamos a ponerles un buen nombre

names(wine_raw) <- str_replace_all(names(wine_raw), c(" " = "_"))

Enriquecimiento de datos

Dado que inicialmente todas las variables son cuantitativas, vamos a realizar una operación sobre nuestro conjunto de datos para agregar dos nuevas columnas categóricas, de tal manera que podemos explorar algunas medidas y gráficas relevantes.

## Partimos de la base de datos 'wine_raw'
## y la ontroducimos a un algoritmo de operaciones
wine_raw %>%
  ## mutate() crea una nueva variable llamada 'calidad'
  ## basada en los rangos ya conocidos de la variable quality
  mutate(
    calidad = ifelse(
      quality == '3' | quality == '4','baja',
      ifelse(
        quality == '5' | quality == '6','media',
        'alta'))
  ) %>% 
  ## mutate_at() recibe la columna 'calidad' y la convierte en un factor
  mutate_at('calidad', factor) %>%
  
  ## mutate() crea una nueva variable llamada 'acetico'
  ## basada en rangos conocidos de la variable 'volatile_acidity'
  mutate(
    acetico = ifelse(volatile_acidity < 0.7, 'bajo', 'alto')
  ) %>% 
  ## mutate_at() recibe la columna 'acetico' y la convierte en un factor
  ## el resultado de todas las operaciones se guarda en 'wine_processed'
  mutate_at('acetico', factor) -> wine_processed

# Especificamos el orden de los factores que acabamos de crear
wine_processed$calidad <- factor(wine_processed$calidad, levels = c("baja","media","alta"))
wine_processed$acetico <- factor(wine_processed$acetico, levels = c("bajo","alto"))

Análisis descriptivo

Resumen numérico

El método summary() que trae por defecto R nos brinda estadísticas de resumen para cada una de las variables de nuestro conjunto de datos.

## Resumen básico de datos
summary(wine_processed)
 fixed_acidity   volatile_acidity  citric_acid    residual_sugar  
 Min.   : 4.60   Min.   :0.1200   Min.   :0.000   Min.   : 0.900  
 1st Qu.: 7.10   1st Qu.:0.3900   1st Qu.:0.090   1st Qu.: 1.900  
 Median : 7.90   Median :0.5200   Median :0.260   Median : 2.200  
 Mean   : 8.32   Mean   :0.5278   Mean   :0.271   Mean   : 2.539  
 3rd Qu.: 9.20   3rd Qu.:0.6400   3rd Qu.:0.420   3rd Qu.: 2.600  
 Max.   :15.90   Max.   :1.5800   Max.   :1.000   Max.   :15.500  
   chlorides       free_sulfur_dioxide total_sulfur_dioxide    density      
 Min.   :0.01200   Min.   : 1.00       Min.   :  6.00       Min.   :0.9901  
 1st Qu.:0.07000   1st Qu.: 7.00       1st Qu.: 22.00       1st Qu.:0.9956  
 Median :0.07900   Median :14.00       Median : 38.00       Median :0.9968  
 Mean   :0.08747   Mean   :15.87       Mean   : 46.47       Mean   :0.9967  
 3rd Qu.:0.09000   3rd Qu.:21.00       3rd Qu.: 62.00       3rd Qu.:0.9978  
 Max.   :0.61100   Max.   :72.00       Max.   :289.00       Max.   :1.0037  
       pH          sulphates         alcohol         quality       calidad    
 Min.   :2.740   Min.   :0.3300   Min.   : 8.40   Min.   :3.000   baja :  63  
 1st Qu.:3.210   1st Qu.:0.5500   1st Qu.: 9.50   1st Qu.:5.000   media:1319  
 Median :3.310   Median :0.6200   Median :10.20   Median :6.000   alta : 217  
 Mean   :3.311   Mean   :0.6581   Mean   :10.42   Mean   :5.636               
 3rd Qu.:3.400   3rd Qu.:0.7300   3rd Qu.:11.10   3rd Qu.:6.000               
 Max.   :4.010   Max.   :2.0000   Max.   :14.90   Max.   :8.000               
 acetico    
 bajo:1366  
 alto: 233  
            
            
            
            

Resumen gráfico

## Cargamos la librería ggplot2
library("ggplot2")

## Usamos el método para graficar histogramas
## Seleccionamos como objetivo la variable quality
ggplot(wine_processed, aes(quality)) +
    geom_histogram()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Note que podemos hacer histogramas para las demás variables. Además, podríamos realizar otros tipos de gráficos univariados.

Nuestro interés ahora será construir resúmenes numéricos y resúmenes gráficos entre dos o más variables.

Efectos de una variable sobre otra

En una investigación o estudio podemos sospechar de la influencia o efecto de un conjunto de variables sobre una variable particular de interés (target / label / variable crítica / variable explicada). Una parte esencial de la fase de análisis es reunir evidencia para seleccionar las variables que tengan mayor probabilidad de tener un efecto sobre nuestra variable de interés.

Existen distintas herramientas estadísticas para tener una idea bien formada de cómo se relacionan dos o más variables entre sí.

Antes de explorar dichas herramientas, conviene hacer una revisión sobre algunos conceptos.

Asociación entre dos variables contínuas

La covarianza es una medida numérica que nos permite cuantificar la relación (lineal) entre dos variables contínuas.

Su estimador es la covarianza muestral:

  • Si dos variables son independientes su covarianza es nula. El reciproco no es cierto en general, si dos variables tienen covarianza nula se dice que son incorreladas (no hay relación lineal, aunque puede haber una relación no lineal).
  • Si la covarianza es positiva indica que a valores grandes de X le corresponden valores grandes de Y (i.e. al incrementar X se incrementa Y) y se dice que hay una relación lineal positiva.
  • Si la covarianza es negativa indica que a valores grandes de X le corresponden valores pequeños de Y (i.e. al incrementar X, Y disminuye) y se dice que hay una relación lineal negativa.

Cuanto mayor es el valor (absoluto) de la covarianza, mayor es el grado de relación lineal entre las variables. Sin embargo, su valor depende de las escala de las variables por lo que es difícil determinar cuando es grande o pequeña. Para medir el grado de relación lineal puede ser preferible reescalarla, i.e. emplear el coeficiente de correlación:

Su estimador es el coeficiente de correlación muestral:

  • Una correlación positiva entre dos variables indica que a medida que los valores de una variable crecen los valores de la otra variable también crecen. Y viceversa. El máximo valor de una correlación positiva es 1.
  • Una correlación negativa entre dos variables indica que a medida que los valores de una variable crecen los valores de la otra variable decrecen. El máximo valor de una correlación negativa es -1.
  • Una correlación de cero entre dos variables indica que no existe una asociación lineal entre ellas.

Dado que el trabajo estadístico de datos es principalmente matricial y tenemos un número finito de variables aleatorias, en vez de calcular la covarianza entre dos variables podemos construir una matriz de covarianzas y calcular las covarianzas entre todas las variables.

Covarianzas en R

## Covarianzas entre dos variables
cov(wine_processed$fixed_acidity, wine_processed$quality)
[1] 0.1744236
cov(wine_processed$chlorides, wine_processed$quality)
[1] -0.004899545
## Matriz de varianzas y covarianzas
## Note que filtramos la base de datos para solamente calcular correlaciones entre variables cuantitativas 
cov(Filter(is.numeric, wine_processed))
                     fixed_acidity volatile_acidity   citric_acid
fixed_acidity          3.031416389    -7.985142e-02  0.2278200037
volatile_acidity      -0.079851417     3.206238e-02 -0.0192716208
citric_acid            0.227820004    -1.927162e-02  0.0379474831
residual_sugar         0.281756262     4.841910e-04  0.0394342700
chlorides              0.007678692     5.165869e-04  0.0018687248
free_sulfur_dioxide   -2.800921493    -1.967359e-02 -0.1242521139
total_sulfur_dioxide  -6.482345858     4.504257e-01  0.2276972740
density                0.002195224     7.443665e-06  0.0001341746
pH                    -0.183585704     6.494699e-03 -0.0162975823
sulphates              0.054010092    -7.921434e-03  0.0103277145
alcohol               -0.114421153    -3.860022e-02  0.0228151729
quality                0.174423588    -5.647588e-02  0.0356118929
                     residual_sugar     chlorides free_sulfur_dioxide
fixed_acidity          0.2817562623  7.678692e-03       -2.800921e+00
volatile_acidity       0.0004841910  5.165869e-04       -1.967359e-02
citric_acid            0.0394342700  1.868725e-03       -1.242521e-01
residual_sugar         1.9878971330  3.690176e-03        2.758611e+00
chlorides              0.0036901759  2.215143e-03        2.738303e-03
free_sulfur_dioxide    2.7586114522  2.738303e-03        1.094149e+02
total_sulfur_dioxide   9.4164414790  7.338675e-02        2.297375e+02
density                0.0009454109  1.782176e-05       -4.332504e-04
pH                    -0.0186442890 -1.925745e-03        1.136531e-01
sulphates              0.0013209414  2.961878e-03        9.159247e-02
alcohol                0.0632189598 -1.109152e-02       -7.736984e-01
quality                0.0156350457 -4.899545e-03       -4.279071e-01
                     total_sulfur_dioxide       density            pH
fixed_acidity               -6.482346e+00  2.195224e-03 -1.835857e-01
volatile_acidity             4.504257e-01  7.443665e-06  6.494699e-03
citric_acid                  2.276973e-01  1.341746e-04 -1.629758e-02
residual_sugar               9.416441e+00  9.454109e-04 -1.864429e-02
chlorides                    7.338675e-02  1.782176e-05 -1.925745e-03
free_sulfur_dioxide          2.297375e+02 -4.332504e-04  1.136531e-01
total_sulfur_dioxide         1.082102e+03  4.424727e-03 -3.376988e-01
density                      4.424727e-03  3.562029e-06 -9.956395e-05
pH                          -3.376988e-01 -9.956395e-05  2.383518e-02
sulphates                    2.394710e-01  4.750962e-05 -5.146186e-03
alcohol                     -7.209298e+00 -9.979518e-04  3.383162e-02
quality                     -4.917237e+00 -2.666037e-04 -7.197822e-03
                         sulphates       alcohol       quality
fixed_acidity         5.401009e-02 -0.1144211534  0.1744235876
volatile_acidity     -7.921434e-03 -0.0386002214 -0.0564758833
citric_acid           1.032771e-02  0.0228151729  0.0356118929
residual_sugar        1.320941e-03  0.0632189598  0.0156350457
chlorides             2.961878e-03 -0.0110915178 -0.0048995449
free_sulfur_dioxide   9.159247e-02 -0.7736984004 -0.4279070696
total_sulfur_dioxide  2.394710e-01 -7.2092978950 -4.9172370717
density               4.750962e-05 -0.0009979518 -0.0002666037
pH                   -5.146186e-03  0.0338316166 -0.0071978223
sulphates             2.873262e-02  0.0169067772  0.0344134084
alcohol               1.690678e-02  1.1356473950  0.4097890108
quality               3.441341e-02  0.4097890108  0.6521684000

Correlaciones en R

## Correlaciones entre dos variables
cor(wine_processed$fixed_acidity, wine_processed$quality, method = 'pearson')
[1] 0.1240516
cor(wine_processed$chlorides, wine_processed$quality, method = 'pearson')
[1] -0.1289066
## Matriz de correlaciones
## Note que filtramos la base de datos para solamente calcular correlaciones entre variables cuantitativas
cor(Filter(is.numeric, wine_processed), method = 'pearson')
                     fixed_acidity volatile_acidity citric_acid residual_sugar
fixed_acidity           1.00000000     -0.256130895  0.67170343    0.114776724
volatile_acidity       -0.25613089      1.000000000 -0.55249568    0.001917882
citric_acid             0.67170343     -0.552495685  1.00000000    0.143577162
residual_sugar          0.11477672      0.001917882  0.14357716    1.000000000
chlorides               0.09370519      0.061297772  0.20382291    0.055609535
free_sulfur_dioxide    -0.15379419     -0.010503827 -0.06097813    0.187048995
total_sulfur_dioxide   -0.11318144      0.076470005  0.03553302    0.203027882
density                 0.66804729      0.022026232  0.36494718    0.355283371
pH                     -0.68297819      0.234937294 -0.54190414   -0.085652422
sulphates               0.18300566     -0.260986685  0.31277004    0.005527121
alcohol                -0.06166827     -0.202288027  0.10990325    0.042075437
quality                 0.12405165     -0.390557780  0.22637251    0.013731637
                        chlorides free_sulfur_dioxide total_sulfur_dioxide
fixed_acidity         0.093705186        -0.153794193          -0.11318144
volatile_acidity      0.061297772        -0.010503827           0.07647000
citric_acid           0.203822914        -0.060978129           0.03553302
residual_sugar        0.055609535         0.187048995           0.20302788
chlorides             1.000000000         0.005562147           0.04740047
free_sulfur_dioxide   0.005562147         1.000000000           0.66766645
total_sulfur_dioxide  0.047400468         0.667666450           1.00000000
density               0.200632327        -0.021945831           0.07126948
pH                   -0.265026131         0.070377499          -0.06649456
sulphates             0.371260481         0.051657572           0.04294684
alcohol              -0.221140545        -0.069408354          -0.20565394
quality              -0.128906560        -0.050656057          -0.18510029
                         density          pH    sulphates     alcohol
fixed_acidity         0.66804729 -0.68297819  0.183005664 -0.06166827
volatile_acidity      0.02202623  0.23493729 -0.260986685 -0.20228803
citric_acid           0.36494718 -0.54190414  0.312770044  0.10990325
residual_sugar        0.35528337 -0.08565242  0.005527121  0.04207544
chlorides             0.20063233 -0.26502613  0.371260481 -0.22114054
free_sulfur_dioxide  -0.02194583  0.07037750  0.051657572 -0.06940835
total_sulfur_dioxide  0.07126948 -0.06649456  0.042946836 -0.20565394
density               1.00000000 -0.34169933  0.148506412 -0.49617977
pH                   -0.34169933  1.00000000 -0.196647602  0.20563251
sulphates             0.14850641 -0.19664760  1.000000000  0.09359475
alcohol              -0.49617977  0.20563251  0.093594750  1.00000000
quality              -0.17491923 -0.05773139  0.251397079  0.47616632
                         quality
fixed_acidity         0.12405165
volatile_acidity     -0.39055778
citric_acid           0.22637251
residual_sugar        0.01373164
chlorides            -0.12890656
free_sulfur_dioxide  -0.05065606
total_sulfur_dioxide -0.18510029
density              -0.17491923
pH                   -0.05773139
sulphates             0.25139708
alcohol               0.47616632
quality               1.00000000

Por defecto el método cor() calcula una correlación de Pearson, por tanto, el resultado numerico asume que la relación entre las variables es lineal. Dado que en la practica hay muchas relaciones no lineales, una forma más robusta de calcular la asociación es calculando una correlación de Spearman (method = ‘spearman’) o el estadístico Tau de Kendall (method = ‘kendall’).

Otra forma más bonita de mostrar correlaciones usando el paquete correlation

# Instalamos el paquete correlation
install.packages("correlation")
# Cargamos el paquete
library("correlation")
# Creamos una matriz detallada de correlaciones
# Note que acá no estamos filtrando las columnas numéricas como lo hicimos antes
# Esto debido a que el paquete automáticamente hace el filtrado. Uno debe verificar
correlaciones <- correlation(wine_processed)
correlaciones
# Correlation Matrix (pearson-method)

Parameter1           |           Parameter2 |        r |         95% CI | t(1597) |         p
---------------------------------------------------------------------------------------------
fixed_acidity        |     volatile_acidity |    -0.26 | [-0.30, -0.21] |  -10.59 | < .001***
fixed_acidity        |          citric_acid |     0.67 | [ 0.64,  0.70] |   36.23 | < .001***
fixed_acidity        |       residual_sugar |     0.11 | [ 0.07,  0.16] |    4.62 | < .001***
fixed_acidity        |            chlorides |     0.09 | [ 0.04,  0.14] |    3.76 | 0.005**  
fixed_acidity        |  free_sulfur_dioxide |    -0.15 | [-0.20, -0.11] |   -6.22 | < .001***
fixed_acidity        | total_sulfur_dioxide |    -0.11 | [-0.16, -0.06] |   -4.55 | < .001***
fixed_acidity        |              density |     0.67 | [ 0.64,  0.69] |   35.88 | < .001***
fixed_acidity        |                   pH |    -0.68 | [-0.71, -0.66] |  -37.37 | < .001***
fixed_acidity        |            sulphates |     0.18 | [ 0.14,  0.23] |    7.44 | < .001***
fixed_acidity        |              alcohol |    -0.06 | [-0.11, -0.01] |   -2.47 | 0.246    
fixed_acidity        |              quality |     0.12 | [ 0.08,  0.17] |    5.00 | < .001***
volatile_acidity     |          citric_acid |    -0.55 | [-0.59, -0.52] |  -26.49 | < .001***
volatile_acidity     |       residual_sugar | 1.92e-03 | [-0.05,  0.05] |    0.08 | > .999   
volatile_acidity     |            chlorides |     0.06 | [ 0.01,  0.11] |    2.45 | 0.246    
volatile_acidity     |  free_sulfur_dioxide |    -0.01 | [-0.06,  0.04] |   -0.42 | > .999   
volatile_acidity     | total_sulfur_dioxide |     0.08 | [ 0.03,  0.13] |    3.06 | 0.051    
volatile_acidity     |              density |     0.02 | [-0.03,  0.07] |    0.88 | > .999   
volatile_acidity     |                   pH |     0.23 | [ 0.19,  0.28] |    9.66 | < .001***
volatile_acidity     |            sulphates |    -0.26 | [-0.31, -0.21] |  -10.80 | < .001***
volatile_acidity     |              alcohol |    -0.20 | [-0.25, -0.15] |   -8.25 | < .001***
volatile_acidity     |              quality |    -0.39 | [-0.43, -0.35] |  -16.95 | < .001***
citric_acid          |       residual_sugar |     0.14 | [ 0.10,  0.19] |    5.80 | < .001***
citric_acid          |            chlorides |     0.20 | [ 0.16,  0.25] |    8.32 | < .001***
citric_acid          |  free_sulfur_dioxide |    -0.06 | [-0.11, -0.01] |   -2.44 | 0.246    
citric_acid          | total_sulfur_dioxide |     0.04 | [-0.01,  0.08] |    1.42 | > .999   
citric_acid          |              density |     0.36 | [ 0.32,  0.41] |   15.66 | < .001***
citric_acid          |                   pH |    -0.54 | [-0.58, -0.51] |  -25.77 | < .001***
citric_acid          |            sulphates |     0.31 | [ 0.27,  0.36] |   13.16 | < .001***
citric_acid          |              alcohol |     0.11 | [ 0.06,  0.16] |    4.42 | < .001***
citric_acid          |              quality |     0.23 | [ 0.18,  0.27] |    9.29 | < .001***
residual_sugar       |            chlorides |     0.06 | [ 0.01,  0.10] |    2.23 | 0.366    
residual_sugar       |  free_sulfur_dioxide |     0.19 | [ 0.14,  0.23] |    7.61 | < .001***
residual_sugar       | total_sulfur_dioxide |     0.20 | [ 0.16,  0.25] |    8.29 | < .001***
residual_sugar       |              density |     0.36 | [ 0.31,  0.40] |   15.19 | < .001***
residual_sugar       |                   pH |    -0.09 | [-0.13, -0.04] |   -3.44 | 0.015*   
residual_sugar       |            sulphates | 5.53e-03 | [-0.04,  0.05] |    0.22 | > .999   
residual_sugar       |              alcohol |     0.04 | [-0.01,  0.09] |    1.68 | 0.860    
residual_sugar       |              quality |     0.01 | [-0.04,  0.06] |    0.55 | > .999   
chlorides            |  free_sulfur_dioxide | 5.56e-03 | [-0.04,  0.05] |    0.22 | > .999   
chlorides            | total_sulfur_dioxide |     0.05 | [ 0.00,  0.10] |    1.90 | 0.639    
chlorides            |              density |     0.20 | [ 0.15,  0.25] |    8.18 | < .001***
chlorides            |                   pH |    -0.27 | [-0.31, -0.22] |  -10.98 | < .001***
chlorides            |            sulphates |     0.37 | [ 0.33,  0.41] |   15.98 | < .001***
chlorides            |              alcohol |    -0.22 | [-0.27, -0.17] |   -9.06 | < .001***
chlorides            |              quality |    -0.13 | [-0.18, -0.08] |   -5.19 | < .001***
free_sulfur_dioxide  | total_sulfur_dioxide |     0.67 | [ 0.64,  0.69] |   35.84 | < .001***
free_sulfur_dioxide  |              density |    -0.02 | [-0.07,  0.03] |   -0.88 | > .999   
free_sulfur_dioxide  |                   pH |     0.07 | [ 0.02,  0.12] |    2.82 | 0.102    
free_sulfur_dioxide  |            sulphates |     0.05 | [ 0.00,  0.10] |    2.07 | 0.505    
free_sulfur_dioxide  |              alcohol |    -0.07 | [-0.12, -0.02] |   -2.78 | 0.110    
free_sulfur_dioxide  |              quality |    -0.05 | [-0.10,  0.00] |   -2.03 | 0.514    
total_sulfur_dioxide |              density |     0.07 | [ 0.02,  0.12] |    2.86 | 0.096    
total_sulfur_dioxide |                   pH |    -0.07 | [-0.12, -0.02] |   -2.66 | 0.149    
total_sulfur_dioxide |            sulphates |     0.04 | [-0.01,  0.09] |    1.72 | 0.860    
total_sulfur_dioxide |              alcohol |    -0.21 | [-0.25, -0.16] |   -8.40 | < .001***
total_sulfur_dioxide |              quality |    -0.19 | [-0.23, -0.14] |   -7.53 | < .001***
density              |                   pH |    -0.34 | [-0.38, -0.30] |  -14.53 | < .001***
density              |            sulphates |     0.15 | [ 0.10,  0.20] |    6.00 | < .001***
density              |              alcohol |    -0.50 | [-0.53, -0.46] |  -22.84 | < .001***
density              |              quality |    -0.17 | [-0.22, -0.13] |   -7.10 | < .001***
pH                   |            sulphates |    -0.20 | [-0.24, -0.15] |   -8.02 | < .001***
pH                   |              alcohol |     0.21 | [ 0.16,  0.25] |    8.40 | < .001***
pH                   |              quality |    -0.06 | [-0.11, -0.01] |   -2.31 | 0.314    
sulphates            |              alcohol |     0.09 | [ 0.04,  0.14] |    3.76 | 0.005**  
sulphates            |              quality |     0.25 | [ 0.20,  0.30] |   10.38 | < .001***
alcohol              |              quality |     0.48 | [ 0.44,  0.51] |   21.64 | < .001***

p-value adjustment method: Holm (1979)
Observations: 1599

Que exista una asociación fuerte entre dos variables no implica una relación causal. Para testear la causalidad veremos otras herramientas más adelante.

Visualización de la relación entre variables

Hemos visto que podemos crear gráficos univariados para tener una fotografía del comportamiento de una variable. De igual manera, es posible construir gráficos que muestren la asociación entre dos o más variables.

Variable 1 Variable 2 Visualización frecuente
Categórica Categórica Tablas de contingencia
Categórica Contínua Boxplot por grupos
Contínua Contínua Diagrama de dispersión

Para nuestro ejemplo del vino rojo, siguiendo las recomendaciones de la tabla, conviene crear diagramas de dispersión.

Diagrama de dispersión

Son útiles porque al cruzar los valores de un par de variables podemos encontrar posibles relaciones matemáticas entre ellas.

# install.packages("hrbrthemes")
library("hrbrthemes")

## Una relación lineal inexistente
ggplot(wine_processed, aes(x=residual_sugar, y=quality)) +
  geom_point() +
  geom_smooth(method=lm , color="red", fill="#69b3a2", se=TRUE) +
  theme_ipsum()
`geom_smooth()` using formula = 'y ~ x'

## Una relación lineal positiva
ggplot(wine_processed, aes(x=alcohol, y=quality)) +
  geom_point() +
  geom_smooth(method=lm , color="red", fill="#69b3a2", se=TRUE) +
  theme_ipsum()
`geom_smooth()` using formula = 'y ~ x'

## Una relación lineal negativa
ggplot(wine_processed, aes(x=volatile_acidity, y=quality)) +
  geom_point() +
  geom_smooth(method=lm , color="red", fill="#69b3a2", se=TRUE) +
  theme_ipsum()
`geom_smooth()` using formula = 'y ~ x'

Correlogramas

Podemos crear una visualización donde se muestren todos los posibles diagramas de dispersión entre parejas de variables con sus respectivos coeficientes de correlación.

## Instalamos la librería GGally
install.packages('GGally')
## Cargamos la librería
library('GGally')
Registered S3 method overwritten by 'GGally':
  method from   
  +.gg   ggplot2
## Creamos la visualización usando el método ggpairs()
ggpairs(
  wine_processed, 
  title="Correlograma"
  ) 
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Podemos graficar filtrando ciertas variables de interés. En este caso, vamos a remover aquellas que tengan un coeficiente de correlación menor a 0.2 con nuestra variable target (quality).

## Declaramos un vector con nuestras variables de interés
var_interes = c('volatile_acidity','citric_acid','sulphates','alcohol','quality')

## Creamos la visualización usando el método ggpairs() agregando el parámetro columns
ggpairs(
  wine_processed, 
  title="Correlograma",
  columns = var_interes
  ) 

Otra forma de visualizar la correlación entre variables.

ggcorr(
  Filter(is.numeric, wine_processed), 
  method = c("everything", "pearson"),
  size = 3
  )

De las anteriores matrices y gráficas podemos observar algunas nuevas correlaciones de interés, por ejemplo, entre el pH y la acidéz. Podemos observar además que para la variable target aproximadamente la mitad de las variables independientes correlacionan positivamente y la otra mitad negativamente.

En la práctica, se pueden seleccionar las variables independientes que tienen las medidas de asociación más altas en la medida que sospechamos que nos aportan más información. Una regla de oro sencilla es excluir variables que tengan una correlación menor (en valor absoluto) a 0.2.

Examen detallado de variables de interés

De nuestro conjunto de datos iniciales hemos detectado ciertas variables independientes o explicativas que nos pueden aportar mayor información para explicar la calidad del vino.

  • volatile_acidity
  • citric_acid
  • sulphates
  • alcohol

Adicionalmente, tenemos la calidad del vino expresada como una variable contínua (quality) y también de forma categórica (calidad).

¿Qué deberíamos hacer? Analizar el comportamiento conjunto de cada una de nuestras variables explicativas con la variable crítica. Dicho esto, vamos ahora a realizar estos cruces bivariados en tres escenarios:

Escenario 1: Asociación entre dos variables contínuas

Ya vimos cómo hacer el cálculo de coeficientes de correlación. Examinemos ahora en diagramas de dispersión las relaciones entre las variables de interés y la variable crítica cuantitativa quality.

Al ver los diagramas de dispersión, ¿es plausible pensar que hay una relación entre las variables?

volatile_acidity

ggplot(wine_processed, aes(x=volatile_acidity, y=quality)) +
  geom_point() +
  geom_smooth(method=lm , color="red", fill="#69b3a2", se=TRUE) +
  theme_ipsum()
`geom_smooth()` using formula = 'y ~ x'

citric_acid

ggplot(wine_processed, aes(x=citric_acid, y=quality)) +
  geom_point() +
  geom_smooth(method=lm , color="red", fill="#69b3a2", se=TRUE) +
  theme_ipsum()
`geom_smooth()` using formula = 'y ~ x'

sulphates

ggplot(wine_processed, aes(x=sulphates, y=quality)) +
  geom_point() +
  geom_smooth(method=lm , color="red", fill="#69b3a2", se=TRUE) +
  theme_ipsum()
`geom_smooth()` using formula = 'y ~ x'

alcohol

ggplot(wine_processed, aes(x=alcohol, y=quality)) +
  geom_point() +
  geom_smooth(method=lm , color="red", fill="#69b3a2", se=TRUE) +
  theme_ipsum()
`geom_smooth()` using formula = 'y ~ x'

En nuestro conjunto de datos original todas las variables son contínuas. El cálculo de medidas de resumen bivariadas como las covarianzas o coeficientes de correlación, así como los resúmenes gráficos vistos, nos permiten tener una idea bien formada de si existen relaciones entre las variables y el sentido de dichas relaciones.

Escenario 2: Asociación entre una variable categórica y una variable contínua

En este escenario no podemos calcular covarianzas ni correlaciones de Pearson, luego debemos disponer de otro conjunto de herramientas para testear las relaciones entre las variables.

  • Correlación biserial-puntual
  • Regresión logística
  • Prueba de Kruskall-Wallis
  • Entre otras

Por facilidad, haremos una prueba de Kruskall-Wallis cuyo p-valor testeará la hipótesis de si existe una relación significante entre las variables.

  • Hipótesis nula: las variables son independientes.
  • Hipótesis alternativa: las variables no son independientes (puede existir un efecto causal).
kruskal.test(wine_processed$volatile_acidity, wine_processed$calidad)

    Kruskal-Wallis rank sum test

data:  wine_processed$volatile_acidity and wine_processed$calidad
Kruskal-Wallis chi-squared = 168.44, df = 2, p-value < 2.2e-16
kruskal.test(wine_processed$citric_acid, wine_processed$calidad)

    Kruskal-Wallis rank sum test

data:  wine_processed$citric_acid and wine_processed$calidad
Kruskal-Wallis chi-squared = 86.083, df = 2, p-value < 2.2e-16
kruskal.test(wine_processed$sulphates, wine_processed$calidad)

    Kruskal-Wallis rank sum test

data:  wine_processed$sulphates and wine_processed$calidad
Kruskal-Wallis chi-squared = 147.44, df = 2, p-value < 2.2e-16
kruskal.test(wine_processed$alcohol, wine_processed$calidad)

    Kruskal-Wallis rank sum test

data:  wine_processed$alcohol and wine_processed$calidad
Kruskal-Wallis chi-squared = 234.32, df = 2, p-value < 2.2e-16

Visualización de las relaciones

En este caso podemos construir boxplot por grupos para cruzar la variable crítica calidad con las variables de interés.

ggplot(data = wine_processed) +
  aes(x = calidad, y = volatile_acidity) +
  geom_boxplot(fill = "#0c4c8a") +
  theme_minimal()

ggplot(data = wine_processed) +
  aes(x = calidad, y = citric_acid) +
  geom_boxplot(fill = "#0c4c8a") +
  theme_minimal()

ggplot(data = wine_processed) +
  aes(x = calidad, y = sulphates) +
  geom_boxplot(fill = "#0c4c8a") +
  theme_minimal()

ggplot(data = wine_processed) +
  aes(x = calidad, y = alcohol) +
  geom_boxplot(fill = "#0c4c8a") +
  theme_minimal()

Escenario 3: Asociación entre dos variables categóricas

En este caso conviene hacer análisis mediante tablas de contingencia, las cuales cuentan las frecuencias observadas en cada categoría.

tbl = table(wine_processed$acetico, wine_processed$calidad) 
tbl
      
       baja media alta
  bajo   34  1122  210
  alto   29   197    7
# Damos nombre a las columnas y las filas 
colnames(tbl) <- c("Calidad baja", "Calidad media", "Calidad alta")
rownames(tbl) <- c("Ácido acético bajo","Ácido acético alto")
tbl
                    
                     Calidad baja Calidad media Calidad alta
  Ácido acético bajo           34          1122          210
  Ácido acético alto           29           197            7

Al tener conformada la tabla de contingencia, la forma de revisar si existe una asociación entre las variables es por medio de una prueba de independencia X2 (Chi-Cuadrado).

La prueba indicará si dos características son independientes o tienen una asociación, de manera que las frecuencias elevadas en una de ellas suele ser acompañado con frecuencias altas en la otra.

  • Hipótesis nula: las columnas y las filas de la tabla son independientes.
  • Hipótesis alternativa: las columnas y las filas son dependientes (puede existir un efecto causal).
## Prueba Chi-Cuadrado
chisq.test(tbl)

    Pearson's Chi-squared test

data:  tbl
X-squared = 72.67, df = 2, p-value < 2.2e-16

Observaciones de cierre

Identificar las relaciones existentes entre dos o más variables es parte arte y parte ciencia, por lo que se recomienda ganar experiencia leyendo articulos cientificos y viendo soluciones a diversos problemas.

Además,

  1. Hay que procurar trabajar con variables informativas, es decir, que guarden una relación con la variable objetivo.
  2. Hay que evitar las redundancias, luego lo ideal es que nuestras variables explicativas/independientes/features sean independientes entre sí.
  3. Nuestra intuición puede fallar en dimensiones superiores a 3. En la mayoría de los casos aumentar la cantidad de variables afecta negativamente el entendimiento de un problema si no contamos con una gran cantidad de datos. Por ultimo, una cantidad controlada de variables asegura una mejor interpretabilidad de los análisis y modelos.