我迫切需要帮助:所以我使用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
请记住,测试数据中包含所有级别/组。
有没有更简单的方法来做到这一点。即按级别进行预测。目前我正在尝试在扫帚包中使用扩充,但它并没有真正起作用。它的作用是:它通过我的所有测试数据运行每个模型,同时忽略级别。
请帮忙!我这样做的规模要大得多,需要快速有效的东西。
答案 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 函数以及mutate
加tidyr::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)