2013-07-24 61 views
3

说我有这个data.frame集团data.frame由多列

data <- data.frame(foo = c(1, 1, 2, 2), 
        bar = c(10,10,10,20), 
        baz = c(1, 2, 3, 4), 
        qux = c(5, 6, 7, 8)) 

我想这组由foobar列在这个到达:

expected <- list(
    data.frame(foo = c(1, 1), 
      bar = c(10, 10), 
      baz = c(1, 2), 
      qux = c(5, 6)), 
    data.frame(foo = 2, 
      bar = 10, 
      baz = 3, 
      qux = 7), 
    data.frame(foo = 2, 
      bar = 20, 
      baz = 4, 
      qux = 8) 
) 

我可以生成每组有一行,但我找不到MATCH函数;当给定具有列foo,bar,baz,qux的输入帧和具有列foo,bar的过滤器帧时,返回foo,bar单元格的内容匹配的行。

groups <- unique(data[c("foo","bar")]) 
MATCH(data, groups[1,]) == expected[[1]] 
MATCH(data, groups[2,]) == expected[[2]] 
MATCH(data, groups[3,]) == expected[[3]] 

或者更高的水平GROUP函数,它只是返回帧,一个列表,其中列给出的匹配:

GROUP(data, by=c("foo","bar")) == expected 

我来到那个最接近的是

out <- aggregate(. ~ foo + bar, data, list) 

凡单元格baz,qux是列表:

> out 
    foo bar baz qux 
1 1 10 1, 2 5, 6 
2 2 10 3 7 
3 2 20 4 8 
> class(out[,"baz"]) 
[1] "list" 

因此,每个组都是out中的一行,但是如何再次展开此操作,以便out[1,]成为两行的数据帧,如expected[[1]]

回答

7

看起来你只是需要split

选项1:保留“foo”和“bar”组合的所有“级别”,即使它产生空的data.frame

> split(data, list(data$foo, data$bar)) 
$`1.10` 
    foo bar baz qux 
1 1 10 1 5 
2 1 10 2 6 

$`2.10` 
    foo bar baz qux 
3 2 10 3 7 

$`1.20` 
[1] foo bar baz qux 
<0 rows> (or 0-length row.names) 

$`2.20` 
    foo bar baz qux 
4 2 20 4 8 

选项2:丢弃空“foo”和“棒”相结合的“级别” - 就像你在预期的输出做。

> split(data, list(data$foo, data$bar), drop=TRUE) 
$`1.10` 
    foo bar baz qux 
1 1 10 1 5 
2 1 10 2 6 

$`2.10` 
    foo bar baz qux 
3 2 10 3 7 

$`2.20` 
    foo bar baz qux 
4 2 20 4 8 
+0

沿着相同的路线另一个选择是'拆分(数据,粘贴(数据$ foo,数据$ bar))' – eddi

+0

@eddi,当然。我只是按照设计/记录的方式使用'split',在分割多个因素时提供了一个分组因子列表。 'paste'解决方案不需要使用'drop'。你看到'paste'优于'interaction'(这是'split'默认使用的)的优点吗?我似乎记得在SO上看到了一个答案,其中'paste'比'interaction'快得多,但现在找不到它。 – A5C1D2H2I1M1N2O1R2T1

+0

afaik'interaction'只是增加了很多额外的东西(然后最终做了'paste'),这对于这种特殊情况来说并不需要 – eddi

3

plyrdlply设计出于这样的目的:

require(plyr)  
dlply(data , .(foo , bar)) 

$`1.10` 
    foo bar baz qux 
1 1 10 1 5 
2 1 10 2 6 

$`2.10` 
    foo bar baz qux 
1 2 10 3 7 

$`2.20` 
    foo bar baz qux 
1 2 20 4 8 
+0

I我们从来没有完全掌握过“plyr”,但是+1分享替代品! – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto谢谢。我正在等待eddi发布'data.table'解决方案.... :-) –

+0

我看到了你的表情符号,但data.table'会从这样的结构中获益吗?我不这么认为。我猜想''钥匙在很大程度上照顾到了这一点。 – A5C1D2H2I1M1N2O1R2T1

0

试试这个,这就好比@阿难的解决方案,但使用interaction

> split(data,interaction(data$foo,data$bar)) 
$`1.10` 
    foo bar baz qux 
1 1 10 1 5 
2 1 10 2 6 

$`2.10` 
    foo bar baz qux 
3 2 10 3 7 

$`1.20` 
[1] foo bar baz qux 
<0 rækker> (eller 0-længde row.names) 

$`2.20` 
    foo bar baz qux 
4 2 20 4 8 

> split(data,interaction(data$foo,data$bar), drop=TRUE) 
$`1.10` 
    foo bar baz qux 
1 1 10 1 5 
2 1 10 2 6 

$`2.10` 
    foo bar baz qux 
3 2 10 3 7 

$`2.20` 
    foo bar baz qux 
4 2 20 4 8 
+2

你认为这是与@AnandaMahto的表面上相同的答案,但使用不同的方法来创建分组变量它可能是更好地作为评论或编辑Ananda的答案? –

+0

@ Simono101我发布了一个初始版本,当他发布他的。然后我看到他的回答后编辑了......所以......我应该怎么做...... – Thomas

+0

@ SimonO101,更好的方法是查看“split.default”的代码或帮助页面中的“f”的解释为“分裂”。 'f'参数恰恰是'交互作用'。 – A5C1D2H2I1M1N2O1R2T1