【问题标题】:How to calculate mean with expending window如何使用扩展窗口计算平均值
【发布时间】:2014-10-09 14:10:39
【问题描述】:

我在下面有一个数据框。我想知道如何通过从“2014-1-5”开始扩展窗口来计算“value_t”列的平均值。例如val(1)=mean(1:5),value(2)=mean(1:6),value(3)=mean(1:7)。我希望算法是有效的(没有循环)。

df<-data.frame(date_t=paste('2014-01-',1:15,sep=""),value_t=1:15)
> df
   date_t        value_t
1   2014-01-1       1
2   2014-01-2       2
3   2014-01-3       3
4   2014-01-4       4
5   2014-01-5       5
6   2014-01-6       6
7   2014-01-7       7
8   2014-01-8       8
9   2014-01-9       9
10 2014-01-10      10
11 2014-01-11      11
12 2014-01-12      12
13 2014-01-13      13
14 2014-01-14      14
15 2014-01-15      15

【问题讨论】:

    标签: r rollapply


    【解决方案1】:

    sapply(5:NROW(df), function(.) mean(df$value_t[1:.])) 怎么样?它涉及一种循环(sapply),但它应该是合理的快速。

    【讨论】:

    • 感谢您的帮助。由于我有一个相当大的 data.frame(100,000*20),它看起来很慢。
    【解决方案2】:

    sapply(...) 解决方案比for(...) 循环更快,但只是(大约 2% - 在误差范围内)。事实证明,在每一步都从数据框中提取列会大大减慢速度。如果您首先将该列作为向量获取,您将获得约 25% 的改进。

    df <- data.frame(value=1:1e4)
    f.sapply <- function() sapply(5:nrow(df), function(.) mean(df$value[1:.]))
    f.loop   <- function() {result <- numeric(nrow(df)-4)
                            for (i in 5:nrow(df)) result[i-4] <- mean(df$value[1:i])
                            result
    }
    f.vec    <- function() {vec<-df$value
                            sapply(5:nrow(df), function(.) mean(vec[1:.]))
    }
    
    # do they produce identical results?
    identical(f.sapply(),f.loop())
    # [1] TRUE
    identical(f.sapply(),f.vec())
    # [1] TRUE
    # which is faster?
    library(microbenchmark)
    microbenchmark(f.sapply(),f.loop(),f.vec())
    # Unit: milliseconds
    #        expr      min       lq   median        uq      max neval
    #  f.sapply() 904.2934 929.7361 947.7621  978.8775 1496.455   100
    #    f.loop() 927.5288 950.3632 963.5926 1012.2407 1347.889   100
    #     f.vec() 669.5615 697.3639 711.1498  751.2634 1060.056   100
    

    【讨论】:

    • 感谢基准测试结果和指向microbenchmark 的指针,这是我还不知道的库:)
    【解决方案3】:

    看看这个

    df$val <- cumsum(df$value_t) / 1:nrow(df)
    df$val[1:4] <- NA
    #     date_t value_t val
    #  2014-01-1       1  NA
    #  2014-01-2       2  NA
    #  2014-01-3       3  NA
    #  2014-01-4       4  NA
    #  2014-01-5       5 3.0
    #  2014-01-6       6 3.5
    #  2014-01-7       7 4.0
    #  2014-01-8       8 4.5
    #  2014-01-9       9 5.0
    # 2014-01-10      10 5.5
    # 2014-01-11      11 6.0
    # 2014-01-12      12 6.5
    # 2014-01-13      13 7.0
    # 2014-01-14      14 7.5
    # 2014-01-15      15 8.0
    

    如果你只想要向量,又不想篡改 df,那就做

    val <- (cumsum(df$value_t) / 1:nrow(df))[-(1:4)]
    # 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0
    

    【讨论】:

    • 感谢您的解决方案。有没有办法让它更通用?读取的case不是平均数,可能是自定义函数,比如累积百分排名。
    • 我想其中一个 apply 函数最适合更一般的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-09
    • 2014-02-17
    • 2018-09-29
    • 1970-01-01
    • 2017-03-12
    • 2019-11-06
    相关资源
    最近更新 更多