条件求和 (R)

Posted

技术标签:

【中文标题】条件求和 (R)【英文标题】:Conditional summing (R) 【发布时间】:2011-05-20 20:10:51 【问题描述】:

我正在尝试创建一个条件总和,以计算平均值。这个想法是一个函数(或一个 apply 语句)检查某个值是否为真(例如 x > 0),然后将 x 的所有大于零的值相加。最后一步是将这个总和除以大于零的实例数。搜索条件 sum(ming) 没有给我有用的信息。

这是数据的一部分:

> tmpData
   Instrument TradeResult.Currency.
1         JPM                    -3
2         JPM                   264
3         JPM                   284
4         JPM                    69
5         JPM                   283
11        KFT                    -8
12        KFT                   -48
13        KFT                   125
14        KFT                  -150
15        KFT                  -206
16        KFT                   107

在我尝试过的功能中,以下是最有希望的:

avgProfit <- function(x) 
    ifelse(x > 0,
    sum(x) / length(which(x > 0)),
    return(0))
    

但是,这个函数的输出是0:

> with(tmpData, tapply(TradeResult.Currency., Instrument, avgProfit))
JPM KFT 
  0   0     
> avgProfit(tmpData$TradeResult.Currency.)
[1] 0
> x
 [1] 1 1 2 1 2 3 3 3 4 4

(JPM 的值应为 225(总计 900 除以 4 个大于零的实例),KFT 的值应为 116)

即使我在函数中计算 x 的总和(如果我理解正确,应该是 data.frame 中各个值的总和),变量“x”的输出让我感到困惑。我找不到这些 1、2、3 和 4 的来源。

如何计算条件总和?此外,我需要使用一个函数还是让它太复杂(也许有一个我忽略的内置 R 函数?)

欢迎任何想法,

问候,

【问题讨论】:

所以 Instrument 在这里没有任何作用,对吧? 嗨 Roman,不,该工具确实在计算每个工具的平均值方面发挥了作用(即 JPM 的平均值,KFT 的平均值)。我认为 Kohske 的子集解决方案是一个优雅的解决方案。感谢您的评论/兴趣! 【参考方案1】:

我可能会从迭代风格中解决这个问题。有一个称为“累加器”或其他的局部变量,遍历列表中的所有元素,并有一个类似的 if 块

if (x[index] > 0)
    accumulator = accumulator + x[index]

完成后返回累加器的值。

【讨论】:

我没有想过使用索引值来解决这样的问题,但我想这种方法对于初学者(比如我自己)来说有点麻烦。 :) 感谢您的回复!【参考方案2】:

首先删除未使用的行然后聚合它们可能是一种简单的方法:

aggregate(TradeResult.Currency.~Instrument,
  mean,
  data=subset(tmpData,TradeResult.Currency.>0))

【讨论】:

谢谢科斯克!这比编写自定义函数要容易和快捷得多。 :)【参考方案3】:

你快到了,我认为 ifelse 是错误的方向,因为你想要平均值,而不是元素比较。

您需要考虑是否会遇到缺失值,以便妥善处理。

