base R中的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当by的FUN参数的长度为1时,我可以通过强制b的类为数字,然后melting来实现。但是当FUN返回一个更长的向量时,这种方法就不起作用了。有什么建议吗?
发布于 2016-03-29 07:31:10
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函数调用。
发布于 2016-03-29 07:38:50
1)聚合对于问题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.371432)如果实际问题更复杂,并且您确实需要使用by来格式化by对象,则应重写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))给予:
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.371433)通过使用问题中的b,虽然不建议这样做,但可以对问题中的b进行改革。我们稍微重述了b,使用了更紧凑的表示法并添加了名称。意识到"by"对象b也是一个2x2矩阵,在这种情况下,我们可以将其转换为数据帧,转置给矩阵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)给予:
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.371434) sqldf也可以使用诸如data.table、doBy、dplyr和sqldf等许多包中的任何一个来解决这个特定问题。这里我们展示一个sqldf解决方案:
library(sqldf)
sqldf("select vs, am, count(*) length, avg(mpg) mean
from mtcars
group by vs, am")给予:
vs am length mean
1 0 0 12 15.05000
2 0 1 6 19.75000
3 1 0 7 20.74286
4 1 1 7 28.37143发布于 2016-03-29 07:29:18
在我发布这篇文章后,我暗自怀疑答案可能是“只使用(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.37143https://stackoverflow.com/questions/36272717
复制相似问题