Search code examples
rstandard-deviationpanel-data

R: Calculate Standard Deviations by Group with a Moving Window


I would love to analyze monthly stock returns for multiple companies (Panel Data). However, I am struggling with calculating the standard deviation for the last X months by company.

Basically, I want to add another column to my existing data.frame, in which the standard deviation according to a moving window of X months by company is shown. Please find below a simplified example of my data and what I would love to achieve.

#My data:
company = c("1","1","1","1","1","2","2","2","2","2","2","2","3","3","3","3","4","4","4")
return = c(0.01,0.015,-0.01,0.02,0.023,-0.04,-0.02,-0.01,0.05,0.06,0.03,-0.09,0.2,0.3,-0.04,-0.02,-0.01,0.023,-0.04)
stock = data.frame(company,return)

Given this initial situation, I would love to calculate the standard deviation in another column, based on e.g. 3 observations.

#Column to be filled with the respective value
stock["std_3obs"] = NA
#However, I do not manage to fill this column accordingly. The following result for a given row is expected:
#row 1 = Not possible, as there are not enough prior observations available
#row 2 = Not possible, as there are not enough prior observations available
#row 3 = sd(c(0.01,0.015,-0.01) = 0.01322876
#row 7 = Not possible, as there are not enough prior observations available
#row 8 = sd(c(-0.040,-0.020,-0.010)) = 0.01527525

Thanks a lot in advance! Any help is highly appreciated! Please be gentle, as I am fairly new to R.

*Side Note: Research on this issue and adapting other solutions always lead to this error: replacement has X rows, data has Y * where X >>> Y


Solution

  • You can use the rolling functions from zoo package :

    library(dplyr)
    
    stock %>%
      group_by(company) %>%
      mutate(std_3obs = zoo::rollapplyr(return, 3, sd, fill = NA))
    
    #  company return std_3obs
    #   <chr>    <dbl>    <dbl>
    # 1 1        0.01   NA     
    # 2 1        0.015  NA     
    # 3 1       -0.01    0.0132
    # 4 1        0.02    0.0161
    # 5 1        0.023   0.0182
    # 6 2       -0.04   NA     
    # 7 2       -0.02   NA     
    # 8 2       -0.01    0.0153
    # 9 2        0.05    0.0379
    #10 2        0.06    0.0379
    #11 2        0.03    0.0153
    #12 2       -0.09    0.0794
    #13 3        0.2    NA     
    #14 3        0.3    NA     
    #15 3       -0.04    0.175 
    #16 3       -0.02    0.191 
    #17 4       -0.01   NA     
    #18 4        0.023  NA     
    #19 4       -0.04    0.0315