1

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.

Marco
  • 11
  • 2
  • 4
    A [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 Answers4

0

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)
0

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()

P1storius
  • 917
  • 5
  • 12
0

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).

user295691
  • 7,108
  • 1
  • 26
  • 35
0

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
moodymudskipper
  • 46,417
  • 11
  • 121
  • 167