R: вычислить корреляцию по группам

17

В R у меня есть кадр данных, содержащий метку класса C (фактор) и два измерения, M1 и M2 . Как рассчитать соотношение между M1 и M2 в каждом классе?

В идеале я хотел бы получить фрейм данных с одной строкой для каждого класса и двумя столбцами: метка класса C и корреляция.

NPE
источник

Ответы:

20

Пакет plyr это путь.

Вот простое решение:

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)

Выход будет:

  group         COR
1     1  0.05152923
2     2 -0.15066838
3     3 -0.04717481
4     4  0.07899114
Таль Галили
источник
1
(+1) Хороший plyrпакет, не так ли? :)
Chl
Это прекрасно работает. Спасибо за указание пакета plyr! Не могли бы вы объяснить синтаксис ". (Группа)"?
NPE
2
Экс - конечно. Это означает «разделить данные по переменной между. (), И на каждом подмножестве выполнить функцию». Чтобы он включал больше переменных, вы должны просто использовать этот синтаксис:. (Var1, var2, var3). Это похоже на разрезание ваших данных по каждой комбинации уровней var1, var2 и var3. И на каждом срезе выполнять свою функцию. Этот пакет поддерживается Хэдли (также автором ggplot2), поэтому я надеюсь, что он будет развиваться.
Тал Галили
2
Да, и кстати, вы также можете использовать plyr с параллельными вычислениями на нескольких ядрах (почти автоматически), см. R-statistics.com/2010/09/…
Tal
1
Это хороший ответ, но я удивлен, что для этого нет встроенного решения, что-то вроде cor (x, y, by = z) было бы настолько интуитивно понятным ...
Waldir Leoncio
12

Если вы склонны использовать функции в базовом пакете, вы можете использовать byфункцию, а затем собрать данные:

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
источник
1
Хорошо, спасибо! Я экспериментировал с by, но не мог понять, как преобразовать результат в кадр данных.
NPE
9

Другой пример, использующий базовые пакеты и данные примера Тала:

DataCov <- do.call( rbind, lapply( split(xx, xx$group),
             function(x) data.frame(group=x$group[1], mCov=cov(x$a, x$b)) ) )
Джошуа Ульрих
источник
Элегантное решение Джошуэ. Как вы думаете, есть ли случаи, когда одно решение лучше другого?
Тал Галили
2
Я думаю, что это вопрос предпочтений. Мой пример по сути то, что plyrделает, но он дает вам более точный контроль, хотя и не так чист. Мое мнение изменилось бы, если бы у одного решения был лучший профиль времени / памяти. Я не сравнивал их, хотя.
Джошуа Ульрих
Как это возвращает корреляцию?
2

Использование data.table короче, чем dplyr

dt <- data.table(xx)
dtCor <- dt[, .(mCor = cor(M1,M2)), by=C]
jp4711
источник
0

Вот аналогичный метод, который даст вам таблицу со значениями n и p для каждой корреляции (для удобства округлены до 3 десятичных знаков):

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
источник
0

Вот более современное решение, использующее dplyr пакета (которого еще не было, когда задавался вопрос):

Построить вход:

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

Вычислить соотношения:

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

Выход:

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
Кен Уильямс
источник