条件求和 (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)的主要内容,如果未能解决你的问题,请参考以下文章