我需要计算数据集中每个用户的总数,但问题是,即使用户的数量为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 :(得分: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
答案 1 :(得分:1)
如果我理解正确,那么总金额就不会累积为负。
尽管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