在R中将一个"by"对象转换为数据框

19

我在R中使用“by”函数来切分数据框并对不同部分应用函数,例如:

pairwise.compare <- function(x) {
Nright <- ...
Nwrong <- ...
Ntied <- ...
return(c(Nright=Nright, Nwrong=Nwrong, Ntied=Ntied))
}
Z.by <- by(rankings, INDICES=list(rankings$Rater, rankings$Class), FUN=pairwise.compare)

结果(Z.by)看起来像这样:

: 4 
: 357 
Nright Nwrong Ntied
     3      0     0
------------------------------------------------------------
: 8 
: 357 
NULL
------------------------------------------------------------
: 10 
: 470 
Nright Nwrong Ntied
     3      4     1 
------------------------------------------------------------ 
: 11 
: 470 
Nright Nwrong Ntied
    12      4     1

我想要的是将这个结果转换成数据框(不包含NULL项),使其看起来像这样:

  Rater Class Nright Nwrong Ntied
1     4   357      3      0     0
2    10   470      3      4     1
3    11   470     12      4     1

我该如何做到这一点?

5个回答

20
< p > by 函数返回一个列表,所以你可以像这样做:

data.frame(do.call("rbind", by(x, column, mean)))

几乎实现了我的要求,我得到了一个带有Nright、Nwrong和Ntied列的数据框,但它没有生成Rater和Class列。 - Lorin Hochstein
2
我建议将你的 pairwise.compare 函数更改为返回这两个字段。否则,你将不得不使用一个 lapply 程序(或 plyr)来获取列表名称和值(这是一个额外的步骤)。 - Shane
看起来在这种情况下,plyr实际上比by更简单,我之前不知道这个软件包。 - Lorin Hochstein
这对我有用,但开始出现“在do.call(“rbind”,X)中的错误:第二个参数必须是列表”。发生了什么? - user1916067

6
考虑使用plyr包中的ddply代替by函数。它可以处理将列添加到数据框的工作。

4
没有任何用ddply函数解决问题的代码示例,而这个回答被认可并评为最佳答案,这让人感到惊讶。在我看来,这应该是一条评论。 - nad7wf

4

虽然这是一个老帖子,但对于任何搜索此主题的人:

analysis = by(...)
data.frame(t(vapply(analysis,unlist,unlist(analysis[[1]]))))
unlist()by()的一个元素(在这里是analysis)作为命名向量进行表达。 vapply()analysis的所有元素执行unlist并输出结果。它需要一个虚拟参数来知道输出类型,这就是analysis[[1]]的用途。如果可能的话,您可能需要添加一个检查,以确保analysis不为空。 每个输出都将成为一列,因此使用t()将其转置为所需方向,其中每个analysis条目都成为一行。

如果您的数据框中存在混合类型(例如一个列中有字符,另一个列中有数字),那么这个解决方案就不适用,因为它依赖于vapply。但在这种特定情况下,Shane上面提供的解决方案完全可以胜任。 - Jealie

3
这扩展了Shane使用rbind()的解决方案,还添加了标识组并删除空组的列 - 这是问题中请求的两个功能。通过使用基本软件包函数,不需要其他依赖项,例如plyr。
simplify_by_output = function(by_output) {
    null_ind = unlist(lapply(by_output, is.null))  # by() returns NULL for combinations of grouping variables for which there are no data. rbind() ignores those, so you have to keep track of them.
    by_df = do.call(rbind, by_output)  # Combine the results into a data frame.
    return(cbind(expand.grid(dimnames(by_output))[!null_ind, ], by_df))  # Add columns identifying groups, discarding names of groups for which no data exist.
}

3

我会做

x = by(data, list(data$x, data$y), function(d) whatever(d))
array(x, dim(x), dimnames(x))

然后你有一个“矩阵”/“数组”,但不是“数据框”。 - bers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接