R: calculer la corrélation par groupe

17

Dans R, j'ai une trame de données comprenant une étiquette de classe C (un facteur) et deux mesures, M1 et M2 . Comment calculer la corrélation entre M1 et M2 au sein de chaque classe?

Idéalement, je récupérerais un bloc de données avec une ligne pour chaque classe et deux colonnes: l'étiquette de classe C et la corrélation.

NPE
la source

Réponses:

20

Le paquet plyr est la voie à suivre.

Voici une solution 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)

La sortie sera:

  group         COR
1     1  0.05152923
2     2 -0.15066838
3     3 -0.04717481
4     4  0.07899114
Tal Galili
la source
1
(+1) Bon plyrpaquet, non? :)
chl
Cela fonctionne très bien. Merci d'avoir signalé le paquet plyr! Pourriez-vous expliquer la syntaxe ". (Groupe)"?
NPE du
2
aix - bien sûr. Cela signifie "diviser les données par la variable entre. (), Et sur chaque sous-ensemble exécuter la fonction". Pour qu'il comprenne plus de variables, vous devez simplement utiliser cette syntaxe:. (Var1, var2, var3). Ce qui revient à couper vos données par chaque combinaison de niveaux de var1, var2 et var3. Et sur chaque coupe pour remplir votre fonction. Ce paquet est maintenu par Hadley (également l'auteur de ggplot2), donc j'espère qu'il continuera à se développer.
Tal Galili
2
Oh, et BTW, vous pouvez également utiliser plyr avec un calcul parallèle sur plusieurs cœurs (presque automatiquement), voir: r-statistics.com/2010/09/…
Tal Galili
1
C'est une bonne réponse, mais je suis étonné qu'il n'y ait pas de solution intégrée pour cela, quelque chose comme cor (x, y, by = z) serait si intuitif ...
Waldir Leoncio
12

Si vous êtes enclin à utiliser des fonctions dans le package de base, vous pouvez utiliser la byfonction, puis réassembler les données:

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
la source
1
Bien, merci! J'ai expérimenté by, mais je n'ai pas réussi à comprendre comment transformer le résultat en un bloc de données.
NPE
9

Un autre exemple utilisant des packages de base et les données d'exemple 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
la source
Solution élégante Joshue. Pensez-vous qu'il existe des cas où une solution est meilleure qu'une autre?
Tal Galili
2
Je pense que c'est une question de préférence. Mon exemple est essentiellement ce qui plyrfait mais il vous donne un contrôle plus fin, bien qu'il ne soit pas aussi propre. Mon opinion changerait si une solution avait un meilleur profil temps / mémoire. Je ne les ai cependant pas comparés.
Joshua Ulrich
Comment cela renvoie-t-il la corrélation?
2

L'utilisation de data.table est plus courte que dplyr

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

Voici une méthode similaire qui vous donnera également un tableau avec les valeurs n et p pour chaque corrélation (arrondi à 3 décimales pour plus de commodité):

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
la source
0

Voici une solution plus moderne, utilisant le dplyrpackage (qui n'existait pas encore lorsque la question a été posée):

Construisez l'entrée:

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

Calculez les corrélations:

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

Le résultat:

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
la source