首页 文章

按组分组对面板数据的Beta估计

提问于
浏览
1

我发现了一些关于这个主题的先前问题,尤其是R: Grouped rolling window linear regression with rollapply and ddplyR: Rolling / moving avg by group,但是,这两个问题都没有为我所面临的问题提供精确的解决方案 . 我目前正在尝试使用线性回归估计CAPM beta而不是面板数据 . 所以我有不同的资金(在下面的例子中我使用了3个基金组),我想分别和每行计算beta . 为了使这更抽象:我试图用一个移动的窗口按组进行线性回归,以根据窗口中的数据估算每一行的系数 .

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]进行滚动回归 . 计算应该单独进行,因此每个基金组的beta列中的前两行将始终显示“NA” . 最后,我希望得到一个包含所有基金组和所有beta值的完整数据框 . 我设法提出了一个新的代码,但它非常混乱,它需要在执行之前按基金和日期订购数据 . 我欢迎任何有关如何使其变得更好的建议 .

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 回答

  • 0

    正如我在上面的评论中提到的,这个解决方案可能有点偏,因为我无法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))
    
    #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
    

相关问题