Оценка бета по панельным данным по группам

Я нашел несколько предыдущих вопросов по этой теме, особенно этот R: Сгруппированная линейная регрессия скользящего окна с помощью rollapply и ddply и R: Rolling/moving avg по группе , однако оба вопроса не дали точного решения проблемы, с которой я столкнулся. В настоящее время я пытаюсь оценить бета-версию 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

person ruki ami    schedule 20.08.2017    source источник


Ответы (1)


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

EDIT: приведенный ниже код не воспроизводит желаемый результат, как указано выше, но в конце концов оказался тем, что искал OP.

Вот оно:

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

Для первых 8 строк в новом фрейме данных (fund = 1) это результат:

  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
person vestland    schedule 23.08.2017
comment
varX и varY определенно должны быть аргументами, а не жестко закодированы в функции. Я разберусь с этим завтра. - person vestland; 23.08.2017
comment
спасибо! Моя ошибка заключалась в том, что я написал coef(lm(as.formula(paste(ret_riskfree, ~, Benchmark_RiskFree,-1)) вместо coef(lm(as.formula(paste(ret_riskfree, ~, Benchmark_riskfree))[2] жаль, что это вызвало недоумение. - person ruki ami; 23.08.2017
comment
Я сделал аргументы функции из жестко запрограммированных переменных. В конце концов, кто-то может прийти и предложить более элегантное решение, но это работает. Ваш вопрос был интересным, хорошо объясненным с помощью воспроизводимого набора данных, поэтому я думаю, вы уже знаете, как обойти SO, но я был бы признателен, если бы вы рассмотрели возможность взглянуть на эта ссылка, если предложение было полезным. - person vestland; 24.08.2017