假设我有这个数据框:
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 ))
我希望按照 foo
和 bar
列进行分组,得到以下结果:
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]]
一样?
split(data, paste(data$foo, data$bar))
。 - eddisplit
的设计/文档使用它,当分割因素超过一个时,提供一个分组因素的list
。paste
解决了使用drop
的需要。您是否认为paste
比interaction
更有优势(这是split
默认使用的)?我似乎记得在SO上看到过一个答案,其中paste
比interaction
快得多,但现在找不到了。 - A5C1D2H2I1M1N2O1R2T1interaction
只是添加了很多额外的东西(最终执行paste
),而这些在这种特定情况下并不需要。 - eddisplit
。 - pascal