首页 文章

如何使用broom和dplyr将分组数据应用于分组模型?

提问于
浏览
4

我想做相当于在mtcars数据集中拟合gpm(加仑每英里= 1 / mpg)到wt的模型 . 这似乎很容易:

data(mtcars)
library(dplyr)
library(tidyr)
library(broom)
library(ggplot2)
library(scales)

mtcars2 <-
    mtcars %>%
    mutate(gpm = 1 / mpg) %>%
    group_by(cyl, am)

lm1 <-
    mtcars2 %>%
    do(fit = lm(gpm ~ wt, data = .))

正如预期的那样,这会得到一个包含6行的行数据帧 .

该图表证实有六组:

p1 <-
    qplot(wt, gpm, data = mtcars2) +
    facet_grid(cyl ~ am) +
    stat_smooth(method='lm',se=FALSE, fullrange = TRUE) +
    scale_x_continuous(limits = c(0,NA))

我可以使用augment()来获得拟合的输出:

lm1 %>% augment(fit)

这给了我32行,mtcars2中的每一行,正如预期的那样 .

现在面临挑战:我想使用newdata获得适合的输出,其中我将wt增加了cyl / 4:

newdata <-
    mtcars2 %>%
    mutate(
        wt = wt + cyl/4)

我希望这会生成一个与lm1%>%augment(fit)大小相同的数据框:newdata中每行占一行,因为扫帚将通过分组变量cyl和am匹配模型和newdata .

不幸,

pred1 <-
    lm1 %>%
    augment(
        fit,
        newdata = newdata)

给我一个192行(= 6 x 32)的数据框,显然使每个模型适合每一行newdata .

从其他地方读取,我认为group_by和rowwise数据帧不兼容,因此lm1未分组,并且augment不能关联模型和newdata . 还有其他设计模式可以让我这样做吗?如果它像上面的尝试一样简单和透明会很好,但更重要的是它的工作原理 .

这是我的sessionInfo():

> sessionInfo()
R version 3.3.1 (2016-06-21)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

locale:
[1] LC_COLLATE=English_United States.1252 
[2] LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] scales_0.4.0  ggplot2_2.1.0 broom_0.4.1   tidyr_0.6.0   dplyr_0.5.0  

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.7      magrittr_1.5     mnormt_1.5-4     munsell_0.4.3   
 [5] colorspace_1.2-6 lattice_0.20-34  R6_2.1.3         stringr_1.1.0   
 [9] plyr_1.8.4       tools_3.3.1      parallel_3.3.1   grid_3.3.1      
[13] nlme_3.1-128     gtable_0.2.0     psych_1.6.9      DBI_0.5-1       
[17] lazyeval_0.2.0   assertthat_0.1   tibble_1.2       reshape2_1.4.1  
[21] labeling_0.3     stringi_1.1.1    compiler_3.3.1   foreign_0.8-67

编辑:

@aosmith:我一直在探索你的第二个选择,我喜欢它 . 但是,当我在我的真实数据上尝试时,我在mutate命令中遇到了一个问题:它返回“错误:扩充不知道如何处理类列表的数据” .

我的真实代码更像是:

newdata %>% 
dplyr::select(cyl, am, wt) %>% # wt holds new predictor values
group_by(cyl, am) %>%
nest() %>%
inner_join(regressions, .) %>% 
## looks like yours at this point
mutate(pred = list(augment(fit, newdata = data))) %>% # Error here
unnest(pred)

我说它看起来像你的,我的意思是我有以下列(这里为了一致性而重命名):ID(chr),attr1(dbl),cyl(dbl),am(chr),fit(list)和data(列表) . 你有cyl,am(dbl),fit和data . 我把我改为dbl,但这没有帮助 .

我认为区别在于我在这个样本中有3个(ID ...类似于mtcars中的rownames)x 2(cyl)x 2(am)单位(每个样本有12个测量值),而mtcars示例有3个(cyl)x 2(am)单元x每个单元的汽车类型的随机数 . 在我的分析中,我需要查看ID值,但newdata同样适用于所有单位 . 如果有帮助,可以将其视为测试中每辆车的逆风速度 . 这是否表明增加投诉的原因是它无法处理 class 列表的数据?

编辑:将ID与新数据合并(使用full = TRUE)解决了最后一个问题 . 我目前正在使用您提供的第一个解决方案 .

1 回答

  • 4

    在这种情况下,我使用了包purrr的 map2 . map2 同时循环遍历两个列表的元素 . 列表必须具有相同的长度并且顺序相同 .

    列表的元素用作要应用的某些函数的参数(在您的情况下为 augment ) . 在这里,您的两个列表将是模型列表和数据集列表(每个 cyl / am 组合一个列表) .

    使用 map2_df 将结果作为data.frame而不是列表返回 .

    library(purrr)
    

    我使用 split 制作了data.frames列表进行预测 . 要分割的因子的顺序决定了列表顺序,所以我确保它与 lm1 的顺序相同 .

    test_split = split(newdata, list(newdata$am, newdata$cyl)
    
    map2_df(lm1$fit, test_split, ~augment(.x, newdata = .y))
    

    为了避免对订单如此担心,您可以按组预测数据,将其连接到 lm1 ,并将 augment 的结果作为删除列表返回 .

    newdata %>%
        group_by(cyl, am) %>%
        nest() %>%
        inner_join(lm1, .) %>%
        mutate(pred = list(augment(fit, newdata = data))) %>%
        unnest(pred)
    

相关问题