【问题标题】:How to use broom::tidy with multiple models?如何在多个模型中使用 broom::tidy?
【发布时间】:2022-05-16 05:29:42
【问题描述】:

我正在尝试使用扫帚来总结 19 个多项式回归模型的结果。我已经关注了这个SO Question 并尝试将它与broom::tidy 一起使用。我的脚本如下:

ALTER PROCEDURE [dbo].[spRegressionPeak]
@StudyID int
AS
BEGIN
Declare @sStudyID VARCHAR(50)
Set @sStudyID = CONVERT(VARCHAR(50),@StudyID)

--We are selecting the distinct StudyID, Productnumber, ResponseID and mean 
values 1 thorugh 6 from the CodeMeans table.  
--Note that spCodeMeans must be run before running this stored procedure to 
ensure response data exists in the CodeMeans table.
--We use IsNull values to pass zeroes where an average wasn't calculated os that 
the polynomial regression can be calculated.
DECLARE @inquery  AS NVARCHAR(MAX) = '
    Select
c.StudyID, c.RespID, c.LikingOrder, avg(isnull(C1,0)) as C1, avg(isnull(C2,0)) as C2, avg(isnull(C3,0)) as C3, avg(isnull(C4,0)) as C4, 
avg(isnull(C5,0)) as C5, avg(isnull(C6,0)) as C6, avg(isnull(C7,0)) as C7, avg(isnull(C8,0)) as C8, avg(isnull(C9,0)) as C9, 
avg(isnull(C10,0)) as C10, avg(isnull(C11,0)) as C11, avg(isnull(C12,0)) as C12, avg(isnull(C13,0)) as C13, avg(isnull(C14,0)) as C14, 
avg(isnull(C15,0)) as C15, avg(isnull(C16,0)) as C16, avg(isnull(C17,0)) as C17, avg(isnull(C18,0)) as C18, avg(isnull(C19,0)) as C19
from ClosedStudyResponses c
where c.StudyID = @StudyID
group by StudyID, RespID, LikingOrder
order by RespID
        '


--We are setting @inquery aka InputDataSet to be our initial dataset.  
--R Services requires that a data.frame be passed to any calculations being 
generated.  As such, df is simply data framing the @inquery data.
--The res object holds the polynomial regression results by RespondentID and 
LikingOrder for each of the averages in the @inquery resultset.

EXEC sp_execute_external_script @language = N'R'
    , @script = N'
    library(tidyr, broom)

    studymeans <- InputDataSet

    df <- data.frame(studymeans) 

    lin.mod.1 <- lm(df$LikingOrder ~ poly(df$C1,3, raw=TRUE))
    lin.mod.2 <- lm(df$LikingOrder ~ poly(df$C2,3, raw=TRUE))
    lin.mod.3 <- lm(df$LikingOrder ~ poly(df$C3,3, raw=TRUE))
    lin.mod.4 <- lm(df$LikingOrder ~ poly(df$C4,3, raw=TRUE))
    lin.mod.5 <- lm(df$LikingOrder ~ poly(df$C5,3, raw=TRUE))
    lin.mod.6 <- lm(df$LikingOrder ~ poly(df$C6,3, raw=TRUE))
    lin.mod.7 <- lm(df$LikingOrder ~ poly(df$C7,3, raw=TRUE))
    lin.mod.8 <- lm(df$LikingOrder ~ poly(df$C8,3, raw=TRUE))
    lin.mod.9 <- lm(df$LikingOrder ~ poly(df$C9,3, raw=TRUE))
    lin.mod.10 <- lm(df$LikingOrder ~ poly(df$C10,3, raw=TRUE))
    lin.mod.11 <- lm(df$LikingOrder ~ poly(df$C11,3, raw=TRUE))
    lin.mod.12 <- lm(df$LikingOrder ~ poly(df$C12,3, raw=TRUE))
    lin.mod.13 <- lm(df$LikingOrder ~ poly(df$C13,3, raw=TRUE))
    lin.mod.14 <- lm(df$LikingOrder ~ poly(df$C14,3, raw=TRUE))
    lin.mod.15 <- lm(df$LikingOrder ~ poly(df$C15,3, raw=TRUE))
    lin.mod.16 <- lm(df$LikingOrder ~ poly(df$C16,3, raw=TRUE))
    lin.mod.17 <- lm(df$LikingOrder ~ poly(df$C17,3, raw=TRUE))
    lin.mod.18 <- lm(df$LikingOrder ~ poly(df$C18,3, raw=TRUE))
    lin.mod.19 <- lm(df$LikingOrder ~ poly(df$C19,3, raw=TRUE))

    lst <- lapply(ls(pattern="lin.mod"), get)
    allmodels <- lapply(lst, summary)

    res <- broom::tidy(allmodels)
'
, @input_data_1 = @inquery
, @output_data_1_name = N'res'
, @params = N'@StudyID int'
,@StudyID = @StudyID 
--- Edit this line to handle the output data frame.
--WITH RESULT SETS ((StudyID int, RespID int, LikingOrder int, NewColumn int, 
res varchar(max)));
END;

当将有效的 StudyID 输入参数传递给上面的脚本时,上面的脚本会引发以下错误:

