基础R的Repo1
函数有自己的特殊输出类“by”,它带有特殊的打印格式。为了便于将结果放入表中,我真的希望将“by”的结果排列为数据框,其中的列指示用于子集的因子的级别:
by
当b <- by(mtcars$mpg, list(mtcars$vs, mtcars$am), function(x) c(length(x), mean(x)))
some_reformatting_function(b)
# am vs length mean
#1 0 0 12 15.05000
#2 0 1 7 20.74286
#3 1 0 6 19.75000
#4 1 1 7 28.37143
的{{1}}参数的长度为1时,我可以通过强制FUN
的类为数字,然后by
来一起破解它。但是当b
返回更长的向量时,这种方法不起作用。有什么建议吗?
答案 0 :(得分:3)
dplyr
非常适合这些任务,而且非常容易学习。
by
生成一种棘手的格式。如果没有来自by
的其他软件包,您希望获得目标的一种方法是再次使用by
以一致的方式组合这些因素。
b <- by(mtcars$mpg, list(mtcars$vs, mtcars$am), function(x) c(length(x), mean(x)))
i <- by(cbind(mtcars$vs, mtcars$am), list(mtcars$vs, mtcars$am), function(x) c(x[1,1], x[1,2]))
i <- unlist(i)
b <- unlist(b)
i <- matrix(i, ncol = 2)
b <- matrix(b, ncol = 2)
d <- data.frame(i, b)
names(d) <- c("am", "vs", "length", "mean")
d
# am vs length mean
# 1 0 0 12.00000 6.00000
# 2 0 1 15.05000 19.75000
# 3 1 1 7.00000 7.00000
# 4 0 1 20.74286 28.37143
您还可以合并上面的by
函数调用。
答案 1 :(得分:2)
1)汇总对于问题中的具体示例,通常会在基数R而不是aggregate
中使用by
:
aggregate(mpg ~ vs + am, mtcars, function(x) c(length = length(x), mean = mean(x)))
,并提供:
vs am mpg.length mpg.mean
1 0 0 12.00000 15.05000
2 1 0 7.00000 20.74286
3 0 1 6.00000 19.75000
4 1 1 7.00000 28.37143
2)依据如果实际问题更复杂,您确实需要使用by
,那么格式化by
对象就像问题{{1}一样应该重写语句以对整个数据帧进行操作,并在函数中包含余量变量:
by
,并提供:
fun <- function(x) with(x,
data.frame(vs = vs[1], am = am[1], length = length(mpg), mean = mean(mpg)))
do.call("rbind", by(mtcars, mtcars[c("vs", "am")], fun))
3)使用问题中的b 虽然不推荐这样做,但可以改进问题中的 vs am length mean
1 0 0 12 15.05000
2 1 0 7 20.74286
3 0 1 6 19.75000
4 1 1 7 28.37143
。我们使用更紧凑的表示法和添加名称稍微重述了b
。在这种情况下,我意识到b
对象"by"
也是一个2x2矩阵,我们可以将其转换为数据框,将其转置为矩阵b
,从m
获取边距行名称将b
和margins
放在一起:
cbind
,并提供:
b <- by(mtcars$mpg, mtcars[c("vs", "am")], function(x) c(length=length(x), mean=mean(x)))
m <- t(do.call("data.frame", c(as.data.frame.matrix(b), check.names = FALSE)))
margins <- read.table(text = rownames(m), sep = ".", col.names = rev(names(dimnames(b))))
cbind(margins, m)
4)sqldf 使用data.table,doBy,dplyr和sqldf等多个软件包中的任何一个也可以解决这个特殊问题。这里我们展示一个sqldf解决方案:
am vs length mean
0.0 0 0 12 15.05000
0.1 0 1 7 20.74286
1.0 1 0 6 19.75000
1.1 1 1 7 28.37143
,并提供:
library(sqldf)
sqldf("select vs, am, count(*) length, avg(mpg) mean
from mtcars
group by vs, am")
答案 2 :(得分:1)
在我发布之后发现了一个潜行的怀疑,答案可能是“只是使用(Hadley的一个包)”,果然,ddply
的默认输出格式更明智我想要的数据框架。
plyr::ddply(mtcars, .variables = c("vs", "am"), function(x) c(nrow(x), mean(x[["mpg"]])))
# vs am V1 V2
#1 0 0 12 15.05000
#2 0 1 6 19.75000
#3 1 0 7 20.74286
#4 1 1 7 28.37143
答案 3 :(得分:1)
data.table
解决方案
library(data.table)
mtcars <- as.data.table(mtcars)
mtcars[, .(length = .N, mean = mean(mpg)), by = .(vs, am)][order(am,vs)]
(感谢@ thelatemail&#39的建议,它更整洁。)
以下是输出
vs am length mean
1: 0 0 12 15.05000
2: 1 0 7 20.74286
3: 0 1 6 19.75000
4: 1 1 7 28.37143
答案 4 :(得分:0)
dplyr
版本是:
group_by(mtcars, am, vs) %>%
summarize(n = n(),
mean_mpg = mean(mpg))