modelr:交叉验证模型适合数据集中符合标准的所有变量
modelr: cross-validated model fitting for all variables in a dataset that match criterion
我有一个数据集,其中包含许多前缀为 "cat_" 的(因子)变量。
library(tidyverse)
library(modelr)
library(lazyeval)
library(purrr)
# create the dataset
df_foo = wakefield::r_data_frame(
n = 100,
wakefield::r_series(wakefield::r_sample, j = 5, name = "cat"),
Y = wakefield::normal()
)
我希望能够使用 tidy 框架计算每个因子变量与响应变量的成对、k 折交叉验证回归 R2。
对于下面的几个变量,跨折叠计算这个很容易。
df_foo %>%
mutate_at(.funs = funs(as.factor), .cols = vars(starts_with("cat"))) %>%
crossv_kfold(k = 10, id = "id") %>%
mutate_(
.dots = setNames(
list(
interp(
quote(
purrr::map_dbl(train, .f = function(train_data) {
summary(stats::lm(Y ~ cat_1, data = train_data))$r.squared
}))),
interp(
quote(
purrr::map_dbl(train, .f = function(train_data) {
summary(stats::lm(Y ~ cat_2, data = train_data))$r.squared
})))
),
nm = c("cat_1", "cat_2")
)
)
问题:
如何将其推广到任意数量的变量?
为什么我必须明确地为函数 purrr::map_dbl
和 stats::lm
使用命名空间访问器(如果我删除命名空间访问器,上面的逻辑将不起作用)?
编辑:
以下代码获取每个变量的 R2,但不能将其展平为等于数据集中变量数的列数。
make_r2_variable = function(var_name, train_data) {
summary(stats::lm(Y ~ var_name, data = train_data))$r.squared
}
make_r2 = function(train_data) {
summarise_at(
.tbl = data.frame(train_data),
.cols = vars(starts_with("cat_")),
.funs = funs(make_r2_variable(., train_data = train_data))
)
}
df_foo = df_foo %>%
mutate_at(.funs = funs(as.factor), .cols = vars(starts_with("cat"))) %>%
crossv_kfold(k = 10, id = "id") %>%
mutate(
R2 = map(.x = train, .f = make_r2)
)
我认为最紧凑的解决方案是:
make_r2_variable = function(var_name, train_data) {
summary(stats::lm(Y ~ var_name, data = train_data))$r.squared
}
make_r2 = function(train_data) {
summarise_at(
.tbl = data.frame(train_data),
.cols = vars(starts_with("cat_")),
.funs = funs(make_r2_variable(., train_data = train_data))
)
}
df_foo = df_foo %>%
mutate_at(.funs = funs(as.factor), .cols = vars(starts_with("cat"))) %>%
crossv_kfold(k = 10, id = "id") %>%
mutate(
R2 = map(.x = train, .f = make_r2)
) %>%
unnest(R2)
这基本上是我在编辑中加上 unnest
的解决方案。这基本上使用 map
改变 S3: resample
列,并在其中使用 mutate_at
循环匹配条件的列。由于 returns 一个 list/1D data.frame
,因此需要调用 unnest
。
我有一个数据集,其中包含许多前缀为 "cat_" 的(因子)变量。
library(tidyverse)
library(modelr)
library(lazyeval)
library(purrr)
# create the dataset
df_foo = wakefield::r_data_frame(
n = 100,
wakefield::r_series(wakefield::r_sample, j = 5, name = "cat"),
Y = wakefield::normal()
)
我希望能够使用 tidy 框架计算每个因子变量与响应变量的成对、k 折交叉验证回归 R2。
对于下面的几个变量,跨折叠计算这个很容易。
df_foo %>%
mutate_at(.funs = funs(as.factor), .cols = vars(starts_with("cat"))) %>%
crossv_kfold(k = 10, id = "id") %>%
mutate_(
.dots = setNames(
list(
interp(
quote(
purrr::map_dbl(train, .f = function(train_data) {
summary(stats::lm(Y ~ cat_1, data = train_data))$r.squared
}))),
interp(
quote(
purrr::map_dbl(train, .f = function(train_data) {
summary(stats::lm(Y ~ cat_2, data = train_data))$r.squared
})))
),
nm = c("cat_1", "cat_2")
)
)
问题:
如何将其推广到任意数量的变量?
为什么我必须明确地为函数
purrr::map_dbl
和stats::lm
使用命名空间访问器(如果我删除命名空间访问器,上面的逻辑将不起作用)?
编辑:
以下代码获取每个变量的 R2,但不能将其展平为等于数据集中变量数的列数。
make_r2_variable = function(var_name, train_data) {
summary(stats::lm(Y ~ var_name, data = train_data))$r.squared
}
make_r2 = function(train_data) {
summarise_at(
.tbl = data.frame(train_data),
.cols = vars(starts_with("cat_")),
.funs = funs(make_r2_variable(., train_data = train_data))
)
}
df_foo = df_foo %>%
mutate_at(.funs = funs(as.factor), .cols = vars(starts_with("cat"))) %>%
crossv_kfold(k = 10, id = "id") %>%
mutate(
R2 = map(.x = train, .f = make_r2)
)
我认为最紧凑的解决方案是:
make_r2_variable = function(var_name, train_data) {
summary(stats::lm(Y ~ var_name, data = train_data))$r.squared
}
make_r2 = function(train_data) {
summarise_at(
.tbl = data.frame(train_data),
.cols = vars(starts_with("cat_")),
.funs = funs(make_r2_variable(., train_data = train_data))
)
}
df_foo = df_foo %>%
mutate_at(.funs = funs(as.factor), .cols = vars(starts_with("cat"))) %>%
crossv_kfold(k = 10, id = "id") %>%
mutate(
R2 = map(.x = train, .f = make_r2)
) %>%
unnest(R2)
这基本上是我在编辑中加上 unnest
的解决方案。这基本上使用 map
改变 S3: resample
列,并在其中使用 mutate_at
循环匹配条件的列。由于 returns 一个 list/1D data.frame
,因此需要调用 unnest
。