Error in setNames(data.frame(data), value.name) : 
'names' attribute [1] must be the same length as the vector [0]
Calls: source ... <Anonymous> -> <Anonymous> -> melt.default -> setNames
In addition: There were 50 or more warnings (use warnings() to see the first 
50)

我的输入数据如下: 期望的结果是获得 data.frame 中所有 19 个模型的摘要。如何解决错误并修改代码以完成最终结果?

【问题讨论】:

  • 这是很多/不可能复制的。你能把它归结为可重现的东西吗?
  • 请发布您需要对其执行tidy 操作的代表性数据样本的dput。看起来应该是df
  • @camille 我刚刚更新了问题以包含要分析的源数据的屏幕截图。感谢您的帮助!
  • 试图从数据的屏幕截图中工作意味着我们必须输入该图片中的所有内容。 See here 发布了一个人们可以回答的 R 问题—dput 有助于实现这一目标。

标签: r broom


【解决方案1】:

如果没有您的工作环境,我不确定您的数据是如何设置的,但您似乎正在尝试在多个预测变量列上拟合具有相同因变量的模型。我认为缺少的部分是根据broom and dplyr 小插图对rowwise 的调用,但不完全确定。不过,这里有一个使用 mtcars 数据集的工作示例。请注意,该结构是在具有包含模型的列表列的行数据帧上使用tidy,而不是直接在列表上。您还可以通过映射包含预测列的数据框直接创建模型,而不是在环境中存储模型并需要使用getls。任何时候你发现自己在使用ls,想想你是否可以把你的元素放在一个列表中!

编辑:在查看此问题再次提示的小插图后,我意识到您实际上可以像现在所示那样做一个快速管道(请参阅编辑历史以了解使用enframe 的方法。通过gather将数据放入适合分组模型拟合的格式,可以更整齐的得到想要的结果!

library(tidyverse)
library(broom)

mtcars %>%
  gather(predictor, measure, -mpg) %>%
  group_by(predictor) %>%
  do(tidy(lm(mpg ~ measure, .)))
#> # A tibble: 20 x 6
#> # Groups:   predictor [10]
#>    predictor term        estimate std.error statistic  p.value
#>    <chr>     <chr>          <dbl>     <dbl>     <dbl>    <dbl>
#>  1 am        (Intercept)  17.1      1.12       15.2   1.13e-15
#>  2 am        measure       7.24     1.76        4.11  2.85e- 4
#>  3 carb      (Intercept)  25.9      1.84       14.1   9.22e-15
#>  4 carb      measure      -2.06     0.569      -3.62  1.08e- 3
#>  5 cyl       (Intercept)  37.9      2.07       18.3   8.37e-18
#>  6 cyl       measure      -2.88     0.322      -8.92  6.11e-10
#>  7 disp      (Intercept)  29.6      1.23       24.1   3.58e-21
#>  8 disp      measure      -0.0412   0.00471    -8.75  9.38e-10
#>  9 drat      (Intercept)  -7.52     5.48       -1.37  1.80e- 1
#> 10 drat      measure       7.68     1.51        5.10  1.78e- 5
#> 11 gear      (Intercept)   5.62     4.92        1.14  2.62e- 1
#> 12 gear      measure       3.92     1.31        3.00  5.40e- 3
#> 13 hp        (Intercept)  30.1      1.63       18.4   6.64e-18
#> 14 hp        measure      -0.0682   0.0101     -6.74  1.79e- 7
#> 15 qsec      (Intercept)  -5.11    10.0        -0.510 6.14e- 1
#> 16 qsec      measure       1.41     0.559       2.53  1.71e- 2
#> 17 vs        (Intercept)  16.6      1.08       15.4   8.85e-16
#> 18 vs        measure       7.94     1.63        4.86  3.42e- 5
#> 19 wt        (Intercept)  37.3      1.88       19.9   8.24e-19
#> 20 wt        measure      -5.34     0.559      -9.56  1.29e-10

reprex package (v0.2.0) 于 2018 年 7 月 10 日创建。

【讨论】:

    【解决方案2】:

    你没有给我们一个可重复的例子;这似乎可行。一些潜在的问题:你需要在模型上运行tidy,而不是摘要;最好避免在模型公式中使用$-indexing。

    library(purrr)
    df <- mtcars
    predvars <- colnames(mtcars)[-1]
    

    ...在您的情况下,这将是paste0("C",1:19) ...

    respvar <- "mpg"  ## would be "LikingOrder"
    predpolys <- sprintf("poly(%s,3,raw=TRUE)",predvars)
    forms <- map(predpolys, reformulate,
                 response=respvar)       ## construct formulas
    names(forms) <- predvars             ## names will be inherited by model lists
    modList <- map(forms, lm, data= df)  ## fit all models
    res <- map(modList, broom::tidy)     ## tidy all models
    

    如果需要,此时您可以dplyr::bind_rows(res,.id="predvar"),或者您可以将map() 替换为map_dfr(..., .id = "predvar") ...

    【讨论】:

      猜你喜欢
      • 2018-09-14
      • 2021-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-10
      • 2018-03-22
      • 1970-01-01
      • 2018-07-30
      相关资源
      最近更新 更多