对 df 中的每个预测变量使用 purrr 映射进行多个线性回归

Using purrr map for several linear regressions for each predictor in df

我正在尝试 运行 许多具有一个 Y 变量和许多 x 变量的单独线性回归。我的数据有 300 多个 x 变量。我一直在尝试用 purrr 和 broom 来做到这一点,但无法弄清楚如何获得我想要的输出。

示例:

iris <- iris %>% 
  select_if(is.numeric)

iris %>% 
  map(~lm(Sepal.Length ~ .x, data = iris)) %>% 
  map(summary) %>% 
  map_df(tidy)

这会产生以下输出:

# A tibble: 6 x 5
  term        estimate std.error statistic   p.value
  <chr>          <dbl>     <dbl>     <dbl>     <dbl>
1 (Intercept)    0      3.79e-17   0.      1.00e+  0
2 .x             1      6.43e-18   1.56e17 0.       
3 (Intercept)    6.53   4.79e- 1   1.36e 1 6.47e- 28
4 .x            -0.223  1.55e- 1  -1.44e 0 1.52e-  1
5 (Intercept)    4.31   7.84e- 2   5.49e 1 2.43e-100
6 .x             0.409  1.89e- 2   2.16e 1 1.04e- 47

这与我要找的很接近,但不完全是!我希望变量名称位于此处的 'term' 列中,我不希望为每个模型粘贴截距。我正在寻找更像的结果:

# A tibble: 6 x 5
  term        estimate std.error statistic   p.value
  <chr>          <dbl>     <dbl>     <dbl>     <dbl>
1 Sepal.Width    0      3.79e-17   0.      1.00e+  0
2 Petal.Width    1      6.43e-18   1.56e17 0.       
3 Petal.Length   6.53   4.79e- 1   1.36e 1 6.47e- 28

对于达到这一点的任何帮助将不胜感激!!当然还要特别感谢对过程的解释(我正在学习)

干杯

lm() 遵循一组称为非标准求值的特殊规则,它在计算中使用部分表达式。这是一个显示差异的简单示例:

a <- "purrr"

print(a)        # Standard evaluation - expression a is evaluated to its value
# [1] "purrr"

library(a)      # Non-standard evaluation - expression a is used as-is
# Error in library(a) : there is no package called ‘a’

类似地,lm() 使用表达式 Sepal.Length ~ .x 的一部分,这就是为什么您在输出中看到 .x,而不是 map() 放入 .x。这里有几个选项可以解决这个问题。

选项 1:构造和计算表达式 "by hand"

colnames(iris) %>%                                # Start with all column names
    setdiff( "Sepal.Length" ) %>%                 # ...that are not Sepal.Length
    rlang::syms() %>%                             # Convert them to symbols
    map( ~rlang::expr(lm(Sepal.Length ~ !!.x,
                         data=iris)) ) %>%        # Create expressions
    map( eval.parent ) %>%                        # Evaluate expressions
    map( broom::tidy ) %>%                        # Tidy up the output
    bind_rows() %>%                               # Combine into a single data frame
    filter( term != "(Intercept)" )               # Drop all (Intercept) entries

在这里,!!.x 将用存储在其中的符号替换 .x。此 map() 步骤的输出将是一组看起来与您想要的完全一样的表达式:

lm(Sepal.Length ~ Sepal.Width, data = iris)
lm(Sepal.Length ~ Petal.Length, data = iris)
lm(Sepal.Length ~ Petal.Width, data = iris)

选项 2:自己注释行

iris %>%
    select( -Sepal.Length ) %>%                   
    map( ~lm(Sepal.Length ~ .x, data=iris) ) %>%    # As before
    map( broom::tidy ) %>%                          # Tidy up the output
    map( filter, term != "(Intercept)" ) %>%        # Remove (Intercept) entries
    map( select, -term ) %>%                        # Remove the default term column
    bind_rows( .id="term" )                         # Make your own from the list names