【问题标题】:Beta estimation over panel data by group按组对面板数据进行 Beta 估计
【发布时间】:2017-08-20 15:57:09
【问题描述】:

我发现了有关此主题的一些先前问题,尤其是 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)

我想对“fund”列指示的每个组的两列 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

【问题讨论】:

    标签: r linear-regression rollapply


    【解决方案1】:

    正如我在上面的评论中提到的,这个解决方案可能有点不对劲,因为我无法 100% 地重现您想要的输出。尽管如此,您想要完成的功能仍然存在。看看它,让我知道这是你可以使用的东西,或者我可以进一步开发。

    编辑:下面的代码没有重现上面指定的所需输出,但最终证明是 OP 正在寻找的。​​p>

    这里是:

    # 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
    

    【讨论】:

    • varX 和 varY 绝对应该是参数,而不是在函数中硬编码。明天我会解决的。
    • 谢谢!我的错误是写 coef(lm(as.formula(paste(ret_riskfree, "~", benchmark_riskfree,-1)),而不是 coef(lm(as.formula(paste(ret_riskfree, "~", benchmark_riskfree))[ 2] 抱歉,这造成了混乱。
    • 我用硬编码的变量制作了函数参数。最终,有人可能会提出一个更优雅的解决方案,但这确实有效。你的问题很有趣,用可重现的数据集很好地解释了,所以我想你已经知道你的方式了,但是如果你考虑看看 this link 如果建议有用的话,我会很感激。
    猜你喜欢
    • 2018-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-28
    • 2013-01-20
    相关资源
    最近更新 更多