Бета-оценка по групповым данным по группам

Я нашел несколько предыдущих вопросов по этой теме, особенно это : линейная регрессия скользящего окна с группировкой с помощью rollapply и ddply и R: скользящая / скользящая средняя по группе, однако оба вопроса не дали точного решения проблемы, с которой я столкнулся. В настоящее время я пытаюсь оценить CAPM бета по данным панели с помощью линейной регрессии. Таким образом, у меня есть разные фонды (в приведенном ниже примере я использовал 3 группы фондов), для которых я хотел бы рассчитывать бета-версии отдельно и для каждой строки. Чтобы поместить это более абстрактно: я пытаюсь сделать линейную регрессию с движущимся окном по группам, чтобы оценить коэффициент для каждой строки на основе данных в окне.

install.packages("zoo","dplyr")
library(zoo);library(dplyr)

# Create dataframe
fund <- as.numeric(c(1,1,1,1,1,1,1,1,3,3,3,3,3,3,2,2,2,2,2,2,2))
return<- as.numeric(c(1:21))
benchmark <- as.numeric(c(1,13,14,20,14,32,4,1,5,7,1,0,7,1,-2,1,6,-7,9,10,9))
riskfree<-as.numeric(c(1,5,1,2,1,6,4,7,5,-5,10,0,3,1,2,1,6,7,8,9,10))
date <- as.Date(c("2010-07-30","2010-08-31","2010-09-30","2010-10-31","2010-11-30","2010-12-31","2011-01-30",
              "2011-02-28","2010-07-31","2010-09-30","2010-10-31","2010-11-30","2010-12-31","2011-01-30",
              "2010-07-30","2010-08-31","2010-09-30","2010-10-31","2010-11-30","2010-12-31","2011-01-30"))
funddata<-data.frame(date,fund,return,benchmark,riskfree)

# Creating variables of interest
funddata["ret_riskfree"]<-as.numeric(funddata$return-funddata$riskfree)
funddata["benchmark_riskfree"]<-as.numeric(funddata$benchmark-funddata$riskfree)

Я хочу сделать скользящую регрессию по двум столбцам df[6:7] для каждой группы, указанной в столбце "фонд". Расчет должен быть сделан отдельно, поэтому первые две строки в столбце бета для каждой группы фондов всегда будут отображать "NA". В конце я хочу получить полный фрейм данных со всеми группами фондов и всеми бета-значениями вместе взятыми. Мне удалось придумать новый код, который работает, но довольно грязный и требует упорядочения данных по фондам и дате перед выполнением. Буду рад любым предложениям, как сделать это лучше.

 funddata <- funddata[order(funddata$fund, funddata$date),]   
 beta_func <- function(x, benchmark_riskfree, ret_riskfree) {
  a <- coef(lm(as.formula(paste(ret_riskfree, "~", benchmark_riskfree,-1)), 
           data = x))
  return(a)
}
beta_list<-list()
for (i in c(1:3)){beta_list[[paste(i, sep="_")]]<-    (rollapplyr(funddata[(funddata$fund==i),6:7], width = 3,
           FUN = function(x) beta_func(as.data.frame(x), "benchmark_riskfree" ,   "ret_riskfree"),
           by.column = FALSE,fill=NA))}
beta_list<-unlist(beta_list, recursive=FALSE)
funddata$beta<-beta_list

1 ответ

Решение

Как я уже упоминал в комментарии выше, это решение может быть немного устаревшим, так как я не могу воспроизвести желаемый результат на 100%. Тем не менее, функциональность того, что вы пытаетесь достичь, есть. Посмотрите на это и дайте мне знать, если это то, что вы могли бы использовать, или я мог бы развиваться дальше.

РЕДАКТИРОВАТЬ: приведенный ниже код не воспроизводит желаемый результат, как указано выше, но, в конце концов, оказался тем, что искал ОП.

Вот оно:

