我正在尝试创建条件和,以便计算平均值。这个想法是函数(或apply语句)检查某个值是否为真(例如x> 0),然后将x的所有值加到大于零的位置。最后一步是将此总和除以大于零的实例数。搜索条件总和(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函数,我忽略了它?)
任何想法都非常受欢迎,
此致
答案 0 :(得分:9)
可能很容易先丢弃未使用的行然后聚合它们:
aggregate(TradeResult.Currency.~Instrument,
mean,
data=subset(tmpData,TradeResult.Currency.>0))
答案 1 :(得分:5)
你几乎就在那里,我认为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])))
JPM KFT 225 116
答案 2 :(得分:4)
最近有很多这些数据聚合/条件分析问题。看到使用的不同方法总是很有趣。我想我会使用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
答案 3 :(得分:2)
聚合是最简单的方法,但我不同意“更干净,因为你不必编写自定义函数”。定义一些明确的功能时,可读性会提高。特别是如果您在脚本中需要平均几次。
聚合比你的自定义函数快一点,因为你忘记了索引。你想这样做:
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在输出之间整齐地隐藏了完全相同的解决方案:-)。我将此作为时间参考。答案 4 :(得分:1)
对此有一种非常简单快速的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
答案 5 :(得分:-1)
我可能只是从迭代风格中解决这个问题。有一个名为'accumulator'或其他的局部变量,循环遍历列表中的所有元素,并且有一个if块类似
if (x[index] > 0)
accumulator = accumulator + x[index]
并在完成后返回累加器的值。