【问题标题】:Efficient conditional summing by multiple conditions in RR中多个条件的有效条件求和
【发布时间】:2014-04-13 00:25:48
【问题描述】:

我正在努力寻找解决以下问题的有效解决方案:

我有一个大约 8 列和 80000 行的大型操纵数据框,通常包含多种数据类型。 如果满足大型数据框的条件,我想创建一个包含一列总和的新数据框。

想象一下原始数据框的头部是这样的。 $years.raw 列表示公司测量了 x 年的数据。

> cbind(company.raw,years.raw,source,amount.inkg)
     company.raw years.raw source      amount.inkg
[1,] "C1"        "1"       "Ink"       "5"        
[2,] "C1"        "1"       "Recycling" "2"        
[3,] "C2"        "1"       "Coffee"    "10"       
[4,] "C2"        "1"       "Combusted" "15"       
[5,] "C2"        "2"       "Printer"   "14"       
[6,] "C2"        "2"       "Tea"       "18"   

我现在需要做的是创建一个新的数据框,它根据某些字符串元素为每家公司和每年汇总列 $amount.inkg 的值。 我将字符串元素保存在下面的三个向量中。字符串元素是原始数据框中 $source 列的一部分。

> vector1 <- c("Tea","Coffee")
> vector2 <- c("Ink","Printer")
> vector3 <- c("Recycling","Combusted")

首选数据框将如下所示:

Company Year              amount.vector1    amount.vector 2 amount.vector 3
C1           1                 0             5                 2
C2           1                 10            0                15        
C2           2                 18            14                0

$amount.vector1 的一般方法是: 总结每家公司和每年的列 $amount.inkg 的值,其中原始数据框列 $source== vector1 的字符串元素。 列 $amount.vector2 相同,只是元素当然不同。

如果没有可用的值,则应添加“0”而不是 NA 错误。 这需要对包含大约 250 家公司的整个原始数据框进行,每家公司的数据为 1:8(差异很大)。

编辑:对于数据框,我需要每年每公司一行。

C1 Year 1  
C1 Year 2
C1 Year 3
C2 Year 1
C2 Year 2

我试图编写一个结合这些条件的函数,但我失败了。 我对 R 很陌生,不知道如何关联这些条件并将它们应用于整个数据框。

【问题讨论】:

  • 如果您想要可执行的答案,请发一个小的reproducible example。在数据框上使用dput 并将其切成小尺寸等。
  • 您不需要创建中间的amount.vector* 数据框,这只是对原始数据框的aggregate/ddply(summarize) 操作。
  • 在您的标题中,这些不是“交叉引用”。它只是多个列(公司、年份)的聚合,并带有源条件。就这样。您无需先按年份手动汇总每个公司,保存中间结果,然后按公司汇总,并以源为条件。

标签: r dataframe aggregate multiple-conditions split-apply-combine


【解决方案1】:

您的数据是“长格式”(公司、来源、年份等多行)

您希望对每个公司和年份聚合amount.inkg,以获得多个来源值。具体来说,您希望与“源”字段的条件进行聚合。

再次,请给我们一个可重现的例子。 (谢谢乔西伯)。 这是一个具有拆分-应用-组合(ddply)或逻辑索引的四线:

df = data.frame(company.raw = c("C1", "C1", "C2", "C2", "C2", "C2"),
                years.raw = c(1, 1, 1, 1, 2, 2),
                source = c("Ink", "Recycling", "Coffee", "Combusted", "Printer", "Tea"),
                amount.inkg = c(5, 2, 10, 15, 14, 18))

# OPTION 1. Split-Apply-Combine: ddply(...summarize) with a conditional on the data
require(plyr) # dplyr if performance on large d.f. becomes an issue
ddply(df, .(company.raw,years.raw), summarize,
    amount.vector1=sum(amount.inkg[source %in% c('Tea','Coffee')]),
    amount.vector2=sum(amount.inkg[source %in% c('Ink','Printer')]),
    amount.vector3=sum(amount.inkg[source %in% c('Recycling','Combusted')])
)


# OPTION 2. sum with logical indexing on the df:
# (This is from before you modified the question to one-row-per-company-and-per-year)
df$amount.vector1 <- sum( df[(df$source %in% c('Tea','Coffee')),]$amount.inkg )
# josilber clarifies you want one-row-per-company
...

选项 3。您也可以将 aggregate(manpage here)subset(...) 一起使用,尽管汇总为一个总和是多余的。

aggregate(df, source %in% c('Tea','Coffee'), FUN = sum)

aggregate 的 by 参数是操作所在的位置(选择、按标准设置子集)。

注意:%in% 执行扫描操作,所以如果你的向量和 d.f.变大,或者为了可扩展性,您需要将其分解为可以矢量化的布尔运算: (source=='Tea' | source=='Coffee')

至于如果子集为空,则防止 NA 和,sum(c()) = 0 所以不用担心。但如果你这样做,要么使用 na.omit,要么在最终结果上使用 ifelse(is.na(x),0,x)

【讨论】:

  • 这些选项似乎都没有返回一个数据框,每个公司/年对都有一行。我相信 OP 正在为每一对寻找一行(也就是 company.rawyears.raw 的组合)。
  • @josilber:他从来没有说过那样的话。他所说的只是“创建一个新的数据框,根据某些字符串元素总结每家公司和每年的 $amount.inkg 列的值。”所以我们的两个解决方案都符合他的标准。
  • 我正在查看问题的一部分,它说“首选数据框看起来像这样” - 该示例对于每个公司/年份对都有一行。后来,“对我来说非常重要的是,最终的数据框每个公司每年只有一行”
  • @josilber:我的#选项 1. ddply 代码正是这样做的。总计的一个输出行,包含三列。您的意思是 OP 想要为每家公司提供一条生产线吗? ddply(df, .(Company) ... 很容易做到这一点
  • @smci 感谢您编辑、更正和回答我的问题。很抱歉我说得不够清楚。我使用您的选项 1 和 2 来解决我的问题。对我的 R 学习和解决这个问题很有帮助。我还没有研究汇总,但它在我的待办事项清单上。感谢您在此主题上的时间和帮助。我现在将编辑问题并尝试使其清楚。
【解决方案2】:

这对于拆分-应用-组合范式来说是一项很好的任务。首先,您按公司/年份对拆分数据框:

data = data.frame(company.raw = c("C1", "C1", "C2", "C2", "C2", "C2"),
                  years.raw = c(1, 1, 1, 1, 2, 2),
                  source = c("Ink", "Recycling", "Coffee", "Combusted", "Printer", "Tea"),
                  amount.inkg = c(5, 2, 10, 15, 14, 18))
spl = split(data, paste(data$company.raw, data$years.raw))

现在,您计算拆分数据中每个元素的汇总数据框:

spl2 = lapply(spl, function(x) {
  data.frame(Company=x$company.raw[1],
             Year=x$years.raw[1],
             amount.vector1 = sum(x$amount.inkg[x$source %in% vector1]),
             amount.vector2 = sum(x$amount.inkg[x$source %in% vector2]),
             amount.vector3 = sum(x$amount.inkg[x$source %in% vector3]))
})

最后,将所有内容组合在一起:

do.call(rbind, spl2)
#      Company Year amount.vector1 amount.vector2 amount.vector3
# C1 1      C1    1              0              5              2
# C2 1      C2    1             10              0             15
# C2 2      C2    2             18             14              0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-19
    • 2011-05-20
    • 1970-01-01
    • 1970-01-01
    • 2022-11-29
    • 2022-01-08
    • 2014-09-30
    相关资源
    最近更新 更多