To be more specific, I have an unbalanced panel data set that contains a variable that measures countries' level of democracy over time. I would like to add up each country's democracy score starting from the first observation to the present with a 1 percent annual depreciation rate.
-
4A [reproducible example](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) would help. We have no idea how your data looks like and how you exactly expect the output to be. – phiver Aug 29 '18 at 13:29
-
No one here will write code for your _requirements_. Please check [this](https://stackoverflow.com/help/on-topic) to understand what kind of questions can be posted here – Thangadurai Aug 29 '18 at 13:31
4 Answers
Example Data:
df = data.frame(year = 1990:2018, theVariable = rnorm(29))
Because you want different weights depending on the year, you have to create them. 0.99 because of -1% per year:
weights = 0.99^(0:28)
Now you can add them multiplied with the weights:
new_var = sum(df$theVariable * weights[2019 - df$year])
If you want the weighted average:
new_var = sum(df$theVariable * weights[2019 - df$year]) / sum(weights)

- 525
- 4
- 10
-
1
-
Yes, you are right. But that was just in addition as he asked for the weighted sum. – Benjamin Schlegel Aug 29 '18 at 14:03
Assuming you mean deprecation of 1 percent of each value per year, and not percent point.
And assuming you have one measurement per year.
You could use:
## Example data
var <- 10:20
sum(var*0.99^(length(var):1))
Where length(var):1
is a sequence of integers counting down from the number of values in var
to 1
.
0.99^[integer]
represents the one percent decline per year/value
These values is multiplied by the corresponding indexes in var
.
Finally, all values are summed up with sum()

- 917
- 5
- 12
I don't think you'll be able to do better than writing a for
loop for this one. There are packages that offer an exponential moving average, which is similar, but not quite the same.
decay_sum <- function(tm, vl, decay) {
last_time <- 0
current_sum <- 0
sums <- numeric(length(vl))
ldecay <- log(1-decay)
for (i in 1:length(vl)) {
delta <- as.numeric(tm[i] - last_time)
current_sum <- current_sum * exp(ldecay * delta/365) + vl[i]
last_time <- tm[i]
sums[i] <- current_sum
}
sums
}
As a test case:
> df2 <- data.frame(when=Sys.time() + 365 * 24 * 60 * 60 * 1:50,value=1)
> df2 %>% mutate(dis=decay_sum(when, value, .1))
when value dis
1 2019-08-29 10:35:32 1 1.000000
2 2020-08-28 10:35:32 1 1.900000
3 2021-08-28 10:35:32 1 2.710000
4 2022-08-28 10:35:32 1 3.439000
This assumes that the date column is ordered (so you can throw in an arrange
if necessary).

- 7,108
- 1
- 26
- 35
Do you want something like this ?
set.seed(1)
input <- sample(1:10,5)
input # [1] 3 4 5 7 2
decay = 0.01
output <- Reduce(function(x,y) x*(1-decay)+y,input,accumulate = TRUE)
output # [1] 3.00000 6.97000 11.90030 18.78130 20.59348
output[3] == 3*0.99^2 + 4*0.99 + 5 # [1] TRUE

- 46,417
- 11
- 121
- 167