2016-10-03 93 views
4

我想做一个等同于在mtcars数据集中拟合gpm(加仑每英里= 1/mpg)到wt的模型。这看起来很容易:如何使用扫帚和dplyr将分组数据应用于分组模型?

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)) 

我可以使用扩充()来获得拟合输出:

lm1 %>% augment(fit) 

这给了我32行,每行一个在mtcars2,如预期。

现在的挑战:我想用newdata,在那里我已经被加重量得到拟合输出缸/ 4:

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

我希望这将产生同样大小的数据帧如lm1%>%增加(适合):newdata中的每一行都有一行,因为扫帚会通过分组变量cyl和am匹配模型和newdata。

不幸的是,

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

给我与192行(= 6×32)的数据帧,显然拟合每个模型到newdata的每一行。

从其他地方读取,我收集到group_by和rowwise数据帧不兼容,所以lm1被取消分组,并且扩充不能关联模型和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(列表)和data(列表)。你有cyl,am(dbl),fit和data。我改变了我的dbl,但这没有帮助。

我认为不同之处在于,我在此样本中有3个(ID ...类似于mtcars中的rownames)x 2(cyl)x 2(am)个单位(每个样本有12个测量值),而mtcars示例具有3(cyl)x 2(am)单元格xa每个单元格的随机数的汽车类型。在我的分析中,我需要看到ID值,但新数据同样适用于所有单位。如果有帮助的话,可以把它看作是测试中每辆汽车逆风的速度。这是否意味着增加投诉的原因,它无法处理班级名单的数据?

编辑:将ID与newdata合并(使用full = TRUE)解决了最后一个问题。我目前正在使用你的第一个建议解决方案

回答

4

对于这种情况,我已使用map2从包purrrmap2同时循环两个列表的元素。这些列表必须具有相同的长度并且顺序相同。

列表中的元素用作您想要应用的某个函数的参数(您的情况为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)) 

为了避免担心为了这么多,你可以通过组nest的预测数据,加入这lm1,并augment结果返回的列表unnesting。

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