【问题标题】:How do I forecast a time series with multiple companies in R?如何在 R 中预测多个公司的时间序列?
【发布时间】:2021-12-09 10:48:37
【问题描述】:

我有一个跨越 5 年的数据框,其中包含约 500 家公司和几个基本统计数据(例如销售额、#员工数、ROA)。这是一个看起来如何的示例。请注意,所有数字都是完全随机选择的,显然年份除外。

Name Year Sales Size ROA
Firm A 2020 857 12000 0.45
Firm B 2020 112 3500 0.32
Firm C 2020 666 7000 0.44
Firm A 2019 860 12000 0.47
Firm B 2019 150 3000 0.31
Firm C 2019 700 6000 0.44
... ... ... ... ...
Firm A 2015 560 10000 0.47
Firm B 2015 100 2000 0.31
Firm C 2015 300 4000 0.44

您建议我如何尝试预测每家公司的 2021 年 ROA,并考虑 5 年(2015 年 - 2020 年)的跨度?我试着玩弄forecast 包。但是,我还没有找到对所有公司进行批量操作的方法。我希望最终得到这样的结果:

Name Year predicted ROA
Firm A 2021 0.50
Firm B 2021 0.35
Firm C 2021 0.43

我会非常感谢任何线索!

【问题讨论】:

  • 使用 fable 包。 fable.tidyverts.org
  • 嗨@RobHyndman 我看过它,但似乎无法弄清楚如何为多家公司执行此操作。给出的示例仅适用于一个特定的公司(或时间序列)。在这里,我有多个时间序列。知道如何解决这个问题吗?

标签: r time-series tibble forecast


【解决方案1】:

实际上有很多方法可以做到这一点。我的以下解决方案可能有点矫枉过正,不是预测您的问题的理想方法,但只是用于时间序列预测的可扩展模型工作流的表示。

查看下面的代码,如果它给你一些有趣的结果,请告诉我。一旦习惯了 tidymodels 堆栈和 modeltime 框架,这种数据就会变得很容易处理。

suppressPackageStartupMessages(library(tidyverse))
suppressPackageStartupMessages(library(tidymodels))
suppressPackageStartupMessages(library(modeltime))
suppressPackageStartupMessages(library(modeltime.ensemble))


#### DATA

h = 1

data <- data.frame(
  id = rep(paste("Firm",c("A","B","C")),6),
  date = rep(2015:2020, rep(3,6)),
  value = runif(18)
)

data <- data %>% 
  pivot_wider(names_from = id, values_from = value)

data <- reshape2::melt(data, id.var='date')
dates <- ymd("2015-01-01")+ years(0:5)
dates <- rep(dates,3)
data$date <- dates
names(data)[2] = "id"

data <- data %>%
  group_by(id) %>%
  future_frame(
    .length_out = h,
    .bind_data  = TRUE) %>%
  ungroup() %>% 
  as_tibble() 

# training- and test set
data_splits <- time_series_split(data, assess = "1 year", cumulative = TRUE)



#### PREDICT

model_fit_glmnet <- linear_reg(penalty = 1) %>%
  set_engine("glmnet") %>%
  fit(value ~ ., data = training(data_splits))

model_fit_xgboost <- boost_tree("regression",  learn_rate = 0.35) %>%
  set_engine("xgboost") %>%
  fit(value ~ ., data = training(data_splits))

ensemble <- modeltime_table(
  model_fit_glmnet,
  model_fit_xgboost
) %>%
  ensemble_weighted(loadings = c(4, 6)) 

model_tbl <- modeltime_table(ensemble)

forecast <-
  model_tbl %>%
  modeltime_forecast(
    new_data    = testing(data_splits),
    actual_data = data,
    keep_data = T
  ) %>%
  group_by(id)  


# change layout
forecast <- forecast %>% filter(str_detect(.key,  "prediction")
)
forecast <- forecast[,c(4,5,6)]

【讨论】:

    【解决方案2】:

    fable 包是为这类事情设计的。这是一个模拟问题中数据结构的人工示例。

    library(tidyverse)
    library(fable)
    # Synthetic data
    df <- tibble(
      Name = rep(paste("Firm",c("A","B","C")),6),
      Year = rep(2015:2020, rep(3,6)),
      ROA = runif(18)
    )
    # Turn it into a tsibble object
    df_ts <- df %>%
      as_tsibble(index=Year, key=Name)
    # Forecast each firm
    fc <- df_ts %>%
      model(ARIMA(ROA)) %>%
      forecast(h=1)
    fc
    #> # A fable: 3 x 5 [1Y]
    #> # Key:     Name, .model [3]
    #>   Name   .model      Year           ROA .mean
    #>   <chr>  <chr>      <dbl>        <dist> <dbl>
    #> 1 Firm A ARIMA(ROA)  2021 N(0.52, 0.14) 0.517
    #> 2 Firm B ARIMA(ROA)  2021 N(0.59, 0.07) 0.587
    #> 3 Firm C ARIMA(ROA)  2021 N(0.52, 0.11) 0.522
    

    reprex package (v2.0.1) 于 2021 年 10 月 26 日创建

    这里我使用了 ARIMA 模型,但也可以使用许多其他模型。请参阅我在https://OTexts.com/fpp3 的教科书,了解许多将寓言与 ARIMA 和其他模型结合使用的示例。

    【讨论】:

      【解决方案3】:

      我喜欢使用 mgcv::gam 进行预测。
      我使用了最简单的模型,其中 ROA 仅取决于名称和年份的平滑函数。
      您需要增加 k,具体取决于您拥有的数据量(默认为 10)。
      by 变量用于按名称拆分模型。

      df <- structure(list(Name = c("Firm A", "Firm B", "Firm C", "Firm A", 
                              "Firm B", "Firm C", "Firm A", "Firm B", "Firm C"), 
                           Year = c(2020L, 2020L, 2020L, 2019L, 2019L, 2019L, 2015L, 2015L, 2015L), 
                           Sales = c(857L, 112L, 666L, 860L, 150L, 700L, 560L, 100L, 300L), 
                           Size = c(12000L, 3500L, 7000L, 12000L, 3000L, 6000L, 10000L, 2000L, 4000L), 
                           ROA = c(0.45, 0.32, 0.44, 0.47, 0.31, 0.44, 0.47, 0.31, 0.44)), 
                      row.names = c(NA, -9L), class = "data.frame")
      gamfit <- mgcv::gam(formula = ROA ~ Name + s(Year, k = 3, by = as.factor(Name)), data = df)
      summary(gamfit)
      predict_df <- data.frame(Name = sort(unique(df$Name)), 
                               Year = 2021L)
      predict_df$ROA <- predict(gamfit, newdata = predict_df)
      
      predict_df
          Name Year       ROA
      1 Firm A 2021 0.3969841
      2 Firm B 2021 0.4098413
      3 Firm C 2021 0.4055556
      

      【讨论】:

      • 谢谢布赖恩。不幸的是,当尝试将 df 扩展到 20 家公司(更不用说 500 家公司)时,我收到“'Calloc' 无法分配内存”的错误消息。知道如何解决这个问题吗?
      • 我很惊讶你只用了 20 个就遇到了内存问题。我唯一的想法是使用 for 循环来循环遍历名称。 gam 有一个子集参数。
      猜你喜欢
      • 2021-10-10
      • 2020-02-08
      • 2015-10-02
      • 1970-01-01
      • 2020-12-23
      • 2020-06-13
      • 1970-01-01
      • 2015-05-19
      • 2020-09-05
      相关资源
      最近更新 更多