【问题标题】:Remove fake negative value in R删除 R 中的假负值
【发布时间】:2019-05-17 08:34:06
【问题描述】:

我需要计算数据集中每个用户的总量,但问题是即使用户的数量为 0,它也会不断减去并生成假负值(数量不能小于 0,它的错误)。

对于每一个 + 或 - 都有真实的事件。但是,当数量达到 0 时,无论出现多少负面事件,结果都不应该低于 0,如果我们有前 10 个负面事件,比如去 -1000,然后我们有一个正面 +200,然后一个负面-100,我需要最终结果是 100。

这里是示例,该用户的最终总金额应为 200。

userdata <- read.table(text="
 ID  Amount UserID Date     Hour
 1   500    2      3/3/2018 0:00
 2  -200    2      3/4/2018 0:00
 3  -250    2      3/5/2018 0:00
 4  -500    2      3/8/2018 0:00
 5   100    2      3/8/2018 0:00
 6  -50     2      3/8/2018 0:00
 7   250    2      3/8/2018 0:00
 8  -100    2      3/8/2018 0:00
", header=TRUE, stringsAsFactors=FALSE)

我需要一种方法来正确计算该金额。

【问题讨论】:

  • 我说的不够具体,如果有大于 0 的数量应该减去操作成本到 0,并不是所有的负操作都是错误。
  • 如果我们将示例中的两个负值都设置为零,那么总数仍然是 500,比您说的应该是 250 多。那么某些正值是否也是不准确/错误的?
  • 减法码在哪里?你能发布你正在做的事情,而不仅仅是最终结果吗?
  • @aksela 我没有减法代码,它不是我的服务器。对于每个 + 或 - 都有真实事件,但是当数量达到 0 时,无论出现多少负面事件,结果都不应该低于 0,如果我们有前 10 个负面事件,比如去 - 1000,然后我们有一个正面 + 200,在一个负面 - 100 之后,我需要最终结果为 100。

标签: r


【解决方案1】:

我认为我们可以使用递归过滤器(一种条件累积和)来解决这个问题。

# Isolate the vector we're interested in and prepend a zero
y <- c(0, userdata$Amount)

# run a for loop
for (i in 2:length(y)) {   # For every position in the vector, 
    y[i] <- y[i-1] + y[i]  # add the previous to the present.
    if (y[i] < 0) {        # If the resulting sum is less than zero,
        y[i] <- 0          # replace it with zero
    }
}

# Or equivalent, but maybe a bit more elegant
for (i in 2:length(y)) { 
    y[i] <- max(c(0, y[i-1] + y[i]))
}

y[-1]
# [1] 500 300  50   0 100  50 300 200  

tail(y, 1)
# 200

【讨论】:

    【解决方案2】:

    如果我理解正确的话,总金额是由永远不会变成负数的累积总和计算的。

    虽然AkselA's recursive filter 通过循环遍历向量的元素来计算总数,但下面的方法会在累积和变为负数时迭代地校正它。请注意,元素的顺序很重要,例如时间序列。

    nonneg_cumsum <- function(x) {
      n <- length(x)
      y <- cumsum(x)
      repeat {
        i <- head(which(y < 0), 1L)
        if (length(i) < 1) return(y)
        y[i:n] <- y[i:n] - y[i]
      }
    }
    
    nonneg_cumsum(userdata$Amount)
    
    [1] 500 300  50   0 100  50 300 200
    

    为了比较,这里是常规 cumsum() 函数的输出:

    cumsum(userdata$Amount)
    
    [1]  500  300   50 -450 -350 -400 -150 -250
    

    【讨论】:

      猜你喜欢
      • 2017-08-06
      • 1970-01-01
      • 1970-01-01
      • 2020-02-22
      • 2015-05-17
      • 2011-03-01
      • 2019-05-23
      • 1970-01-01
      相关资源
      最近更新 更多