R: calcular correlación por grupo

17

En R, tengo un marco de datos que comprende una etiqueta de clase C (un factor) y dos mediciones, M1 y M2 . ¿Cómo calculo la correlación entre M1 y M2 dentro de cada clase?

Idealmente, obtendría un marco de datos con una fila para cada clase y dos columnas: la etiqueta de clase C y la correlación.

NPE
fuente

Respuestas:

20

El paquete plyr es el camino a seguir.

Aquí hay una solución simple:

xx <- data.frame(group = rep(1:4, 100), a = rnorm(400) , b = rnorm(400) )
head(xx)

require(plyr)
func <- function(xx)
{
return(data.frame(COR = cor(xx$a, xx$b)))
}

ddply(xx, .(group), func)

El resultado será:

  group         COR
1     1  0.05152923
2     2 -0.15066838
3     3 -0.04717481
4     4  0.07899114
Tal Galili
fuente
1
(+1) Buen plyrpaquete, ¿no? :)
chl
Esto funciona muy bien. ¡Gracias por señalar el paquete plyr! ¿Podría explicar la sintaxis ". (Grupo)"?
NPE
2
aix - claro. Significa "dividir los datos por la variable entre. (), Y en cada subconjunto realizar la función". Para que incluya más variables, simplemente debe usar esta sintaxis:. (Var1, var2, var3). Lo que es como cortar sus datos por cada combinación de niveles de var1, var2 y var3. Y en cada corte para realizar su función. Hadley (también el autor de ggplot2) mantiene este paquete, por lo que confío en que seguirá desarrollándose.
Tal Galili
2
Ah, y por cierto, también podría usar plyr con una computación paralela en varios núcleos (casi automáticamente), consulte: r-statistics.com/2010/09/…
Tal Galili
1
Esa es una buena respuesta, pero me sorprende que no haya una solución integrada para esto, algo como cor (x, y, by = z) sería tan intuitivo ...
Waldir Leoncio
12

Si está inclinado a usar funciones en el paquete base, puede usar la byfunción y luego volver a ensamblar los datos:

xx <- data.frame(group = rep(1:4, 100), a = rnorm(400) , b = rnorm(400) )
head(xx)

# This returns a "by" object
result <- by(xx[,2:3], xx$group, function(x) {cor(x$a, x$b)})

# You get pretty close to what you want if you coerce it into a data frame via a matrix
result.dataframe <- as.data.frame(as.matrix(result))

# Add the group column from the row names
result.dataframe$C <- rownames(result)
hgcrpd
fuente
1
¡Genial gracias! He estado experimentando con by, pero no pude encontrar la manera de transformar el resultado en un marco de datos.
NPE
9

Otro ejemplo usando paquetes base y datos de ejemplo de Tal:

DataCov <- do.call( rbind, lapply( split(xx, xx$group),
             function(x) data.frame(group=x$group[1], mCov=cov(x$a, x$b)) ) )
Joshua Ulrich
fuente
Elegante solución Joshue. ¿Crees que hay casos en que una solución es mejor que otra?
Tal Galili
2
Creo que es una cuestión de preferencia. Mi ejemplo es esencialmente lo que plyrhace, pero te da un control más fino, aunque no es tan limpio. Mi opinión cambiaría si una solución tuviera un mejor perfil de tiempo / memoria. Sin embargo, no los he comparado.
Joshua Ulrich
¿Cómo devuelve esto la correlación?
2

Usar data.table es más corto que dplyr

dt <- data.table(xx)
dtCor <- dt[, .(mCor = cor(M1,M2)), by=C]
jp4711
fuente
0

Aquí hay un método similar que también le dará una tabla con los valores de n y p para cada correlación (redondeado a 3 decimales por conveniencia):

library(Hmisc)
corrByGroup <- function(xx){
  return(data.frame(cbind(correl = round(rcorr(xx$a, xx$b)$r[1,2], digits=3),
                          n = rcorr(xx$a, xx$b)$n[1,2],
                          pvalue = round(rcorr(xx$a, xx$b)$P[1,2], digits=3))))
}
AnnaCM
fuente
0

Aquí hay una solución más moderna, usando el dplyrpaquete (que aún no existía cuando se hizo la pregunta):

Construir la entrada:

xx <- data.frame(group = rep(1:4, 100), a = rnorm(400) , b = rnorm(400) )

Calcule las correlaciones:

library(dplyr)
xx %>%
  group_by(group) %>%
  summarize(COR=cor(a,b))

La salida:

Source: local data frame [4 x 2]

  group         COR
  (int)       (dbl)
1     1  0.05112400
2     2  0.14203033
3     3 -0.02334135
4     4  0.10626273
Ken Williams
fuente