【问题标题】:Calculating percentages in an apply statement (R)在应用语句中计算百分比 (R)
【发布时间】:2010-12-05 15:48:22
【问题描述】:

我正在为一些非常简单的事情而苦苦挣扎,但是我在兜圈子,只是看不到我在哪里犯了错误。我真的希望有人可以给我一个方便的建议,让我不再被困!

我的目标:我想计算 data.frame 中结果高于 0 的实例的百分比。我已经尝试使用 for 循环,但无济于事。因此,经过更多搜索后,我使用 apply 函数来计算各种指标,如均值、标准差和最小值/最大值。这很好用,但是对于计算百分比,apply 函数不起作用,即使我制作了自定义函数并将其插入到 apply 函数中。

这是我的 data.frame 的缩短版本:

     tradesList[c(1:5,10:15),c(1,7)]
   Instrument TradeResult.Currency.
1         JPM                    -3
2         JPM                   264
3         JPM                   284
4         JPM                    69
5         JPM                   283
10        JPM                  -294
11        KFT                    -8
12        KFT                   -48
13        KFT                   125
14        KFT                  -150
15        KFT                  -206

我想总结这个data.frame,例如通过显示每个工具的平均TradeResult:

> tapply(tradesList$TradeResult.Currency., tradesList$Instrument, mean)
 JPM  KFT 
42.3 14.6 

但是,我还想计算每个工具的 TradeResult > 0 的行的百分比。使用 'which' 函数检查 > 0 的实例确实有效,但是,apply 不会接受此函数作为参数。

> length(which(tradesList$TradeResult.Currency. > 0)) / length(tradesList$TradeResult.Currency.) * 100
[1] 50
> tapply(tradesList$TradeResult.Currency., tradesList$Instrument, (length(which(tradesList$TradeResult.Currency. > 0)) / length(tradesList$TradeResult.Currency.) * 100))
Error in match.fun(FUN) : 
  c("'(length(which(tradesList$TradeResult.Currency. > 0))/length(tradesList$TradeResult.Currency.) * ' is not a function, character or symbol", "'    100)' is not a function, character or symbol")
> 

我在帮助函数中搜索了有关此错误的更多信息,并尝试了各种不同的函数公式化方法(例如使用括号或引号),但每种方法都导致相同的结果。

有人知道计算大于零的实例的百分比吗?也许我错过了什么?

非常感谢,

问候,

编辑: 非常感谢 G. Grothendieck、Gavin Simpson 和 DWin 的快速cmets。非常感谢并且很有帮助!

已解决: 这是我现在拥有的:

> tmpData <- tradesList[c(1:5,10:15),c(1,7)]
> tmpData
   Instrument TradeResult.Currency.
1         JPM                    -3
2         JPM                   264
3         JPM                   284
4         JPM                    69
5         JPM                   283
10        JPM                  -294
11        KFT                    -8
12        KFT                   -48
13        KFT                   125
14        KFT                  -150
15        KFT                  -206
> 100*    # to get percentages
+ with( tmpData, 
+ tapply( (TradeResult.Currency. > 0) , Instrument, sum)/   # number GT 0
+        tapply( TradeResult.Currency., Instrument, length) ) # total number
     JPM      KFT 
66.66667 20.00000 
> 100 * tapply(tmpData$TradeResult.Currency. > 0, tmpData$Instrument, mean)
     JPM      KFT 
66.66667 20.00000 
> pcentFun <- function(x) {
+     res <- x > 0
+     100 * (sum(res) / length(res))
+ }
> 
> with(tmpData, tapply(TradeResult.Currency., Instrument, pcentFun))
     JPM      KFT 
66.66667 20.00000

再次感谢!

问候,

【问题讨论】:

    标签: r apply


    【解决方案1】:

    编写一个简单的函数来进行计算:

    pcentFun <- function(x) {
        res <- x > 0
        100 * (sum(res) / length(res))
    }
    

    然后我们可以通过tapply() 将其应用于仪器组

    > with(tradeList, tapply(TradeResult.Currency, Instrument, pcentFun))
         JPM      KFT 
    66.66667 20.00000 
    

    但如果您想要带有仪器名称的摘要,aggregate() 会更有用:

    > with(tradesList, aggregate(TradeResult.Currency, 
    +                            by = list(Instrument = Instrument), pcentFun))
      Instrument        x
    1        JPM 66.66667
    2        KFT 20.00000
    

    【讨论】:

    • 感谢 Gavin,这真的很有帮助。汇总建议也可以用于我的 R 分析的其余部分。太好了!
    • 提示:总和除以长度是均值的定义。
    • @Hadley;谢谢你提出了一个很好的观点——我认为@Jura25 会更容易地识别出我使用的公式,而不是认为这是平均值。此外,@Jura25 在字里行间阅读,正在寻找如何在应用函数方面走得更远。仅仅使用mean 不会有那么大的进步。
    【解决方案2】:

    试试这个:

    100 * tapply(tradesList$TradeResult.Currency. > 0, tradesList$Instrument, mean)
    

    它给出了帖子中的示例数据:

      JPM   KFT 
    66.67 20.00 
    

    这里使用的是 sqldf(请注意,RSQLite 驱动程序将点转换为下划线,因为点也是 SQL 运算符,所以我们在点所在的地方使用下划线):

    > library(sqldf)
    > sqldf("select Instrument, 
    +     100 * avg(TradeResult_Currency_ > 0) as '%>0',
    +     avg(TradeResult_Currency_) as 'Avg Currency'
    +     from tradesList group by Instrument")
      Instrument   %>0 Avg Currency
    1        JPM 66.67        100.5
    2        KFT 20.00        -57.4
    

    这两个也可以通过适当修改已发布的aggregate 解决方案转换为aggregate

    【讨论】:

    • 感谢 G. Grothendieck,简单优雅但非常有效。感谢您的回复!
    【解决方案3】:

    您可以使用 sum 或 mean 处理逻辑结果以获得有意义的汇总结果:

    100*    # to get percentages
    with( tradesList, 
    tapply( (TradeResult.Currency. > 0) , Instrument, sum)/   # number GT 0
           tapply( TradeResult.Currency., Instrument, length) ) # total number
    

    编辑:我注意到 Gavin 给了你一个返回数据框的答案,这是一个通常很好理解的类。 Gabor 和我的回复中的值类别都是一维数组。通过 c() 将对象包围起来,它们可以变成命名向量,c() 可以作为向量函数的连接和强制。就他们的立场而言,它们完全可以接受以预期方式使用“[”进行rbinding或访问,并从names()返回预期结果。

    tapply 函数在 INDEX 参数中返回具有维数的数组,并且可以非常有效地结合使用表对象进行矩阵运算。我经常将总和除以计数,或以计数除以总和,以获得 2、3 或 4 维的有意义的类别统计信息。

    【讨论】:

    • 感谢 DWin,非常干净的建议,对于像我这样的初学者来说也是可以理解的。我想 with() 语句是我更经常使用的。感谢您的回复!
    猜你喜欢
    • 2010-10-20
    • 2020-10-17
    • 1970-01-01
    • 2015-04-05
    • 1970-01-01
    • 2014-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多