data.frame上多列上的每组操作

时间:2013-08-15 15:07:47

标签: r dataframe

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

中写出来

我考虑过这些功能:

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

4 个答案:

答案 0 :(得分: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

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

现在,让我们在数据中添加一列,显示组对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)

答案 1 :(得分:1)

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

答案 2 :(得分:1)

基础R解决方案是使用lapplysplit

的组合
> 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

答案 3 :(得分: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 ddply的优势 - 更简单(更人性化和更短)的语法,保持分组顺序,当然还有更快的速度。 (供参考,plyr版本为ddply(dt, .(b, c), summarize, sum(a))