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


17

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

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

Ответы:


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)

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]

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))))
}

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.