累积平均数与要更新的条件

时间:2019-08-15 07:09:09

标签: function dplyr data.table

我有一个纵向记录的变量(变量1)。我想随着时间的推移计算累计平均值(或“正常”)变量。更重要的是,我只想在Var.1满足条件时更新累计平均值,在这种情况下,它是前一个法线的70%以上。如果满足,则应进行更新;否则,应将先前的值结转。我一直在寻找矢量化解决方案,但不确定是否可行。

我的示例数据如下。我已经输入了排除第五项(50)后的正常值,因为它不满足> 70%的规则。

library(tibble)
Sample.GT = tibble(Var.1 = c(80, 80,90,90,50,80,70, 80,80,80),
                   Normal = c(80, 80,83.33,85,85,84,81.67,81.43,81.25,81.11))
最好使用Dplyr或data.table解决方案。我希望通过大数据集的组来实现此目标,因此快速解决方案是理想的选择。

1 个答案:

答案 0 :(得分:1)

data.table中可能的递归方法:

n <- 1
cs <- GT$Var.1[1L]
GT[1L, cm := cs]
GT[-1L, cm := {
    if (Var.1 > 0.7*cs/n) {
        cs <- cs + Var.1
        n <- n + 1
    }
    cs / n
}, seq_len(GT[,.N])[-1L]]

或使用Rcpp会更快:

library(Rcpp)
calcNorm <- cppFunction('
NumericVector calcNorm(NumericVector v) {
    int sz = v.size();
    double n = 1.0, cs = v[0];
    NumericVector ret(sz);
    ret[0] = cs;

    for (int i = 1; i < sz; i++) {
        if (v[i] > 0.7*cs/n) {
            cs = cs + v[i];
            n = n + 1.0;
        }
        ret[i] = cs / n;   
    }
    return(ret);
}
')
GT[, newNormal := calcNorm(Var.1)]

输出:

    Var.1 Normal       cm
 1:    80  80.00 80.00000
 2:    80  80.00 80.00000
 3:    90  83.33 83.33333
 4:    90  85.00 85.00000
 5:    50  85.00 85.00000
 6:    80  84.00 84.00000
 7:    70  81.67 81.66667
 8:    80  81.43 81.42857
 9:    80  81.25 81.25000
10:    80  81.11 81.11111

数据:

library(data.table)
GT = data.table(Var.1 = c(80, 80,90,90,50,80,70, 80,80,80),
    Normal = c(80, 80,83.33,85,85,84,81.67,81.43,81.25,81.11))

编辑感谢sindri_baldur的评论