如何以长格式显示“by”对象

时间:2016-03-28 23:08:57

标签: r melt

基础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返回更长的向量时,这种方法不起作用。有什么建议吗?

5 个答案:

答案 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获取边距行名称将bmargins放在一起:

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))