R Как получить среднее значение одной переменной на основе диапазонов другой переменной? - PullRequest
6 голосов
/ 30 августа 2011

Если у меня есть серия наблюдений с двумя переменными X и Y, как я могу получить среднее значение Y на основе диапазонов переменной X?

Так, например, с некоторыми данными, такими как:

df = data.frame(x=runif(50,1,100),y=runif(50,300,700))

Как я могу получить ответ на вопрос «Когда Х равен 1–10, среднее значение у 332,4, когда Х равно 11–20, среднее значение у равно 632,3 и т. Д .... "

Ответы [ 6 ]

6 голосов
/ 30 августа 2011

Сократите x, используя cut, а затем используйте ddply в упаковке plyr:

> df$xrange <- cut(df$x, breaks=seq(0, 100, 10))

library(plyr)
ddply(df, .(xrange), summarize, mean_y=mean(y))
     xrange   mean_y
1    (0,10] 490.7571
2   (10,20] 462.6347
3   (20,30] 507.5614
4   (30,40] 482.6004
5   (40,50] 510.3081
6   (50,60] 480.7927
7   (60,70] 507.8944
8   (70,80] 458.4668
9   (80,90] 501.9672
10 (90,100] 493.4844
4 голосов
/ 30 августа 2011

Используйте cut для формирования групп и tapply для их суммирования.

df$grp <- cut(df$x, seq(0, 100, 10))
with(df, tapply(y, grp, mean))

Если вы фанат plyr, вы можете предпочесть

library(plyr)
ddply(df, .(grp), summarise, m = mean(y))

Для полноты aggregate версия

aggregate(y ~ grp, df, mean)
3 голосов
/ 30 августа 2011

Вот решение data.table

require(data.table)
data.table(df)[,list(mean_y = mean(y)), by = 'cut(x, seq(0, 100, 10))']
3 голосов
/ 30 августа 2011

Я думаю, что ваш вопрос делает ваши ответы слишком узкими. Вы должны думать о методах регрессии, чтобы суммировать совместные отношения непрерывных переменных. Построение диаграмм рассеяния и подгонка сплайнов регрессии приведет к меньшему насилию по отношению к базовым отношениям, чем указанный вами кусочный анализ.

3 голосов
/ 30 августа 2011

Одним из способов является использование cut() для создания коэффициента из переменной x, определяющего разрывы каждые десять единиц. Учитывая этот фактор, вы можете затем использовать by() или aggregate() или ... для суммирования фрейма данных, или, скорее, просто столбец y:

R> set.seed(42); DF <- data.frame(x=runif(50,1,100), y=rnorm(50,30,70))
R> summary(DF)
       x               y         
 Min.   : 1.39   Min.   :-179.5  
 1st Qu.:40.66   1st Qu.: -19.4  
 Median :64.45   Median :  39.6  
 Mean   :60.29   Mean   :  25.9  
 3rd Qu.:90.10   3rd Qu.:  74.7  
 Max.   :98.90   Max.   : 140.3  
R> DF$cx <- cut(DF$x, breaks=seq(0,100,by=10))
R> ?by
R> by(DF, DF$cx, FUN=function(z) mean(z$y))
DF$cx: (0,10]
[1] 67.8747
--------------------------------------------- 
DF$cx: (10,20]
[1] 52.9104
--------------------------------------------- 
DF$cx: (20,30]
[1] -53.8961
--------------------------------------------- 
DF$cx: (30,40]
[1] 44.1992
--------------------------------------------- 
DF$cx: (40,50]
[1] 21.7404
--------------------------------------------- 
DF$cx: (50,60]
[1] 16.2122
--------------------------------------------- 
DF$cx: (60,70]
[1] -27.0338
--------------------------------------------- 
DF$cx: (70,80]
[1] 42.283
--------------------------------------------- 
DF$cx: (80,90]
[1] 40.8042
--------------------------------------------- 
DF$cx: (90,100]
[1] 38.8917
R> 

Или используя ddply():

R> library(plyr)
R> ddply(DF, .(cx), function(z) mean(z$y))
         cx       V1
1    (0,10]  67.8747
2   (10,20]  52.9104
3   (20,30] -53.8961
4   (30,40]  44.1992
5   (40,50]  21.7404
6   (50,60]  16.2122
7   (60,70] -27.0338
8   (70,80]  42.2830
9   (80,90]  40.8042
10 (90,100]  38.8917
R> 
2 голосов
/ 30 августа 2011

Вы можете использовать tapply с pretty, чтобы установить контрольные точки для cut:

 tapply(df$y,cut(df$x,pretty(range(df$x),high.u.bias=0.1)),mean)
  (0,10]  (10,20]  (20,30]  (30,40]  (40,50]  (50,60]  (60,70]  (70,80] 
496.9840 510.4164 502.4092 492.5806 493.3364 549.5207 507.4511 472.3391 
 (80,90] (90,100] 
479.8795 482.6728 

aggregate также можно использовать:

aggregate(df$y,list(cut(df$x,pretty(range(df$x),high.u.bias=0.1))),FUN=mean)
    Group.1        x
1    (0,10] 496.9840
2   (10,20] 510.4164
3   (20,30] 502.4092
4   (30,40] 492.5806
5   (40,50] 493.3364
6   (50,60] 549.5207
7   (60,70] 507.4511
8   (70,80] 472.3391
9   (80,90] 479.8795
10 (90,100] 482.6728
...