【问题标题】:How to use a shift calculation with a cumulative value in a data.table in R如何在 R 中的 data.table 中使用具有累积值的移位计算
【发布时间】:2017-09-08 10:26:27
【问题描述】:

我有一个布局如下的 data.table

TestData <- data.table(Threshold = 20,
                       Upto = 100,
                       Demand = c(0,0,5,0,50,10,10,10,10,50,20,60),
                       Stock  = c(100,0,0,0,0,0,0,0,0,0,0,0))

股票价值应计算为累积值,公式为:

如果库存(前一行)减去需求(当前行)小于或等于 超过阈值,然后更新 Stock 中的当前单元格 “Upto”中的值。否则用库存(前一行)减去需求(当前行)来更新库存(当前行)的值。

然后程序应该重新开始。结果应如下所示:

TestData <- data.table(Threshold = 20,
                       Upto = 100,
                       Demand = c(0,0,5,0,50,10,10,10,10,50,20,60),
                       Stock = c(100,100,95,95,45,35,25,100,90,40,100,40))

    Threshold Upto Demand Stock
 1:        20  100      0   100
 2:        20  100      0   100
 3:        20  100      5    95
 4:        20  100      0    95
 5:        20  100     50    45
 6:        20  100     10    35
 7:        20  100     10    25
 8:        20  100     10   100
 9:        20  100     10    90
10:        20  100     50    40
11:        20  100     20   100
12:        20  100     60    40

我所做的如下:

TestData[, Stock:= ifelse(cumsum(shift(Stock, 0, type="lead") - Demand) <= Threshold,
                     Upto,
                     cumsum(shift(Stock, 0, type="lead") - Demand))]

但在第一次更新后,计算停止并显示 100 每次平铺结束。库存中的第一个值是我手动设置的初始值。谢谢!

【问题讨论】:

  • 我认为您可能需要一个循环,因为每次迭代都取决于前一次迭代的值(前一天的库存)
  • @docendodiscimus 是的,我认为需要一个循环,因为有一个重置规则(累积需求在达到 80 后的一行间隙后重新开始)。

标签: r data.table shift


【解决方案1】:

这是一个data.table 解决方案。创新在于by 分组。请务必发布此解决方案失败的任何边界案例。

TestData <- data.table(Threshold = 20,
                       Upto = 100,
                       Demand = c(0,0,5,0,50,10,10,10,10,50,20,60),
                       Stock  = c(100,0,0,0,0,0,0,0,0,0,0,0))

#to see by grouping
#TestData[,trunc(cumsum(Demand)/(Threshold - Upto))]

TestData[, Stock2 := c(Upto[1], Upto[1] - cumsum(Demand[-1])),
    by=trunc(cumsum(Demand)/(Threshold - Upto))]
TestData

【讨论】:

    【解决方案2】:

    这是一个棘手的问题。使用do-while原则做到了:

    upVal     = 100
    threshVal = 20
    cumVals   <- TestData$Demand
    cumMaster <- cumsum(cumVals) 
    
    
    repeat{
        IND <- cumMaster>=upVal-threshVal
        cumVals[min(which(IND == TRUE))] <- 0
        cumMaster[IND] <- cumsum(cumVals[IND])
        if(all(cumMaster<upVal-threshVal)){
            break
        }
    }
    
    TestData$Stock <- 100 - cumMaster
    

    结果

    TestData$Stock
    

    【讨论】:

      【解决方案3】:

      如果您可以使用循环解决方案。我不认为这对 dplyr(或 data.table)是可行的,但我希望有人能证明我错了。

      for (i in 2:nrow(TestData)) {
        # If stock - demand <= threshold, restock
        if ((TestData[i-1, "Stock"] - TestData[i, "Demand"]) <= TestData[i, "Threshold"]) 
        {
          TestData[i, "Stock"] <- TestData[i-1, "Upto"]
        }
        # Else update stock with stock - demand
        else 
        {
          TestData[i, "Stock"] <- TestData[i-1, "Stock"] - TestData[i, "Demand"]
        }
      }
      

      【讨论】:

      • 您可以在循环中的每次迭代中将TestData[i-1, "Stock"] - TestData[i, "Demand"] 存储为临时变量,否则您可能会在某些迭代中计算两次。 remaining = TestData[i-1, "Stock"] - TestData[i, "Demand"]; TestData[i, "Stock"] &lt;- if (remaining &lt;= TestData[i, "Threshold"]) TestData[i-1, "Upto"] else remaining
      • 谢谢大家。我选择了这个作为答案,因为它最适合我遇到的实际问题。
      猜你喜欢
      • 1970-01-01
      • 2021-04-05
      • 2017-03-17
      • 1970-01-01
      • 2016-04-17
      • 2017-11-29
      • 1970-01-01
      • 1970-01-01
      • 2013-06-19
      相关资源
      最近更新 更多