【问题标题】:How can I speed up a rolling regression with multiple conditions in r?如何在 r 中加速具有多个条件的滚动回归?
【发布时间】:2022-01-17 07:30:53
【问题描述】:

我有一个相当大的数据集(大约 1200 万行),我需要对包含过去 30 行条目的每一行运行滚动回归。这是一个简单的线性回归,但回归需要考虑两个因素:股票和需要运行的时间窗口。我已经找到了一种方法来运行我的 1200 万次回归,但不幸的是,这种方法需要的时间太长了。 lm() 做的工作太多,因为我只需要回归的截距和系数,但使用更简单的线性回归,例如 lmfit/lm.fit/lmList 等,到目前为止我还无法包含我的两个条件。 我也尝试过并行化回归,但由于我是初学者,我没有成功。 你能帮我尽可能加快这个计算吗?

代码:

regression <- df %>%
              rowwise() %>% 
              droplevels()%>%
              mutate(mod = list(lm(returns ~ Factor1 + Factor2 + Factor3 + Factor4,
                                   data = filter(df,
                                                 Stock == .env$Stock,
                                                 date <= .env$date,
                                                 date >= .env$datemonthbefore))))

regressionestimates <- regression %>%
  mutate(res = list(broom::tidy(mod)),
         broom::glance(mod)) %>% 
  select(date,
         Stock,
         res,
         nobs) %>% 
  unnest(res) 

【问题讨论】:

  • 我发现rowwise 让一切变得非常缓慢。也许一次做一个Stock。如果数据按date 排序,则使用 for 循环并按顺序对 30 个连续行进行子集化。
  • @MichaelDewar 非常感谢您的回答!所以你会做两个嵌套循环,一个用于股票,一个用于日期?我有大约 5000 只股票要回归。到目前为止,我对大量数据进行循环的经验并不是很好。
  • 是的。我尝试了两个循环的答案。 (purrr::map 隐含地是一个循环。)

标签: r regression large-data lm


【解决方案1】:

我确信有更快的方法可以做到这一点,但这很有效。 (我认为。)

library(tidyverse)

set.seed(1000)

df <- tibble(date = rep(16001:19000, 5000),
             Stock = rep(1:5000, each = 3000)) %>%
    mutate(date = as.Date(date, origin = "1969-12-31"),
           returns = rnorm(15e6),
           Factor1 = rnorm(15e6),
           Factor2 = rnorm(15e6),
           Factor3 = rnorm(15e6),
           Factor4 = rnorm(15e6)) %>%
    nest(data = -Stock)

fit_one_stock <- function(data, window_size = 30L){
    data <- data %>% arrange(date)
    data.matrix <- as.matrix(data[,,drop = FALSE])
    steps <- nrow(data)-window_size

    output <- vector("list", steps+1)

    for(i in 0:steps){
        this_data <- data.matrix[(1+i):(window_size+i),,drop = FALSE]
        output[[i+1]]  <- coef(.lm.fit(cbind(1,this_data[,c("Factor1", "Factor2", "Factor3", "Factor4")]), this_data[,"returns"])) %>%
            setNames(c("(Intercept)", "Factor1", "Factor2", "Factor3", "Factor4"))
    }

    output

    bind_rows(output) %>%
        bind_cols(date = data[window_size:nrow(data),1])
}

tictoc::tic()
df2 <- df %>% #head(100) %>%
    mutate(models = map(data, fit_one_stock))
tictoc::toc()

df2 %>% select(-data) %>% unnest(models)

【讨论】:

  • 一段时间后我又回到了这个问题上,因为起初它对我没有用。现在我找到了一种运行它的方法,但我仍在努力解决未嵌套的部分。你知道即使它没有效率我怎么能取消嵌套? “df3 % unnest(cols = c(data, models))” 对我不起作用,因为它说“错误:在第 1 行,无法将大小 2015 的输入回收到大小 1890。”跨度>
  • @ABCE,我已经更新了答案。我在函数 fit_one_stock 中做了一些更改。
  • 更新后的解决方案运行顺利,我的数据集并没有花太长时间。谢谢!
猜你喜欢
  • 1970-01-01
  • 2021-02-09
  • 2019-09-25
  • 2023-03-08
  • 2016-05-07
  • 2021-09-14
  • 1970-01-01
  • 2020-09-30
  • 1970-01-01
相关资源
最近更新 更多