0

我经常遇到的一般问题:我想对 data.frame 执行一些操作,每个因子级别都会产生一个数字,为​​此它使用来自多个列的信息。如何在 R 中编写它?

我考虑了这些功能:

  • tapply - 不在多列上操作
  • 聚合 - 函数分别给出列
  • ave - 结果与输入的行数相同,而不是因子级别数
  • by - 这是最热门的候选人,但我讨厌返回的格式 - 列表。我想要data.frame结果,我知道我可以转换它,但它很难看,我更喜欢另一种解决方案!
4

4 回答 4

2

基本 R 解决方案是使用lapply和的组合split

> data.frame(lapply(split(iris[,1:4], iris[,5]), colMeans))
             setosa versicolor virginica
Sepal.Length  5.006      5.936     6.588
Sepal.Width   3.428      2.770     2.974
Petal.Length  1.462      4.260     5.552
Petal.Width   0.246      1.326     2.026

...或者您可以将其包装起来do.call(rbind, ...)以稍微不同的形式获得输出:

> data.frame(do.call(rbind,lapply(split(iris[,1:4], iris[,5]), colMeans)))
           Sepal.Length Sepal.Width Petal.Length Petal.Width
setosa            5.006       3.428        1.462       0.246
versicolor        5.936       2.770        4.260       1.326
virginica         6.588       2.974        5.552       2.026

...或者sapply如果您的数据可以存储在矩阵中,请使用:

> sapply(split(iris[,1:4], iris[,5]), colMeans)
             setosa versicolor virginica
Sepal.Length  5.006      5.936     6.588
Sepal.Width   3.428      2.770     2.974
Petal.Length  1.462      4.260     5.552
Petal.Width   0.246      1.326     2.026
于 2013-08-15T15:25:03.250 回答
2

OP 要求一个一般性的答案,所以我认为“plyr”包是最合适的。'plyr' 包在处理大型数据集时有局限性,但对于日常使用(在原始帖子中暗示),'plyr' 函数对于任何 R 用户来说都是极好的资产。

设置:这是一个供我们使用的快速数据示例。

data <- data.frame(id=1:50, group=sample(letters[1:3], 50, rep=TRUE), x_Value=sample(1:500, 50), y_Value=sample(2:5, 50, rep=TRUE)*100)

如何使用 plyr:我将在这里以基本用途为例,让事情开始。首先,加载包。

library(plyr)

现在,让我们开始计算。使用“plyr”函数,您可以根据输入和输出选择函数的前两个字母。在这个例子中,我将输入一个数据帧 (d) 并输出一个数据帧 (d),所以我将使用“ddply”函数。

'ddply' 函数使用以下语法:

ddply(
    data_source, 
    .(grouping_variables), 
    function, 
    column_definitions)

首先,让我们快速找出有多少条目属于组 a、b 和 c:

ddply(
    data, 
    .(group), 
    summarize, 
    N=length(id))
#   group  N
# 1     a 17
# 2     b 16
# 3     c 17

在这里,我们首先指定了数据源,然后指定了我们想要通过“组”变量对行进行分组。我们使用“summarize”函数来删除除 grouping_variables 和 column_definitions 中的列之外的所有列。使用“长度”功能基本上只是为此目的的一个计数。

现在,让我们在数据中添加一列,显示 x 和 y 值的组均值。

ddply(
    data,
    .(group), 
    mutate, 
    group_mean_x=mean(x_Value), 
    group_mean_y=mean(y_Value))
#    id group x_Value y_Value group_mean_x group_mean_y
# 1   8     a     301     300     218.7059     394.1176
# 2  13     a      38     500     218.7059     394.1176
# 3  14     a     425     300     218.7059     394.1176
# .....................................................
# 17 47     a     191     300     218.7059     394.1176
# 18  5     b     411     500     235.1875     325.0000
# 19  6     b     121     400     235.1875     325.0000
# 20 11     b     151     200     235.1875     325.0000
# .....................................................
# 33 49     b     354     200     235.1875     325.0000
# 34  1     c     482     400     246.1765     400.0000
# 35  2     c      43     300     246.1765     400.0000
# .....................................................
# 50 50     c     248     500     246.1765     400.0000

我已经截断了结果以使其更短。在这里,我们使用了相同的数据源和分组变量,但是“mutate”函数在添加列的同时保留了数据源中的所有数据。

现在,让我们对之前的数据进行两步操作。让我们在汇总表中显示 x 和 y 平均值之间的平均值和差异。

ddply(
    data, 
    .(group), 
    summarize, 
    group_mean_x=mean(x_Value), 
    group_mean_y=mean(y_Value), 
    difference=group_mean_x - group_mean_y)
#   group group_mean_x group_mean_y difference
# 1     a     218.7059     394.1176  -175.4118
# 2     b     235.1875     325.0000   -89.8125
# 3     c     246.1765     400.0000  -153.8235

我向您展示这个示例,因为发生了一些重要的事情......我们正在使用我们刚刚定义为不同列定义的一部分的列。这在创建汇总表时非常非常有用。

最后,让我们按两个因素进行分组:组和 x 值的 10^2 位中的数字。让我们创建一个汇总表,显示每个组的平均 x 和 y 值以及 10^2 位的 x 值。

ddply(
    data, 
    .(group, x_100=as.integer(x_Value/100)), 
    summarize, 
    mean_x=mean(x_Value), 
    mean_y=mean(y_Value))
#    group x_100   mean_x   mean_y
# 1      a     0  20.0000 425.0000
# 2      a     1 145.6667 333.3333
# 3      a     2 272.0000 400.0000
# 4      a     3 328.6667 433.3333
# 5      a     4 427.5000 350.0000
# 6      b     0  37.0000 200.0000
# 7      b     1 148.6667 383.3333
# 8      b     2 230.0000 325.0000
# 9      b     3 363.0000 200.0000
# 10     b     4 412.5000 400.0000
# 11     c     0  55.6000 360.0000
# 12     c     1 173.5000 350.0000
# 13     c     2 262.5000 450.0000
# 14     c     3 355.6667 400.0000
# 15     c     4 481.0000 433.3333

这个例子很重要,因为它向我们展示了两件事:我们可以使用向量化语句创建分组列,并且我们可以通过用逗号分隔列列表来按多个列进行分组。

这组快速示例应该足以开始使用“plyr”包。更多细节可以在 中找到help(plyr)

于 2013-08-15T15:54:15.977 回答
1

在 SO 上搜索会产生很多答案,这里有一个简单的例子。

library(data.table)

dt = data.table(a = c(1:6), b = c(1,1,1,2,2,2), c = c(1,2,1,2,1,2))
dt
#   a b c
#1: 1 1 1
#2: 2 1 2
#3: 3 1 1
#4: 4 2 2
#5: 5 2 1
#6: 6 2 2

dt[, sum(a), by = list(b, c)]
#   b c V1
#1: 1 1  4
#2: 1 2  2
#3: 2 2 10
#4: 2 1  5

即使在这个简单的例子中,我们也可以看到优于plyr's的优势ddply——更简单(更人性化和更短)的语法、保留分组顺序,当然还有更快的速度。(供参考的plyr版本是ddply(dt, .(b, c), summarize, sum(a))

于 2013-08-15T15:56:55.583 回答
1

plyr 包中的 ddply 按一个或多个因子拆分 data.frame,为每个拆分执行一个函数并返回一个 data.frame 作为结果。你可能想看看那里。

于 2013-08-15T15:17:16.323 回答