【问题标题】:Rolling percentage add along column滚动百分比沿列添加
【发布时间】:2018-08-13 06:05:46
【问题描述】:

我觉得这在基础 R 中应该很容易,但我就是想不通。 我有一个简单的数据框,假设它看起来像这样

tbl <-  read.table(text = 
    "Field1 Field2
    100 200
    150 180
    200 160
    280 250
    300 300
    300 250",
header = TRUE)

现在,我想做的是创建一个将应用滚动 % 加法的函数,例如:

fn <- function(tbl, pct) {}

接受上面的数据框为tbl。它根据pct 将当前行的百分比添加到下一个行中,并且几乎以累积方式滚动。

例如,fn(tbl$Field1, 0.1) 将生成以下结果:

100   (100 + 0.1*0)
160   (150 + 0.1*100 = 160)
216   (200 + 0.1*160 = 216)
301.6 (280 + 0.1*216 = 301.6)

等等

我会使用包解决方案,但更喜欢 base R,因为它有助于学习过程!我的长期目标是通过 field 和 pct 的每个组合构建一个循环过程,以便我可以在回归模型中测试它的效果;因此,我的直觉是我以后可以应用的功能是前进的方向。

谢谢。

【问题讨论】:

  • 你看过lag()函数吗?
  • filter 在这里很方便,filter(tbl, 0.1, method = "recursive")。请参阅这个不错的帖子以获得解释:simple examples of filter function, recursive option specifically
  • 不错。 filter 也比我的回答快。
  • 过滤器似乎完全符合我的需要。我不得不仔细检查(:))但是是的,它工作得很好。我没有将我的问题与自动回归联系起来。现在,我的下一个挑战是如何应用这些组合(这可能是我怀疑的第二个问题!)。谢谢。

标签: r apply rolling-computation


【解决方案1】:

filter() functionstats 包的一部分,它是基数 R。保留一位小数:

round(filter(tbl$Field1, 0.1, method="recursive"), 1)

这会产生以下结果

100.0 160.0 216.0 301.6 330.2 333.0

【讨论】:

  • 为了清楚 OP 的问题,我只指定了 OP 所指的列。当然,filter(tbl, 0.1, method="recursive") 会对整个 data.frame 做同样的事情
【解决方案2】:

很想找出一个不涉及显式循环的解决方案,但我想不出一个。您可以将所需结果分解为乘以 pct^c(0, 1, 2, ...) 的数字总和,但我认为这只会让您进行大量额外计算。所以我的解决方案很简单:

fn = function(x, pct) {
  n = length(x)
  result = NA*x
  last_result = 0
  for(i in 1:n) {
    result[i] = last_result = x[i] + last_result*pct
  }
  return(result)
}

fn(tbl$Field1, 0.1)

# [1] 100.000 160.000 216.000 301.600 330.160 333.016

【讨论】:

    【解决方案3】:

    您可以使用Reduce() 函数,如下所示。

    cumpersum = function(x, percent = 0.1) {
      Reduce(function(x1, x2) percent * x1 + x2, x, accumulate = TRUE)
    }
    
    dat <- data.frame(
      Field1 = c(100, 150, 200, 280, 300, 300),
      Field2 = c(200, 180, 160, 250, 300, 250)
    )
    
    dat$Field1cumper <- cumpersum(dat$Field1, .1)
    dat
    
    #   Field1 Field2 Field1cumper
    # 1    100    200        100.0
    # 2    150    180        160.0
    # 3    200    160        216.0
    # 4    280    250        301.6
    # 5    300    300        330.2
    # 6    300    250        333.0
    

    【讨论】:

    • 很高兴了解Reduce(),但在这个应用程序中它比愚蠢的for循环慢很多。
    • 有一个稍快的purrr::accumulate() 函数。但我认为stats::filter() 是为 OP 的确切目的而构建的。 Reduce() 是我立即想到的,因为这个问题是一种 foldingreducing 问题。
    【解决方案4】:

    如果您想编写一个仅使用基础 R 的解决方案并使用 for 循环和索引从最基础的编程开始学习,您可以知道您可以编写一个函数,其语料库如下所示:

    solution= tbl$Field1
    for (i in 1:length(tbl$Field1)) {
    
      if (i==1) {
        solution[1] = tbl$Field1[1] 
      } else {
        solution[i] = tbl$Field1[i] + pct * solution[i-1]
      }
    }
    

    虽然我建议您查看更高级的解决方案。已经提到的lag 函数可能很方便。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多