2011-04-26 98 views
10

根據分組因子,按行拆分data.frame相當容易。但是,我如何按列分割並可能應用一個函數?使用分組變量按列分割數據幀

my.df <- data.frame(a = runif(10), 
     b = runif(10), 
     c = runif(10), 
     d = runif(10)) 
grp <- as.factor(c(1,1, 2,2)) 

我想要的是一個羣體的平均值。

我到目前爲止是一個窮人的申請。

lapply(as.list(as.numeric(levels(grp))), FUN = function(x, cn, data) { 
      rowMeans(data[grp %in% x]) 
     }, cn = grp, data = my.df) 

編輯 謝謝大家參與。我跑了10次重複*,我的工作數據幀大約有22000行。這些都是幾秒鐘內的結果。

Roman: 2.19 
Joris: 4.60 
Joris #2: 3.79 #changed sapply to lapply as suggested by Joris in the [R chatroom][1]. 
Gavin: 4.70 
James & EDi: > 200 # * ran only one replicate due to the large order of magnitude difference 

讓我感到奇怪的是,目前沒有包裝功能。也許有一天我們能做

apply(X = my.df, MARGIN = 3, INDEX = my.groups, FUN = mean) # :) 
+0

你的數據幀具有10行,和GRP具有4個值。他們應該如何匹配? – hadley 2011-04-26 13:14:09

+0

@hadley:數據框有4列,grp有4個值,所以匹配... – 2011-04-26 13:26:54

+0

@hadley,我想分割列,而不是行,所以我應該匹配長度(my.df)==長度(GRP)。 – 2011-04-26 13:35:18

回答

6

可以使用同樣的邏輯,但在一個更方便的形式:

sapply(levels(grp),function(x)rowMeans(my.df[which(grp==x)])) 
+0

該版本比我向Joris演示的版本快了〜x2。索引通常是。+1 – 2011-04-26 13:45:38

0

這工作正常?

aggregate(t(my.df), list(grp), mean) 
+0

+1好用的聚合! – Ramnath 2011-04-26 12:21:42

+0

這種方法默默地忽略了grp向量不正確的事實。 – hadley 2011-04-26 13:15:20

0

如何:

my.df2 <- data.frame(t(my.df),grp) 
aggregate(.~grp,my.df2,mean) 
+0

不好意思,但是這個解決方案在我的工作數據集上花費了太多時間(請參閱我的更新答案)。 – 2011-04-26 14:08:26

5

轉換my.df到列表和拆分,然後應用你的函數列表的組件的每個子集,後強迫到數據幀:

lapply(split(as.list(my.df), grp), function(x) rowMeans(as.data.frame(x))) 

這給:

> lapply(split(as.list(my.df), grp), function(x) rowMeans(as.data.frame(x))) 
$`1` 
[1] 0.8229189 0.4901288 0.2057578 0.6531641 0.3897858 0.4225179 
[7] 0.3905410 0.3928784 0.1715857 0.3973192 

$`2` 
[1] 0.61348623 0.61229702 0.31938521 0.28325342 0.25857158 
[6] 0.49071991 0.01179999 0.57639186 0.38407240 0.17467337 

即相當於@羅馬的「窮人的申請」:

> roman <- lapply(as.list(as.numeric(levels(grp))), 
+     FUN = function(x, cn, data) { 
+      rowMeans(data[grp %in% x]) 
+     }, cn = grp, data = my.df) 
> gavin <- lapply(split(as.list(my.df), grp), 
+     function(x) rowMeans(as.data.frame(x))) 
> all.equal(roman, gavin) 
[1] "names for current but not for target" 

除了成分上的名字。

+0

這種方法默默地忽略了grp向量不正確的事實。 – hadley 2011-04-26 13:14:59

+0

@hadley什麼是不正確的長度? 'grp'長度爲4,'as.list(my.df)'也是長度爲4的。爲什麼這不等於'split(1:4,grp)'?一個列表畢竟是一個向量。 – 2011-04-26 13:35:56

+0

@hadley給了你對Q的評論,我想你已經誤解了需要什麼。 – 2011-04-26 14:16:29