R: oblicz korelację według grup

17

W R mam ramkę danych zawierającą etykietę klasy C (współczynnik) i dwa pomiary, M1 i M2 . Jak obliczyć korelację między M1 i M2 w każdej klasie?

Idealnie byłoby odzyskać ramkę danych z jednym wierszem dla każdej klasy i dwiema kolumnami: etykietą klasy C i korelacją.

NPE
źródło

Odpowiedzi:

20

Pakiet plyr jest najlepszym rozwiązaniem.

Oto proste rozwiązanie:

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)

Dane wyjściowe będą:

  group         COR
1     1  0.05152923
2     2 -0.15066838
3     3 -0.04717481
4     4  0.07899114
Tal Galili
źródło
1
(+1) Niezła plyrpaczka, prawda? :)
chl
To działa świetnie. Dziękujemy za wskazanie pakietu plyr! Czy możesz wyjaśnić składnię „. (Group)”?
NPE
2
aix - jasne. Oznacza to „podziel dane według zmiennej pomiędzy. () I na każdym podzbiorze wykonaj funkcję”. Aby mieć więcej zmiennych, należy po prostu użyć tej składni:. (Var1, var2, var3). To jest jak cięcie danych o każdą kombinację poziomów var1, var2 i var3. I na każdym cięciu, aby wykonać swoją funkcję. Ten pakiet jest utrzymywany przez Hadleya (również autora ggplot2), więc ufam, że będzie się rozwijał.
Tal Galili
2
Aha i BTW, możesz również użyć plyr z obliczeniami równoległymi na kilku rdzeniach (prawie automatycznie), patrz: r-statistics.com/2010/09/09/…
Tal Galili
1
To ładna odpowiedź, ale dziwi mnie, że nie ma na to wbudowanego rozwiązania, coś w rodzaju cor (x, y, by = z) byłoby tak intuicyjne ...
Waldir Leoncio
12

Jeśli masz skłonność do korzystania z funkcji w pakiecie podstawowym, możesz użyć byfunkcji, a następnie ponownie złożyć dane:

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
źródło
1
Fajnie dzięki! Eksperymentowałem by, ale nie mogłem wymyślić, jak przekształcić wynik w ramkę danych.
NPE
9

Kolejny przykład z wykorzystaniem pakietów podstawowych i przykładowych danych Tala:

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
źródło
Eleganckie rozwiązanie Joshue. Czy uważasz, że zdarzają się przypadki, gdy jedno rozwiązanie jest lepsze od drugiego?
Tal Galili
2
Myślę, że to kwestia preferencji. Mój przykład jest zasadniczo tym, co plyrrobi, ale daje lepszą kontrolę, choć nie jest tak czysty. Moja opinia zmieniłaby się, gdyby jedno rozwiązanie miało lepszy profil czas / pamięć. Nie porównałem ich jednak.
Joshua Ulrich
Jak to zwraca korelację?
2

Korzystanie z data.table jest krótsze niż dplyr

dt <- data.table(xx)
dtCor <- dt[, .(mCor = cor(M1,M2)), by=C]
jp4711
źródło
0

Oto podobna metoda, która da również tabelę z wartościami n i p dla każdej korelacji (dla wygody zaokrąglona do 3 miejsc po przecinku):

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
źródło
0

Oto bardziej nowoczesne rozwiązanie, wykorzystujące dplyrpakiet (który jeszcze nie istniał, gdy zadano pytanie):

Skonstruuj dane wejściowe:

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

Oblicz korelacje:

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

Wyjście:

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
źródło