R中的回归子集算法
Regression Subset Algorithm in R
我想在 R 中为 'beta regression' 模型构建回归子集算法。
R 中有一个适合 beta 回归的包 betareg
,我感兴趣的是最大化 'log likelihood'.
的模型
基本上,这是通过选择最佳的 k 因子回归模型来实现的,对于 k = 1,2,...,p,其中 p 是您拥有的变量数。
例如,如果我将 x_1、x_2、x_3 作为我的变量,并将 y 作为我的响应。我想要一些东西:
第 1 步:找到最佳 1 因子模型
mod1 <- betareg(y~x_1, data = test)
mod1.sum <- summary(mod1)
mod2 <- betareg(y~x_2, data = test)
mod2.sum <- summary(mod2)
mod3 <- betareg(y~x_3, data = test)
mod3.sum <- summary(mod3)
现在我已经拟合了所有模型,我想比较每个模型的对数似然:
likelihoods <- c( mod1.sum$loglik, mod2.sum$loglik, mod3.sum$loglik)
which.max(likelihoods)
第 2 步:找到添加到最佳 1 因子模型的最佳因子,我们假设 x_1 是上一步中的最佳因子。然后在这一步中,我们将 x_1 和 x_2 的模型与 x_1 和 x_3 的模型进行比较,选择具有最大对数似然的模型。
第 3 步:将最好的两个变量作为给定,找出对对数似然增加贡献最大的第三个变量。
第 4 步:Return 最佳 1 因子模型,最佳 2 因子模型,...,最佳 p 因子模型,包含的因子及其对应的对数似然。
当 p 很大时,比如 40 左右,我很难有效地做到这一点
这是不使用 betareg 的替代解决方案。输出结果类似,供您考虑。
这是我使用的数据集:
set.seed(12345)
dat <- data.frame(y=runif(50), x_1=runif(50), x_2=runif(50), x_3=runif(50))
使用 leaps 库创建所有可能组合的列表:
library(leaps)
subs<-regsubsets(y~., data=dat, nbest=10, nvmax=100, really.big=T)
subs<-summary(subs)$which[,-1]
all.mods<-lapply(1:nrow(subs), function(x)paste("y", paste(names(which(subs[x,])), collapse="+"), sep="~"))
all.mods
[[1]]
[1] "y~x_2"
[[2]]
[1] "y~x_1"
[[3]]
[1] "y~x_3"
[[4]]
[1] "y~x_2+x_3"
[[5]]
[1] "y~x_1+x_2"
[[6]]
[1] "y~x_1+x_3"
[[7]]
[1] "y~x_1+x_2+x_3"
运行 所有模型的线性回归:
all.lm<-lapply(all.mods, function(x)lm(as.formula(x), data=dat))
检查每个模型的 logLikihood:
lapply(all.lm, logLik)
[[1]]
'log Lik.' -7.051835 (df=3)
[[2]]
'log Lik.' -9.288776 (df=3)
[[3]]
'log Lik.' -9.334048 (df=3)
[[4]]
'log Lik.' -6.904604 (df=4)
[[5]]
'log Lik.' -7.051584 (df=4)
[[6]]
'log Lik.' -9.215915 (df=4)
[[7]]
'log Lik.' -6.888849 (df=5)
据我所知,没有专门有效的最佳子集 selection 用于 beta 回归(在 R 或其他语言中)。然而,有一些通用实现为此提供了近似解决方案,例如,基于 kofnGA
包(在 CRAN and published in JSS 上)等遗传算法。请参见下面的示例。 (要使用 forward 搜索而不是 best-subset selection,请参阅我的其他答案。)
或者,您可以使用近似于 betareg
所做的(广义)线性模型,并为此使用子集 selection。例如,您可以对响应(即 qlogis(y)
)进行对数变换,然后通过 leaps
(CRAN) or lmSubsets
(R-Forge). Or you could use a GLM with family = quasibinomial
and use glmulti
(CRAN, JSS).然后您可以使用该近似模型的最佳子集结果并将其用于 beta 回归。当然,这不会为您提供 最佳 beta 回归结果,但它可能是进一步分析的有用起点。
因此,回到β回归的直接遗传算法。为了说明如何使用 kofnGA
完成此操作,我们首先加载包和示例数据:
library("betareg")
library("kofnGA")
data("FoodExpenditure", package = "betareg")
然后,我们构建一个包含响应变量 y
和回归矩阵 x
的列表。请注意,我们在这里省略了截距,以便稍后将其强制进入模型(即截距不应受 selection)。
fe_data <- list(
y = with(FoodExpenditure, food/income),
x = model.matrix(~ income + persons, data = FoodExpenditure)[, -1]
)
除了上面设置的两个回归器之外,我们现在向回归器矩阵添加 40 个随机噪声变量
fe_data$x <- cbind(fe_data$x,
matrix(rnorm(40 * nrow(fe_data$x)), ncol = 40))
colnames(fe_data$x)[3:42] <- paste0("x", 1:40)
现在我们可以使用 kofnGA
到 select 可能的 42 个回归变量中有 2 个回归变量的最佳模型(加上始终包含的截距)。由于 kofnGA
最小化目标,我们使用 betareg
提供的负对数似然。主力函数 betareg.fit
而不是 betareg
用于避免不必要的公式解析等
nll <- function(v, data) -betareg.fit(x = cbind(1, data$x[, v]),
y = data$y)$loglik
最后,我们 运行 遗传算法仅用于 100 代,以在这个简短的例子中节省一些计算时间:
set.seed(1)
ga <- kofnGA(n = 42, k = 2, OF = nll, data = fe_data, ngen = 100)
结果输出是
summary(ga)
## Genetic algorithm search, 100 generations
## Number of unique solutions in the final population: 1
##
## Objective function values:
## average minimum
## Initial population -36.56597 -41.74583
## Final population -45.33351 -45.33351
##
## Best solution (found at generation 1):
## 1 2
因此,在这个非常简单的人工设置中,遗传算法确实选择了前 2 个回归变量(来自真实数据),而不是我们添加的任何不相关的随机 40 个回归变量。因此,我们现在可以继续使用回归变量
重新拟合适当的 beta 回归模型
colnames(fe_data$x)[ga$bestsol]
## [1] "income" "persons"
等请注意,此处使用的 beta 回归仅使用固定精度参数(log link)。如果您想要可变色散,则需要相应地修改 nll
。
除了我的其他答案显示如何使用 kofnGA
执行 best-subset selection 进行 beta 回归外,我还包括一个例如如何手动 forward selection。
我们再次从加载包和数据开始:
library("betareg")
data("FoodExpenditure", package = "betareg")
我还设置了包含响应和所有回归变量的列表(包括 40 个随机回归变量)。(请注意,与另一个不同,我将截距保留在 x
中,这在这里更方便。)
fe_data <- list(
y = with(FoodExpenditure, food/income),
x = model.matrix(~ income + persons, data = FoodExpenditure)
)
set.seed(123)
fe_data$x <- cbind(fe_data$x,
matrix(rnorm(40 * nrow(fe_data$x)), ncol = 40))
colnames(fe_data$x)[4:43] <- paste0("x", 1:40)
然后我们再次设置负对数似然函数(但不需要手动包括截距,因为它仍在x
)。
nll <- function(v, data) -betareg.fit(x = data$x[, v, drop = FALSE],
y = data$y)$loglik
然后我们存储所有可能回归变量的索引 vall
并使用截距 (v <- 1
) 和相应的负对数似然 (n
) 初始化我们的搜索。
vall <- 1:ncol(fe_data$x)
v <- 1
n <- nll(v, data = fe_data)
然后我们将前向搜索迭代 15 次(以避免在这个小数据集上出现数值不稳定性以获得更多变量)。我们总是 select 最能减少负对数似然的附加变量:
for(i in 1:15) {
vi <- vall[-v]
ni <- sapply(vi, function(vii) nll(v = c(v, vii), data = fe_data))
v <- c(v, vi[which.min(ni)])
n <- c(n, ni[which.min(ni)])
}
选择变量的顺序如下。请注意,首先选择真实回归器,然后选择随机噪声回归器。 (但尝试 set.seed(1)
以上将在真实回归之前包括随机回归...)
colnames(fe_data$x)[v]
## [1] "(Intercept)" "income" "persons" "x28" "x18"
## [6] "x29" "x22" "x11" "x5" "x8"
## [11] "x38" "x24" "x13" "x23" "x36"
## [16] "x16"
负对数似然和相关 BIC 的相应减少可以可视化为:
m <- seq_along(v)
plot(m, n, type = "b",
xlab = "Number of regressors", ylab = "Log-likelihood")
plot(m, n + log(nrow(fe_data$x)) * (m + 1), type = "b",
xlab = "Number of regressors", ylab = "BIC")
所以这确实会选择具有三个真实回归变量的模型作为最佳 BIC 模型。
我想在 R 中为 'beta regression' 模型构建回归子集算法。
R 中有一个适合 beta 回归的包 betareg
,我感兴趣的是最大化 'log likelihood'.
基本上,这是通过选择最佳的 k 因子回归模型来实现的,对于 k = 1,2,...,p,其中 p 是您拥有的变量数。
例如,如果我将 x_1、x_2、x_3 作为我的变量,并将 y 作为我的响应。我想要一些东西:
第 1 步:找到最佳 1 因子模型
mod1 <- betareg(y~x_1, data = test)
mod1.sum <- summary(mod1)
mod2 <- betareg(y~x_2, data = test)
mod2.sum <- summary(mod2)
mod3 <- betareg(y~x_3, data = test)
mod3.sum <- summary(mod3)
现在我已经拟合了所有模型,我想比较每个模型的对数似然:
likelihoods <- c( mod1.sum$loglik, mod2.sum$loglik, mod3.sum$loglik)
which.max(likelihoods)
第 2 步:找到添加到最佳 1 因子模型的最佳因子,我们假设 x_1 是上一步中的最佳因子。然后在这一步中,我们将 x_1 和 x_2 的模型与 x_1 和 x_3 的模型进行比较,选择具有最大对数似然的模型。
第 3 步:将最好的两个变量作为给定,找出对对数似然增加贡献最大的第三个变量。
第 4 步:Return 最佳 1 因子模型,最佳 2 因子模型,...,最佳 p 因子模型,包含的因子及其对应的对数似然。
当 p 很大时,比如 40 左右,我很难有效地做到这一点
这是不使用 betareg 的替代解决方案。输出结果类似,供您考虑。
这是我使用的数据集:
set.seed(12345)
dat <- data.frame(y=runif(50), x_1=runif(50), x_2=runif(50), x_3=runif(50))
使用 leaps 库创建所有可能组合的列表:
library(leaps)
subs<-regsubsets(y~., data=dat, nbest=10, nvmax=100, really.big=T)
subs<-summary(subs)$which[,-1]
all.mods<-lapply(1:nrow(subs), function(x)paste("y", paste(names(which(subs[x,])), collapse="+"), sep="~"))
all.mods
[[1]]
[1] "y~x_2"
[[2]]
[1] "y~x_1"
[[3]]
[1] "y~x_3"
[[4]]
[1] "y~x_2+x_3"
[[5]]
[1] "y~x_1+x_2"
[[6]]
[1] "y~x_1+x_3"
[[7]]
[1] "y~x_1+x_2+x_3"
运行 所有模型的线性回归:
all.lm<-lapply(all.mods, function(x)lm(as.formula(x), data=dat))
检查每个模型的 logLikihood:
lapply(all.lm, logLik)
[[1]]
'log Lik.' -7.051835 (df=3)
[[2]]
'log Lik.' -9.288776 (df=3)
[[3]]
'log Lik.' -9.334048 (df=3)
[[4]]
'log Lik.' -6.904604 (df=4)
[[5]]
'log Lik.' -7.051584 (df=4)
[[6]]
'log Lik.' -9.215915 (df=4)
[[7]]
'log Lik.' -6.888849 (df=5)
据我所知,没有专门有效的最佳子集 selection 用于 beta 回归(在 R 或其他语言中)。然而,有一些通用实现为此提供了近似解决方案,例如,基于 kofnGA
包(在 CRAN and published in JSS 上)等遗传算法。请参见下面的示例。 (要使用 forward 搜索而不是 best-subset selection,请参阅我的其他答案。)
或者,您可以使用近似于 betareg
所做的(广义)线性模型,并为此使用子集 selection。例如,您可以对响应(即 qlogis(y)
)进行对数变换,然后通过 leaps
(CRAN) or lmSubsets
(R-Forge). Or you could use a GLM with family = quasibinomial
and use glmulti
(CRAN, JSS).然后您可以使用该近似模型的最佳子集结果并将其用于 beta 回归。当然,这不会为您提供 最佳 beta 回归结果,但它可能是进一步分析的有用起点。
因此,回到β回归的直接遗传算法。为了说明如何使用 kofnGA
完成此操作,我们首先加载包和示例数据:
library("betareg")
library("kofnGA")
data("FoodExpenditure", package = "betareg")
然后,我们构建一个包含响应变量 y
和回归矩阵 x
的列表。请注意,我们在这里省略了截距,以便稍后将其强制进入模型(即截距不应受 selection)。
fe_data <- list(
y = with(FoodExpenditure, food/income),
x = model.matrix(~ income + persons, data = FoodExpenditure)[, -1]
)
除了上面设置的两个回归器之外,我们现在向回归器矩阵添加 40 个随机噪声变量
fe_data$x <- cbind(fe_data$x,
matrix(rnorm(40 * nrow(fe_data$x)), ncol = 40))
colnames(fe_data$x)[3:42] <- paste0("x", 1:40)
现在我们可以使用 kofnGA
到 select 可能的 42 个回归变量中有 2 个回归变量的最佳模型(加上始终包含的截距)。由于 kofnGA
最小化目标,我们使用 betareg
提供的负对数似然。主力函数 betareg.fit
而不是 betareg
用于避免不必要的公式解析等
nll <- function(v, data) -betareg.fit(x = cbind(1, data$x[, v]),
y = data$y)$loglik
最后,我们 运行 遗传算法仅用于 100 代,以在这个简短的例子中节省一些计算时间:
set.seed(1)
ga <- kofnGA(n = 42, k = 2, OF = nll, data = fe_data, ngen = 100)
结果输出是
summary(ga)
## Genetic algorithm search, 100 generations
## Number of unique solutions in the final population: 1
##
## Objective function values:
## average minimum
## Initial population -36.56597 -41.74583
## Final population -45.33351 -45.33351
##
## Best solution (found at generation 1):
## 1 2
因此,在这个非常简单的人工设置中,遗传算法确实选择了前 2 个回归变量(来自真实数据),而不是我们添加的任何不相关的随机 40 个回归变量。因此,我们现在可以继续使用回归变量
重新拟合适当的 beta 回归模型colnames(fe_data$x)[ga$bestsol]
## [1] "income" "persons"
等请注意,此处使用的 beta 回归仅使用固定精度参数(log link)。如果您想要可变色散,则需要相应地修改 nll
。
除了我的其他答案显示如何使用 kofnGA
执行 best-subset selection 进行 beta 回归外,我还包括一个例如如何手动 forward selection。
我们再次从加载包和数据开始:
library("betareg")
data("FoodExpenditure", package = "betareg")
我还设置了包含响应和所有回归变量的列表(包括 40 个随机回归变量)。(请注意,与另一个不同,我将截距保留在 x
中,这在这里更方便。)
fe_data <- list(
y = with(FoodExpenditure, food/income),
x = model.matrix(~ income + persons, data = FoodExpenditure)
)
set.seed(123)
fe_data$x <- cbind(fe_data$x,
matrix(rnorm(40 * nrow(fe_data$x)), ncol = 40))
colnames(fe_data$x)[4:43] <- paste0("x", 1:40)
然后我们再次设置负对数似然函数(但不需要手动包括截距,因为它仍在x
)。
nll <- function(v, data) -betareg.fit(x = data$x[, v, drop = FALSE],
y = data$y)$loglik
然后我们存储所有可能回归变量的索引 vall
并使用截距 (v <- 1
) 和相应的负对数似然 (n
) 初始化我们的搜索。
vall <- 1:ncol(fe_data$x)
v <- 1
n <- nll(v, data = fe_data)
然后我们将前向搜索迭代 15 次(以避免在这个小数据集上出现数值不稳定性以获得更多变量)。我们总是 select 最能减少负对数似然的附加变量:
for(i in 1:15) {
vi <- vall[-v]
ni <- sapply(vi, function(vii) nll(v = c(v, vii), data = fe_data))
v <- c(v, vi[which.min(ni)])
n <- c(n, ni[which.min(ni)])
}
选择变量的顺序如下。请注意,首先选择真实回归器,然后选择随机噪声回归器。 (但尝试 set.seed(1)
以上将在真实回归之前包括随机回归...)
colnames(fe_data$x)[v]
## [1] "(Intercept)" "income" "persons" "x28" "x18"
## [6] "x29" "x22" "x11" "x5" "x8"
## [11] "x38" "x24" "x13" "x23" "x36"
## [16] "x16"
负对数似然和相关 BIC 的相应减少可以可视化为:
m <- seq_along(v)
plot(m, n, type = "b",
xlab = "Number of regressors", ylab = "Log-likelihood")
plot(m, n + log(nrow(fe_data$x)) * (m + 1), type = "b",
xlab = "Number of regressors", ylab = "BIC")
所以这确实会选择具有三个真实回归变量的模型作为最佳 BIC 模型。