提取模型摘要并将其存储为新列
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
包中的 map
和 glance
。
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 中的新列?