关于级别数据的预测(使用组模型)

时间:2016-08-29 16:37:35

标签: r

我迫切需要帮助:所以我使用dplyr按组进行回归分析。我是这样的:

regressions <- mtcars %>% group_by(cyl) %>%
do(fit = lm(wt ~ mpg + qsec + gear, .))

我在数据框中得到的模型如下所示:

  ##     cyl     fit
  ##   (dbl)   (chr)
  ## 1     4 <S3:lm>
  ## 2     6 <S3:lm>
  ## 3     8 <S3:lm>

现在我想预测新数据更短(即与我的训练数据不同),并且具有相同的水平。即圆柱体4,6,8。我的问题是:如何使用new / testdata预测每个模型仅指我的测试集中的级别。

 so model cyl 4 only uses data 4 cyl to predict 
model cyl 6 uses data 6 cyl to predict
model cyl 8 uses data 8 cyl to predict
and so on and so forth.enter code here

请记住,测试数据中包含所有级别/组。

有没有更简单的方法来做到这一点。即按级别进行预测。目前我正在尝试在扫帚包中使用扩充,但它并没有真正起作用。它的作用是:它通过我的所有测试数据运行每个模型,同时忽略级别。

请帮忙!我这样做的规模要大得多,需要快速有效的东西。

3 个答案:

答案 0 :(得分:5)

对于 purrr 以及 dplyr tidyr ,这可能是一个不错的选择。 purrr 包可以使用列表,我相信从长远来看会替换do

例如,如果您的测试数据集中包含相同的变量,我称之为mtcars_test

mtcars_test = mtcars

您可以根据cyl将此数据集拆分为三个部分。

test_split = split(mtcars_test, mtcars_test$cyl)

然后,您可以使用map2运行三个模型以及拆分测试数据来进行预测。

library(purrr)

map2(regressions$fit, test_split, predict)

结果是一个列表。在您的实际情况中,您可能希望以更整洁的格式得出结果。在这种情况下,您可以使用 purrr 函数以及mutatetidyr::nest来形成原始回归结果:

library(tidyr)

regs = mtcars %>%
    group_by(cyl) %>%
    nest() %>%
    mutate(fit = map(data, ~lm(wt ~ mpg + qsec + gear, .)))

然后通过map2添加预测,但在mutate内。在您的示例中尝试使用do后,此方法无效。

regs %>% 
    mutate(testpred = map2(fit, test_split, predict))

要使用柱面数和测试预测得到最终结果,请使用tidyr::unnest

regs %>% 
    mutate(testpred = map2(fit, test_split, predict)) %>%
    unnest(testpred)

# A tibble: 32 × 2
     cyl testpred
   <dbl>    <dbl>
1      6 3.607719
2      6 4.263550
3      6 5.418092
4      6 4.386157
5      6 3.898692
6      6 4.632542
...

答案 1 :(得分:0)

我在访问data.frame中的lm个对象时遇到了一些问题,所以第一个循环并不漂亮:

A <- list()
for (i in unique(mtcars$cyl)) {
  A[[as.character(i)]] <- predict(as.list(regressions[regressions$cyl == i, ])$fit[[1]],
                    newdata = mtcars[mtcars$cyl == i, ])
}

更简单的解决方案是在同一循环中执行两个步骤(回归然后预测)。

reg <- list()
pred <- list()
for (cyl in unique(mtcars$cyl)) {
  reg[[as.character(cyl)]] <- lm(wt ~ mpg + qsec + gear, filter(mtcars, cyl == cyl))
  pred[[as.character(cyl)]] <- predict(reg[[as.character(cyl)]],
                                       newdata = filter(mtcars, cyl == cyl))
}

显然,您可以直接在lapply上使用unqieu(mtcars$cyl)这两种方法中的任何一种。在这两种情况下,我在循环迭代器上使用as.character来确保您的结果&#39;列表不会增加到六个柱面,留下五个空位。

最后,您可以使用*元素将所有变量与cyl变量交叉,这样您事实上可以创建与组一样多的模型。然后,您可以直接使用预测而无需子集。请注意,我将cyl变量切换为factor类,以确保按组分配一个斜率。我还在公式括号内明确指定了截距,以确保按组进行不同的截距。

mtcars$cyl <- factor(mtcars$cyl)
reg <- lm(wt ~ (1 + mpg + qsec + gear)*cyl, mtcars)
predict(reg, mtcars)

这种方法的唯一问题是系数更难以解释,(即:mpg的{​​{1}}系数是cyl = 6的系数加上mpg的系数{1}})

答案 2 :(得分:0)

使用broom::augment非常紧凑且轻松实现。

您符合回归和分数:

library(broom)
library(dplyr)

# fit the set of regressions by cyl
regressions = mtcars %>% group_by(cyl) %>%
  do(fit = lm(wt ~ mpg + qsec + gear, .))

# score the regressions by cyl
scores = regressions %>% 
  augment(fit) 

您可以检查此结果是否与单个回归拟合的结果相同,并对由cyl值定义的组进行评分。

# check that regression with cyl == 4 and predictions gives the same result
lm_4 = lm(wt ~ mpg + qsec + gear, data = subset(mtcars, cyl == 4))
predict(lm_4, newdata = subset(mtcars, cyl == 4))
scores %>% 
  filter(cyl == 4)

# check that regression with cyl == 8 and predictions gives the same result
lm_8 = lm(wt ~ mpg + qsec + gear, data = subset(mtcars, cyl == 8))
predict(lm_8, newdata = subset(mtcars, cyl == 8))
scores %>% 
  filter(cyl == 8)