为每个因子水平拟合一个 `lm` 模型。

3
我正在尝试编写一个函数,用于迭代(或使用purrr :: map())因子的每个级别,并为因子等于该级别的数据子集拟合lm()模型。
为了使用mtcars创建一个简单的可重现示例,只需说我想要针对mtcars $ gear 的每个值都有一个不同的lm模型。 我将首先将其作为因子进行处理,因为我的实际问题涉及通过因子进行迭代:
library(tidyverse)

mtcars <- mtcars %>% 
  mutate(factor_gear = factor(gear))

我希望该函数适用于每个 factor_gear 级别。这些级别由以下给出:

levels(mtcars$factor_gear)

即:
  [1] "3" "4" "5"

所需要的输出应该是:“

所以我想要的输出是:

”。
fit1 <- lm(mpg ~ cyl, data = mtcars %>% filter(factor_gear=="3"))
fit2 <- lm(mpg ~ cyl, data = mtcars %>% filter(factor_gear=="4"))
fit3 <- lm(mpg ~ cyl, data = mtcars %>% filter(factor_gear=="5"))

fits <- list(fit1, fit2, fit3)

我已经开始编写这个函数,但是无法让它正常工作。
我认为一个函数应该:
  1. 将因子的每个水平值转化为一个向量
  2. 对每个水平值运行一个lm模型。
fit_each_level <- function(factor_variable) {

  # trying to: 1. get every level of of the factor into a vector
  factor_levels <- levels(df_cars$factor_variable)

  # trying to: 2. run an lm model for each level.
  for i in factor_levels {
    fit <- mtcars %>% filter(factor_variable==i [# every value of segment_levels]) %>% 
    lm(mpg ~ cyl, data = . )
  }

}

fit_each_level(factor_gear)

如果函数运行良好,我最终可以在另一个因素上进行操作,例如:
mtcars <- mtcars %>% 
  mutate(factor_carb = factor(carb))

fit_each_level(factor_carb)

您可以按因子进行分组,然后按组运行lm。请注意,这可能会影响标准误差(使用mpg ~ cyl*factor_gear在按组运行时可能与mpg ~ cyl得到不同的标准误差)。 - MichaelChirico
2个回答

5

对于 dplyr 1.1.0 及以上版本,新的语法应该是 -

library(dplyr)

mtcars %>%
  summarise(model = list(lm(mpg ~ cyl, data = pick(everything()))), 
           .by = factor_gear)

你可以为每个 factor_gear 嵌套数据框并使用 map 应用 lm

library(dplyr)

mtcars %>%
  group_by(factor_gear) %>%
  tidyr::nest() %>%
  mutate(model = map(data, ~lm(mpg ~ cyl, data = .x)))

#  factor_gear data               model 
#  <fct>       <list>             <list>
#1 4           <tibble [12 × 11]> <lm>  
#2 3           <tibble [15 × 11]> <lm>  
#3 5           <tibble [5 × 11]>  <lm>  

在新的dplyr中,您可以使用cur_data来引用组中的当前数据,从而避免了nestmap的需要。
mtcars %>%
  group_by(factor_gear) %>%
  summarise(model = list(lm(mpg ~ cyl, data = cur_data())))

谢谢,这太不可思议了,这会让我的代码变得简单多了。对于你的最佳解决方案,我有一个关于mutate(model = map(data, ~lm(mpg ~ cyl, data = .x)))的问题。当你首次提到data,比如= map(data时,它看起来好像还没有在其他地方声明或赋值。它是如何工作的?它是从后面的data = .x获得的吗? - Jeremy K.
这实际上来自于 nestnest 会创建一个包含数据框的列表列,默认列名为 data。如果你只运行 mtcars %>% group_by(factor_gear) %>% tidyr::nest(),你就会看到这个结果。 - Ronak Shah
对于未来阅读此内容的任何人来说,这个链接是学习更多的好方法:https://r4ds.had.co.nz/many-models.html - Jeremy K.
cur_data()已被弃用,请改用pick()函数 - Adonis Cedeño

2

确保您拥有最新版本的dplyr(1.0.0)。然后可以使用:

model_coefs <- function(formula, data) {
  coefs <- lm(formula, data)$coefficients
  data.frame(coef = names(coefs), value = coefs)
}

mtcars %>%
  dplyr::mutate(factor_gear = factor(gear)) %>%
  dplyr::nest_by(factor_gear) %>%
  dplyr::summarise(model_coefs(mpg ~ cyl, data)) %>% 
  tidyr::pivot_wider(names_from = coef, values_from = value)

# A tibble: 3 x 3
# Groups:   factor_gear [3]
  factor_gear `(Intercept)`   cyl
  <fct>               <dbl> <dbl>
1 3                    29.8 -1.83
2 4                    41.3 -3.59
3 5                    40.6 -3.2 


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接