2012-01-09 15 views

Respuesta

17

¿Qué tal esto para una solución de base R:

df <- data.frame(group = rep(c("G1", "G2"), each = 10), 
       var1 = rnorm(20), 
       var2 = rnorm(20)) 

r <- by(df, df$group, FUN = function(X) cor(X$var1, X$var2, method = "spearman")) 
# df$group: G1 
# [1] 0.4060606 
# ------------------------------------------------------------ 
# df$group: G2 
# [1] 0.1272727 

Y luego, si desea que los resultados en forma de un hoja.de.datos:

data.frame(group = dimnames(r)[[1]], corr = as.vector(r)) 
# group  corr 
# 1 G1 0.4060606 
# 2 G2 0.1272727 

EDITAR: Si prefiere una solución basada en plyr, aquí hay una:

library(plyr) 
ddply(df, .(group), summarise, "corr" = cor(var1, var2, method = "spearman")) 
+0

Gracias Josh por la pronta respuesta. ¡Todos trabajaron! ;-) – user1009166

+0

(+1) Buena respuesta. ¿Qué pasa con 'r <- by (df, df $ group, FUN = function (X) cor (df [, - 1], method =" spearman "))'? – MYaseen208

+0

@ MYaseen208. Gracias. El código que das devuelve algo ligeramente diferente. No sé su nombre, pero es como una matriz de varianza-covarianza, excepto con una correlación en cada celda. El código que utilicé devuelve, en cambio, una correlación escalar única para cada grupo. –

5

Ésta es otra manera de hacerlo:

# split the data by group then apply spearman correlation 
# to each element of that list 
j <- lapply(split(df, df$group), function(x){cor(x[,2], x[,3], method = "spearman")}) 

# Bring it together 
data.frame(group = names(j), corr = unlist(j), row.names = NULL) 

Comparando mi método, el método de Josh, y la solución plyr usando rbenchmark:

Dason <- function(){ 
    # split the data by group then apply spearman correlation 
    # to each element of that list 
    j <- lapply(split(df, df$group), function(x){cor(x[,2], x[,3], method = "spearman")}) 

    # Bring it together 
    data.frame(group = names(j), corr = unlist(j), row.names = NULL) 
} 

Josh <- function(){ 
    r <- by(df, df$group, FUN = function(X) cor(X$var1, X$var2, method = "spearman")) 
    data.frame(group = attributes(r)$dimnames[[1]], corr = as.vector(r)) 
} 

plyr <- function(){ 
    ddply(df, .(group), summarise, "corr" = cor(var1, var2, method = "spearman")) 
} 


library(rbenchmark) 
benchmark(Dason(), Josh(), plyr()) 

que da la salida

> benchmark(Dason(), Josh(), plyr()) 
    test replications elapsed relative user.self sys.self user.child sys.child 
1 Dason()   100 0.19 1.000000  0.19  0   NA  NA 
2 Josh()   100 0.24 1.263158  0.22  0   NA  NA 
3 plyr()   100 0.51 2.684211  0.52  0   NA  NA 

Parece que mi método es un poco más rápido pero no mucho. Creo que el método de Josh es un poco más intuitivo. La solución plyr es la más fácil de codificar pero no es la más rápida (¡pero seguro que es mucho más conveniente)!

+0

Gracias por pensar en probarlos con 'benchmark'. +1 por juntar eso. Tengo un par de comentarios adicionales. (1) En las llamadas repetidas al punto de referencia, la diferencia habitual entre los enfoques 'lapply (split (...)' y 'by (...)' es más o menos del 7-10%. (2) Si está interesado Para continuar con esto, probablemente sea más útil probar los tres métodos en algunos marcos de datos grandes, con más de 1000 grupos y filas de 1e6. ¡Salud! –

+0

¡Gracias a Dason también por su tiempo! – user1009166

3

Si desea una solución eficiente para grandes cantidades de grupos, entonces data.table es el camino a seguir.

library(data.table) 
DT <- as.data.table(df) 
setkey(DT, group) 
DT[,list(corr = cor(var1,var2,method = 'spearman')), by = group] 
+0

+1 Tenga en cuenta que 'setkey 'es opcional. Keyed-by es más rápido que deshabilitado para grandes conjuntos de datos (por ejemplo, 1e7 filas +) donde también hay muchos grupos grandes. Unkeyed-by ya es bastante rápido. –

Cuestiones relacionadas