提取模型摘要并将其存储为新列

Posted

技术标签:

【中文标题】提取模型摘要并将其存储为新列【英文标题】:Extract model summaries and store them as a new column 【发布时间】:2017-04-17 06:00:41 【问题描述】:

我是 purrr 范式的新手,我正在努力解决它。

根据一些资料,我已经设法嵌套数据框,对嵌套数据运行线性模型,从每个 lm 中提取一些系数,并为每个 lm 生成摘要。我想做的最后一件事是从摘要中提取“r.squared”(我原以为这是我想要实现的最简单的部分),但无论出于何种原因,我都无法获得语法正确的。

这是我所拥有的 MWE:

library(purrr)
library(dplyr)
library(tidyr)

mtcars %>%
  nest(-cyl) %>%
  mutate(fit = map(data, ~lm(mpg ~ wt, data = .)),
         sum = map(fit, ~summary))

这是我提取失败的 r.squared 的尝试:

mtcars %>%
  nest(-cyl) %>%
  mutate(fit = map(data, ~lm(mpg ~ wt, data = .)),
         sum = map(fit, ~summary),
         rsq = map_dbl(sum, "r.squared"))
Error in eval(substitute(expr), envir, enclos) : 
  `x` must be a vector (not a closure)

这与 RStudio 网站上给出的示例表面上相似:

mtcars %>%
  split(.$cyl) %>%
  map(~ lm(mpg ~ wt, data = .x)) %>%
  map(summary) %>%
  map_dbl("r.squared")

这可行,但是我希望 r.squared 值位于新列中(因此是 mutate 语句),并且我想了解为什么我的代码无法正常工作,而不是解决问题。

编辑:

这是一个可行的解决方案,我使用以下解决方案:

mtcars %>%
      nest(-cyl) %>% 
      mutate(fit = map(data, ~lm(mpg ~ wt, data = .)),
             summary = map(fit, glance),
             r_sq = map_dbl(summary, "r.squared"))

编辑2:

因此,实际上该错误来自于在 summary = map(fit, ~summary) 行中包含波浪号键。我的猜测是使对象成为嵌套的函数,而不是摘要本身返回的对象。如果有人想插话,希望对此有权威的回答。

需要明确的是,这个版本的原始代码可以正常工作:

mtcars %>%
  nest(-cyl) %>%
  mutate(fit = map(data, ~lm(mpg ~ wt, data = .)),
         summary = map(fit, summary),
         r_sq = map_dbl(summary, "r.squared"))

【问题讨论】:

【参考方案1】:

为了适应您当前的管道,您需要使用 unnest 以及 broom 包中的 mapglance

library(tidyr)
library(dplyr)
library(broom)

mtcars %>%
  nest(-cyl) %>%
  mutate(fit = map(data, ~lm(mpg ~ wt, data = .))) %>% 
  unnest(map(fit, glance))

您将获得的不仅仅是 r-squared,您还可以使用 select 删除不需要的内容。

如果您想将模型摘要嵌套在列表列中:

mtcars %>%
  nest(-cyl) %>% 
  mutate(fit = map(data, ~lm(mpg ~ wt, data = .)),
         summary = map(fit, glance)) 

如果您只想从嵌套框架中提取单个值,您只需将map 用于实际值(而不是我最初建议的[[extract2,非常感谢您发现这一点) .

mtcars %>%
  nest(-cyl) %>% 
  mutate(fit = map(data, ~lm(mpg ~ wt, data = .)),
         summary = map(fit, glance),
         r_sq = map_dbl(summary, "r.squared"))

【讨论】:

嗯,这似乎是我想要做的,我只是对为什么以这种方式构造代码感到困惑。我不明白你为什么要取消数据?你能解释一下吗?感谢您的回答! 使用unnest 将数据框从列表列中取出,并将所有可用列分散到父数据框。您可以将其保持嵌套,但无法直接访问 r-squared 列。我将更新答案以使代码没有unnest 所以 unnest 是针对 map(fit, ~glance) 语句的结果,我认为它是在取消嵌套嵌套的小标题(这是我感到困惑的地方)。这种方法也规避了使用摘要制作总和列的要求,对吧?如果我明白;第二个版本中的 coeffs 列将包含相同的信息(尽管格式不同)。我有没有办法从总和列中提取“r.squared”?只是我看到自己再次碰到了这堵墙,我有一个嵌套列表,我只想从中提取一个元素。 你是对的。我添加了用于从列表列中的嵌套数据框中提取单列的方法。我还清理了代码,有 2 个汇总图毫无意义,可以通过将 glance 映射到 fit 一步完成。 奇怪的是,我编写 map_dbl 行的方式没有任何问题,只是无法处理摘要返回的对象。与一瞥完美结合。好像有点奇怪。。【参考方案2】:

一定有更好的方法,这是我对管道的尝试:

mtcars %>%
  split(.$cyl) %>%
  map(~ lm(mpg ~ wt, data = .x)) %>%
  map(summary) %>%
  map_dbl("r.squared") %>% 
  list() %>% 
  as.data.frame(col.names = "r.squared") %>% 
  add_rownames(var = "cyl")

# # A tibble: 3 × 2
#     cyl r.squared
#   <chr>     <dbl>
# 1     4 0.5086326
# 2     6 0.4645102
# 3     8 0.4229655

注意:您可能会收到以下警告。

警告消息:已弃用,请改用 tibble::rownames_to_column()。

【讨论】:

谢谢,确实有更好的办法;检查我在 OP 上的编辑 @zx8754 我很难理解为什么map_dbl("r.squared") 在这个例子中起作用。我的意思是"r.squared" 不是一个函数,那么这个提取究竟是如何进行或应用的呢?你能澄清一下吗? :)【参考方案3】:

我认为对于您想要实现的目标,您最好使用 broom 包中的 glance() 函数:

library(broom)
library(dplyr)
mtcars %>%
  group_by(cyl) %>%
  do(glance(lm(mpg ~ wt, data = .))) %>%
  select(cyl, r.squared)
#    cyl r.squared
#  <dbl>     <dbl>
#1     4 0.5086326
#2     6 0.4645102
#3     8 0.4229655

【讨论】:

这确实得到了所需的输出,但是(抱歉我很挑剔)我真的很想找到一个在我拥有的当前管道中工作的实现。我确信有一种方法,这只是获得正确语法的一个例子。感谢您的回答 如果你想要的只是 lm 模型的结果,这是一个更简单的答案。但是,@jake-kaupp 的解决方案保留了解决方案中的原始变量和模型,这在某些情况下可能很有用,例如从用户定义的函数返回输出。

以上是关于提取模型摘要并将其存储为新列的主要内容,如果未能解决你的问题,请参考以下文章

是否有更快的方法来获取基于线性回归模型的值并将其附加到 DataFrame 中的新列?

如何修改查询集并将其保存为新对象?

在仪表板上显示模型摘要

如果值=1(二进制值),则提取列名并将它们与分隔符组合并将其放入新列中

将向量合并为 df,并将向量名称转换为新列的行

从文件名中提取时间戳并使用 Pig 将其添加到新列(例如日期)中