R中多个条件的有效条件求和

时间:2014-03-10 02:21:26

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

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

我有一个大的操作数据框,大约有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很新,并且不知道如何链接这些条件并将它们应用于整个数据框架。

2 个答案:

答案 0 :(得分:2)

您的数据是“长形式”(多行公司,来源,年份......)

对于多个来源值,您希望在每个公司和年份汇总 amount.inkg。特别是你想在'source'字段上与条件聚合。

再次,请给我们重复的例子。 (谢谢josilber)。 这是一个带有Split-Apply-Combine(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)

聚合的by参数是操作的位置(选择,按标准进行子集化)。

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

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

答案 1 :(得分:1)

这对于split-apply-combine范例来说是一项很好的任务。首先,按公司/年份对分割数据框:

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