# Datasource
fund <- as.numeric(c(1,1,1,1,1,1,1,1,3,3,3,3,3,3,2,2,2,2,2,2,2))
return<- as.numeric(c(1:21))
benchmark <- as.numeric(c(1,13,14,20,14,32,4,1,5,7,1,0,7,1,-2,1,6,-7,9,10,9))
riskfree<-as.numeric(c(1,5,1,2,1,6,4,7,5,-5,10,0,3,1,2,1,6,7,8,9,10))
date <- as.Date(c("2010-07-30","2010-08-31","2010-09-30","2010-10-31","2010-11-30","2010-12-31","2011-01-30",
                  "2011-02-28","2010-07-31","2010-09-30","2010-10-31","2010-11-30","2010-12-31","2011-01-30",
                  "2010-07-30","2010-08-31","2010-09-30","2010-10-31","2010-11-30","2010-12-31","2011-01-30"))
funddata<-data.frame(date,fund,return,benchmark,riskfree)

# Creating variables of interest
funddata["ret_riskfree"]<-as.numeric(funddata$return-funddata$riskfree)
funddata["benchmark_riskfree"]<-as.numeric(funddata$benchmark-funddata$riskfree)

# Target check #################################################################
# Subset last three rows in original dataframe
df_check <- funddata[funddata$fund == 1,]
df_check <- tail(df_check,3)

# Run regression check
mod_check <- lm(df_check$ret_riskfree~df_check$benchmark_riskfree)
coef(mod_check)

# My suggestion ################################################################
# The following function takes three arguments:
# 1. a dataframe, myDf
# 2. a column that you'd like to myDf on
# 3. a window length for a sliding window, myWin

fun_rollreg <- function(myDf, subCol, varY, varX, myWin){
  df_main <- myDf

  # Make an empty data frame to store results in
  df_data <- data.frame()

  # Identify unique funds
  unFunds <- unique(unlist(df_main[subCol]))

  # Loop through your subset
  for (fundx in unFunds){

    # Subset
    df <- df_main
    df <- df[df$fund == fundx,]

    # Keep a copy of the original until later
    df_new <- df

    # Specify a container for your beta estimates
    betas <- c()

    # Specify window length
    wlength <- myWin

    # Retrieve some data dimensions to loop on
    rows = dim(df)[1]
    periods <- rows - wlength

    # Loop through each subset of the data
    # and run regression
    for (i in rows:(rows - periods)){

        # Split dataframe in subsets
        # according to the window length
        df1 <- df[(i-(wlength-1)):i,]

        # Run regression
        beta <- coef(lm(df1[[varY]]~df1[[varX]]))[2]

        # Keep regression ressults
        betas[[i]] <- beta
    }
    # Add regression data to dataframe
    df_new <- data.frame(df, betas)

    # Keep the new dataset for later concatenation
    df_data <- rbind(df_data, df_new)
  }   
  return(df_data)
}

# Run the function:
df_roll <- fun_rollreg(myDf = funddata, subCol = 'fund',
                      varY <- 'ret_riskfree', varX <- 'benchmark_riskfree',
                      myWin = 3)
# Show the results
print(head(df_roll,8))

#For the first 8 rows in the new dataframe (fund = 1), this is the result:


            date fund return benchmark riskfree ret_riskfree benchmark_riskfree       betas
1 2010-07-30    1      1         1        1            0                  0          NA
2 2010-08-31    1      2        13        5           -3                  8          NA
3 2010-09-30    1      3        14        1            2                 13  0.10465116
4 2010-10-31    1      4        20        2            2                 18  0.50000000
5 2010-11-30    1      5        14        1            4                 13 -0.20000000
6 2010-12-31    1      6        32        6            0                 26 -0.30232558
7 2011-01-30    1      7         4        4            3                  0 -0.11538462
8 2011-02-28    1      8         1        7            1                 -6 -0.05645161
Другие вопросы по тегам