tmpData <- read.table(textConnection("  Instrument TradeResult.Currency.
1         JPM                    -3
2         JPM                   264
3         JPM                   284
4         JPM                    69
5         JPM                   283
11        KFT                    -8
12        KFT                   -48
13        KFT                   125
14        KFT                  -150
15        KFT                  -206
16        KFT                   107"))



with(tmpData, tapply(TradeResult.Currency., Instrument, function(x) mean(x[x > 0])))

摩根大通KFT 225 116

【讨论】:

感谢 Mdsumner 更正了我的功能,并以一个很好的简短形式。在计算值之前检查缺失值是个好主意。谢谢!【参考方案4】:

聚合可能是最简单的方法,但我不同意“更清洁,因为您不必编写自定义函数”。定义一些明确的功能时,可读性会提高。尤其是当您在脚本中多次需要该平均值时。

Aggregate 比您的自定义函数快很多,因为您忘记了索引。你想这样做:

avgProfit <- function(x)
  mean(x[x>0])

由于没有开销,这再次比聚合更快:

> tmpData <- data.frame(
+     instrument = rep(c("JPM","KFT"),each=10000),
+     TCurr = runif(20000,-10,100)
+ )

> system.time(
+   with(tmpData,tapply(TCurr,instrument,avgProfit)))
   user  system elapsed 
   0.02    0.00    0.02 

> system.time(
+   aggregate(TCurr~instrument,mean,data=subset(tmpData,TCurr>0)))
   user  system elapsed 
   0.09    0.00    0.10 

在大多数情况下,您可以忽略这种差异。在庞大的数据集(n > 100,000)上,您会开始感受到它,尤其是当您需要对一整套变量进行此操作时。

编辑:刚刚看到 mdsummer 在输出之间巧妙地隐藏了完全相同的解决方案:-)。我将此作为时间参考。

【讨论】:

+1 用于性能比较。如果您有时间,您是否也将ddply 解决方案添加到您的测试中?它在我的机器上测试得最快.. @Chase :使用我的数据框,它的速度差不多。使用更大的数据帧,它会更快一些。 tapply 比 ddply 慢一点。【参考方案5】:

最近有不少这样的数据聚合/条件分析问题。看到使用的不同方法总是很有趣。我想我会添加一个使用plyr 的方法。我喜欢plyr 函数,因为它们为所有函数提供标准语法,并允许您指定输入和输出的结构。在这里,我们将使用ddply,因为我们传入了data.frame,并希望data.frame 在另一侧返回。我们使用summarise 函数来计算每个仪器的平均值,其中值为正数。

library(plyr)
ddply(tmpData, .(instrument), summarise, avgProfit = mean(TCurr[TCurr > 0]))

为了跟进 @Joris 的性能比较,ddply 的性能似乎与其他方法一样好:

> tmpData <- data.frame(
+      instrument = rep(c("JPM","KFT"),each=10e6),
+      TCurr = runif(20e6,-10,100)
+  )
> 
>  system.time(
+ ddply(tmpData, .(instrument), summarise, avgProfit = mean(TCurr[TCurr > 0]))
+  )
   user  system elapsed 
   4.43    0.89    5.32 
>  
>  avgProfit <- function(x)  mean(x[x>0])
>  
>  system.time(
+ with(tmpData,tapply(TCurr,instrument,avgProfit))
+ )
   user  system elapsed 
   7.88    0.47    8.36 
>  
> system.time(
+ aggregate(TCurr~instrument,mean,data=subset(tmpData,TCurr>0))
+ )
   user  system elapsed 
  28.29    2.35   30.65 

【讨论】:

+1 表示 ddply,确实,ddply 比这里的 tapply 快一点。【参考方案6】:

有一个非常简单快速的data.table 方法:

library(data.table)

setDT(dt)[, .(avg = mean(TradeResult.Currency.[which(TradeResult.Currency.>0 )])), by= Instrument]

#    Instrument avg
# 1:        JPM 225
# 2:        KFT 116

基准测试: 使用@Joris 和@Chase 的性能比较,这个解决方案比ddply 方法快了近五倍,比aggregate 方法快了40 倍。

tmpData <- data.frame(
        instrument = rep(c("JPM","KFT"),each=10e6),
        TCurr = runif(20e6,-10,100))

system.time( ddply(tmpData, .(instrument), summarise, avgProfit = mean(TCurr[TCurr > 0]))  )
# user  system elapsed 
# 1.41    0.62    2.03 

system.time( setDT(tmpData)[, .(avg = mean(TCurr[which(TCurr>0 )])), by= instrument]  )
# user  system elapsed 
# 0.36    0.18    0.43

system.time( aggregate(TCurr~instrument, mean, data=subset(tmpData,TCurr>0)) )
#  user  system elapsed 
# 16.07    1.81   17.20 

【讨论】:

以上是关于条件求和 (R)的主要内容,如果未能解决你的问题,请参考以下文章

如何根据多个条件对行求和 - R? [复制]

R中数据帧的条件求和

Group_by,条件求和并替换R中的变量

Mysql按照某个条件进行分组求和并且要知道参与求和的各项明细

EXCEL条件求和怎么用??

Excel表格如何单条件求和