我有一个简单的数据框如下:
thedata <- data.frame(values = c(30,20,10,40,20)
,week = seq(from = 1, to = 5, by = 1))
thedata$lengths <-length(thedata$values):1-1
我希望在每一行中运行以下计算:
values*0.2^lengths
...我希望迭代并总计每个累积长度。例如,第一行计算将是:
sum(30*.20^1, 30*.20^2, 30*.20^3, 30*.20^4)
第三个是:
sum(10*.20^1, 10*.20^2)
......等等(最后一行为0,因为它是时间序列中的最后一个值)。到目前为止,我获得最大成功的方法是循环/ sapply组合:
for (i in thedata$lengths){
print(unlist(sapply(thedata[1], function(x) {x*0.2^i})))
}
但是将数据操作到正确的格式会变得有点混乱,我需要做一些不同的事情来使迭代正常工作。
我已经玩过rollapply和stats :: filter / reduce combo但收效甚微。
注意:这里有一个类似但更广泛的问题: Calculate running sum/decay value in time series
第二部分:
为了完整性,我也对上面的相同问题感兴趣,但是添加条件是每次迭代都使用values列中的相应值。所以第一行计算将是:
sum(20*.20^1, 10*.20^2, 40*.20^3, 20*.20^4)
我认为这主要通过以下代码解决:
thisfunc <- function(x) { w = 1:length(x); sum(x*.2^w)}
thedata$filtervalues2 <- rollapply(thedata$values, width=5,FUN=thisfunc, align="left", partial=TRUE)
thedata
shift <- function(x, n){
c(x[-(seq(n))], rep(NA, n))
}
thedata$filtervalues2 <- shift(thedata$filtervalues2, 1)
thedata[is.na(thedata)] <- 0
thedata
values week filtervalues2
1 30 1 4.752
2 20 2 3.760
3 10 3 8.800
4 40 4 4.000
5 20 5 0.000
虽然有点笨重。我想我更喜欢这种sqldf方法:
thedata$values2 <- thedata$values
trythis <- sqldf("select a.week,
sum(case when b.week > a.week
then b.values2*power(0.2,b.week-a.week)
else 0 end) as calc1
from thedata a,
thedata b
group by a.week")
答案 0 :(得分:2)
看过@ snoram的回答后,我发现结合我们的两种方法可以得到最少的结果:
library(dplyr)
thedata %>%
rowwise() %>%
mutate(new = sum(values * 0.2^seq_len(lengths)))
## values week lengths new
## <dbl> <dbl> <dbl> <dbl>
## 1 30 1 4 7.488
## 2 20 2 3 4.960
## 3 10 3 2 2.400
## 4 40 4 1 8.000
## 5 20 5 0 0.000
原始回答
我就是这样做的:
func <- function(values, lengths) {
calc = 0
for(i in 1:lengths) {
calc = calc + values * 0.2^i
}
return(calc)
}
library(dplyr)
thedata %>%
rowwise() %>%
mutate(new = func(values, lengths))
## values week lengths new
## <dbl> <dbl> <dbl> <dbl>
## 1 30 1 4 7.488
## 2 20 2 3 4.960
## 3 10 3 2 2.400
## 4 40 4 1 8.000
## 5 20 5 0 24.000
答案 1 :(得分:2)
粗糙的基础R解决方案。
n <- nrow(thedata)
thedata$result <- numeric(n)
for (row in seq.int(to = n)) {
len <- thedata[row, "lengths"]
if (len > 0) {
thedata[row, "result"] <-
sum(thedata[row, "values"] * 0.2 ^ seq.int(to = len))
}
}
thedata
values week lengths result
1 30 1 4 7.488
2 20 2 3 4.960
3 10 3 2 2.400
4 40 4 1 8.000
5 20 5 0 0.000
答案 2 :(得分:0)
thedata$values * sapply(NROW(thedata):1, function(i) ifelse(i == 1, 0, sum(0.2^((i-1):1))))
#[1] 7.488 4.960 2.400 8.000 0.000