首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何以长格式显示"by“对象

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

Stack Overflow用户
提问于 2016-03-29 07:08:57
回答 5查看 62关注 0票数 2

base R中的by函数有自己的特殊输出类"by",该类带有特殊的打印格式。为了便于将结果放入表中,我真的希望将"by“的结果排列为一个数据框,其中包含指示用于子集的因子的级别的列:

代码语言:javascript
复制
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

byFUN参数的长度为1时,我可以通过强制b的类为数字,然后melting来实现。但是当FUN返回一个更长的向量时,这种方法就不起作用了。有什么建议吗?

EN

回答 5

Stack Overflow用户

发布于 2016-03-29 07:31:10

dplyr非常适合于这些任务,并且非常容易学习。

by产生了一种难以处理的格式。在没有来自by的其他包的情况下,一种方法是再次使用by以一致的方式组合这些因素。

代码语言:javascript
复制
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函数调用。

票数 3
EN

Stack Overflow用户

发布于 2016-03-29 07:38:50

1)聚合对于问题1中的特定示例,通常会在基数R中使用aggregate,而不是by

代码语言:javascript
复制
aggregate(mpg ~ vs + am, mtcars, function(x) c(length = length(x), mean = mean(x)))

给予:

代码语言:javascript
复制
  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对象,则应重写by语句以在整个数据帧上操作,并在函数中包括边距变量:

代码语言:javascript
复制
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))

给予:

代码语言:javascript
复制
  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

3)通过使用问题中的b,虽然不建议这样做,但可以对问题中的b进行改革。我们稍微重述了b,使用了更紧凑的表示法并添加了名称。意识到"by"对象b也是一个2x2矩阵,在这种情况下,我们可以将其转换为数据帧,转置给矩阵m,从b的行名中获得边距,将marginscbind的所有内容放在一起:

代码语言:javascript
复制
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)

给予:

代码语言:javascript
复制
    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

4) sqldf也可以使用诸如data.table、doBy、dplyr和sqldf等许多包中的任何一个来解决这个特定问题。这里我们展示一个sqldf解决方案:

代码语言:javascript
复制
library(sqldf)
sqldf("select vs, am, count(*) length, avg(mpg) mean 
       from mtcars 
       group by vs, am")

给予:

代码语言:javascript
复制
  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
票数 2
EN

Stack Overflow用户

发布于 2016-03-29 07:29:18

在我发布这篇文章后,我暗自怀疑答案可能是“只使用(Hadley的一个软件包)”,果然,ddply的默认输出格式是我想要的更合理的数据帧。

代码语言:javascript
复制
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
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36272717

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档