Visualizar correlaciones

En éste artículo vamos a ver dos formas de visualizar una matriz de correlaciones. Primero mediante el paquete corrplot, y después utilizaremos el paquete igraph para transformar nuestra matriz de correlaciones en una red.

Lo primero es preparar unos datos. Para ello, vamos a utilizar un fichero obtenido a partir de la API de la AEMET, que nos ofrece datos meteorológicos de forma gratuita.

df <- read.csv(RutaDatos)
df$presMed <- (df$presMax + df$presMin) / 2

#Seleccionamos las variables que nos interesan
df <- df[, c("tmed", "sol", "presMed", "velmedia", "prec")]

Éste dataframe contiene los datos recogidos por una estación meteorólogica. Cada fila representa los datos de un día:

Paquete corrplot

Empezamos con el paquete corrplot. Es muy sencillo de utilizar, simplemente cargamos el paquete y llamamos a la función corrplot sobre la matriz de correlaciones:

library(corrplot)

Correlaciones <- cor(df)
corrplot(Correlaciones)

Por defecto nos saca un gráfico en el que las correlaciones aparecen representadas como círculos, que son más grandes a medida que aumenta la correlación. Si la correlación es grande y positiva tendrá un color frío, mientras que si es negativa (relación inversa) tendrá un color cálido.

La función corrplot tiene muchos parámetros. Podemos consultarlos utilizando ?corrplot en la terminal de R después de haber cargado el paquete.

Gráfico en red

Para poder visualizar nuestra matriz de correlaciones como una red necesitamos la librería igraph. He empaquetado el proceso en una función para que sea más fácil de reutilizar el código.

library(igraph)
CorrNet <- function(Data, CorrMin = "sig", RandomSeed = 1){
  #Parametros:
  #data: dataframe con los datos a representar.Unicamente se seleccionaran las variables numericas
  #CorrMin: si le pasamos el valor "sig" (por defecto), muestra unicamente las correlaciones estadisticamente significativas. Si se le pasa un valor numerico, representa las correlaciones que son mayores a dicho valor (tanto las positivas como las negativas)
  #RandomSeed: semilla para el generador de numeros aleatorios. Se pueden probar varios valores hasta obtener un grafico que sea mas estetico
  
  #Cogemos las variables numericas
  Variables <- Data[, sapply(Data, is.numeric)]
  
  MatrizCor <- data.frame(round(cor(Data,
                                  use = "complete.obs"),
                              2))

  X <- cor(Data, use = "complete.obs") -> X2
  n <- nrow(Data)
  
  if(CorrMin == "sig"){
    #Nos quedamos solo con las correlaciones significativas
    #Calculamos la correlacion minima para ser significativa
    t <- qt(0.95, df = n - 2) #Calculamos el inicio de la region critica
    CorrMin <- t / sqrt(n - 2 + (t^2)) #Esta ecuacion se obtiene despejando r de la ecuacion para ver si una correlacion es significativa: t = (r * sqrt(n - 2)) / (sqrt(1 - (r ^ 2)))
  }
  
  X <- abs(X)
  
  X[X < CorrMin] = 0
  X[X > 0.999] = 0
  X[X < CorrMin] = 0
  X2[abs(X2) > 0.999] = 0
  X2[abs(X2) < CorrMin] = 0
  
  set.seed(RandomSeed) #Para que genere siempre el mismo grafico con los mismos datos
  #Creamos una red que incluye las correlaciones en valor absoluto
  network <- graph_from_adjacency_matrix(X, weighted = TRUE, 
                                         mode = "undirected", 
                                         diag = FALSE)
  #Creamos una segunda red que incluye correlaciones con signo
  network2 <- graph_from_adjacency_matrix(X2, weighted = TRUE, 
                                          mode = "undirected", 
                                          diag = FALSE)
  
  EdgeWidth <- (E(network)$weight - mean(E(network)$weight)) / E(network)$weight
  EdgeWidth <- (E(network)$weight - min(E(network)$weight)) / (max(E(network)$weight) - min(E(network)$weight))
  EdgeWidth <- 1 + (E(network)$weight * 15)
  
  #Definimos el color en funcion de si las correlaciones son positivas o negativas
  E(network)$color <- ifelse(E(network2)$weight > 0,
                              adjustcolor("#a9a9a9", alpha.f = 0.5),
                              adjustcolor("#aa00ff", alpha.f = 0.5))
  #Generamos el grafico
  plot(network,
       edge.width = EdgeWidth,
       vertex.label.family = "Helvetica",
       vertex.frame.color = NA,
       vertex.label.color = "black")
  
  par(xpd = FALSE) #Permite que los graficos con lineas de fondo se muestren bien
  
  rm(.Random.seed, 
     envir = globalenv()) #Restablecemos la semilla aleatoria
}

Si le pasamos el dataframe con los datos a ésta función seleccionará automaticamente todas las variables numéricas y obtendrá la matriz de correlaciones. Entonces, mediante la función graph_from_adjacency_matrix() del paquete igraph la convierte en una red.

Es posible que la función nos devuelva un error si no disponemos de la fuente Helvetica. Si es el caso, quitar el parámetro vertex.label.family de la función plot() o especificar otra fuente que este disponible.

CorrNet(df)

Vemos que la temperatura media esta correlacionada de forma positiva con las horas de sol, y las horas de sol están correlacionadas de forma negativa con las precipitaciones.

En el gráfico los diferentes nodos representan a nuestras variables, y el grosor de los enlaces representa la intensidad de la correlación. Por defecto representa únicamente aquellas correlaciones que son significativas, por lo que si no hay enlace entre dos variables quiere decir que la correlación no es significativa.

Además, las correlaciones que son negativas aparecen en morado, en éstos casos si el enlace es grueso quiere decir que la relación entre las dos variables es inversa y fuerte.