特征选择 | 逻辑回归-通过系数符号和VIF进一步筛选变量-R版本
本文是上篇(特征选择 | 逻辑回归-通过系数符号和VIF进一步筛选变量)的续,是R版本的实现。
R代码
1、逐步选择,对R逻辑回归逐步选择变量的实现做了微调:
logit_stepwise <- function(data, label, slentry, slstay){
# author: 小石头(bigdata_0819@163.com)
# data:包含自变量和应变量的数据框
# label:应变量
# slentry:选择变量时显著水平判断的阈值
# slstay: 剔除变量时显著水平判断的阈值
# return: lst:
# SelectionProcess: 变量逐步选择的过程
# models: 每一步的模型结果
# model_optimal: 最终输出的模型
# result_optimal: 最终输出的模型结果
Selected <- c()
Remaining <- names(data)[which(names(data)!=label)]
NumberInModel <- 0
SelectionProcess_list <- list()
model_list <- list()
result_list <- list()
### 第0步,只有截距项
Step <- 0
formula <- paste0(label, ' ~ 1')
result <- glm(formula, data=data, family=binomial)
summ <- summary(result)
model <- data.frame(summ$coefficients)
model <- tibble::rownames_to_column(model, "Variable")
rownames(model) <- NULL
model <- cbind(Step, model)
colnames(model) <- c('Step', 'Variable', 'Estimate', 'StdErr', 'Zvalue', 'Pvalue')
model_list <- c(model_list, list(model))
### 逐步选择过程
while(length(Remaining)>0){
## 计算剩余变量的显著性
Remaining_Sl_list <- list()
for(var in Remaining){
formula <- paste0(label, ' ~ ', paste(c(Selected, var), collapse = "+"))
result <- glm(formula, data=data, family=binomial)
summ <- summary(result)
coef <- data.frame(summ$coefficients)
coef <- tibble::rownames_to_column(coef, "Variable")
coef <- coef[coef$Variable == var, ]
Remaining_Sl_list <- c(Remaining_Sl_list, list(coef))
}
Remaining_Sl <- dplyr::bind_rows(Remaining_Sl_list)
colnames(Remaining_Sl) <- c('Variable', 'Estimate', 'StdErr', 'Zvalue', 'Pvalue')
Entered_var <- Remaining_Sl$Variable[which.min(Remaining_Sl$Pvalue)]
z <- Remaining_Sl$Zvalue[which.min(Remaining_Sl$Pvalue)]
p <- min(Remaining_Sl$Pvalue)
if(p>slentry){
break
}else{
Step <- Step+1
NumberInModel <- NumberInModel+1
Selected <- c(Selected, Entered_var)
Remaining <- Remaining[Remaining!=Entered_var]
SelectionProcess <- data.frame(Step=Step,
Entered=Entered_var,
Removed='-',
NumberInModel=NumberInModel,
Zvalue=z,
Pvalue=p,
stringsAsFactors=FALSE)
SelectionProcess_list <- c(SelectionProcess_list, list(SelectionProcess))
formula <- paste0(label, ' ~ ', paste(Selected, collapse = "+"))
result <- glm(formula, data=data, family=binomial)
summ <- summary(result)
model <- data.frame(summ$coefficients)
model <- tibble::rownames_to_column(model, "variable")
rownames(model) <- NULL
model <- cbind(Step, model)
colnames(model) <- c('Step', 'Variable', 'Estimate', 'StdErr', 'Zvalue', 'Pvalue')
model_list <- c(model_list, list(model))
result_list <- c(result_list, list(result))
## 剔除已选择变量中最不显著的变量
var_Pvalue <- model[model$Variable!='(Intercept)', ]
if(max(var_Pvalue$Pvalue)>slstay){
Step <- Step+1
NumberInModel <- NumberInModel-1
Removed_var <- var_Pvalue$Variable[which.max(var_Pvalue$Pvalue)]
z <- var_Pvalue$Zvalue[which.max(var_Pvalue$Pvalue)]
p <- max(var_Pvalue$Pvalue)
Selected <- Selected[Selected!=Removed_var]
Remaining <- c(Remaining, Removed_var)
SelectionProcess <- data.frame(Step=Step,
Entered='-',
Removed=Removed_var,
NumberInModel=NumberInModel,
Zvalue=z,
Pvalue=p,
stringsAsFactors=FALSE)
SelectionProcess_list <- c(SelectionProcess_list, list(SelectionProcess))
formula <- paste0(label, ' ~ ', paste(Selected, collapse = "+"))
result <- glm(formula, data=data, family=binomial)
summ <- summary(result)
model <- data.frame(summ$coefficients)
model <- tibble::rownames_to_column(model, "variable")
rownames(model) <- NULL
model <- cbind(Step, model)
colnames(model) <- c('Step', 'Variable', 'Estimate', 'StdErr', 'Zvalue', 'Pvalue')
model_list <- c(model_list, list(model))
result_list <- c(result_list, list(result))
}
}
}
SelectionProcess <- dplyr::bind_rows(SelectionProcess_list)
models <- dplyr::bind_rows(model_list)
model_optimal <- model_list[[length(model_list)]]
result_optimal <- result_list[[length(result_list)]]
model_optimal$significance[model_optimal$Pvalue<=0.001] <- '***'
model_optimal$significance[model_optimal$Pvalue>0.001 & model_optimal$Pvalue<=0.01] <- '**'
model_optimal$significance[model_optimal$Pvalue>0.01 & model_optimal$Pvalue<=0.05] <- '*'
model_optimal$significance[model_optimal$Pvalue>0.05] <- ''
lst <- list(SelectionProcess=SelectionProcess, models=models, model_optimal=model_optimal, result_optimal=result_optimal)
return(lst)
}
2、迭代剔除系数为负值和VIF较大的变量:
model_logit <- function(data, label, slentry, slstay){
# author: 小石头(bigdata_0819@163.com)
# data:包含自变量和应变量的数据框
# label:应变量
# return: lst:
# SelectionProcess: 变量逐步选择的过程
# models: 每一步的模型结果
# model_optimal: 最终输出的模型
# result_optimal: 最终输出的模型结果
while(TRUE){
### 剔除系数为负值的变量
while(TRUE){
lst <- logit_stepwise(data=data, label=label, slentry=slentry, slstay=slstay)
SelectionProcess <- lst$SelectionProcess
models <- lst$models
model_optimal <- lst$model_optimal
result_optimal <- lst$result_optimal
vars_minus <- model_optimal$Variable[model_optimal$Estimate<0]
vars_minus <- SelectionProcess$Entered[SelectionProcess$Entered %in% vars_minus]
if(length(vars_minus)>0){
data <- dplyr::select(data, -c(vars_minus[length(vars_minus)]))
}else{
break
}
}
### 剔除VIF>10的变量
model_vars <- model_optimal$Variable[model_optimal$Variable!='(Intercept)']
formula = paste0(label, ' ~ ', paste(model_vars, collapse = "+"))
la <- lm(formula, data)
VIF <- car::vif(la)
if(max(VIF)>10){
data <- dplyr::select(data, -c(names(VIF)[which.max(VIF)]))
}else{
break
}
}
VIF_df <- data.frame(Variable=names(VIF), VIF=VIF)
model_optimal <- merge(model_optimal, VIF_df, by='Variable', all.x=TRUE, all.y=FALSE)
model_optimal <- dplyr::select(model_optimal, -c('Step'))
Step_df <- SelectionProcess[!duplicated(SelectionProcess$Entered, fromLast=TRUE), c('Step', 'Entered')]
colnames(Step_df) <- c('Step', 'Variable')
model_optimal <- merge(Step_df, model_optimal, by='Variable', all.x=FALSE, all.y=TRUE)
model_optimal[model_optimal$Variable=='(Intercept)', 'Step'] <- 0
model_optimal <- dplyr::arrange(model_optimal, Step)
model_optimal$Step <- 1:length(model_optimal$Step)-1
lst <- list(SelectionProcess=SelectionProcess, models=models, model_optimal=model_optimal, result_optimal=result_optimal)
return(lst)
}
使用相同数据集查看训练结果,可以看出最终结果和上篇的一致的。
lst <- model_logit(data=data, label='target', slentry=0.05, slstay=0.05)
model_optimal <- lst$model_optimal
同时发现VIF的值有一些差异,主要因为这里使用的R方法在计算VIF做线性回归时包含了截距项,而Python模块statsmodels.stats.outliers_influence中的variance_inflation_factor函数在做线性回归时没有包含截距项(见下面的源码)。是否包含截距项对VIF值的影响不大,也不改变各变量VIF的排序性,因而并不影响结果。
variance_inflation_factor的源码:
##### variance_inflation_factor源码 #####
"""Influence and Outlier Measures
Created on Sun Jan 29 11:16:09 2012
Author: Josef Perktold
License: BSD-3
"""
from statsmodels.regression.linear_model import OLS
def variance_inflation_factor(exog, exog_idx):
"""variance inflation factor, VIF, for one exogenous variable
The variance inflation factor is a measure for the increase of the
variance of the parameter estimates if an additional variable, given by
exog_idx is added to the linear regression. It is a measure for
multicollinearity of the design matrix, exog.
One recommendation is that if VIF is greater than 5, then the explanatory
variable given by exog_idx is highly collinear with the other explanatory
variables, and the parameter estimates will have large standard errors
because of this.
Parameters
----------
exog : ndarray
design matrix with all explanatory variables, as for example used in
regression
exog_idx : int
index of the exogenous variable in the columns of exog
Returns
-------
vif : float
variance inflation factor
Notes
-----
This function does not save the auxiliary regression.
See Also
--------
xxx : class for regression diagnostics TODO: does not exist yet
References
----------
https://en.wikipedia.org/wiki/Variance_inflation_factor
"""
k_vars = exog.shape[1]
x_i = exog[:, exog_idx]
mask = np.arange(k_vars) != exog_idx
x_noti = exog[:, mask]
r_squared_i = OLS(x_i, x_noti).fit().rsquared
vif = 1. / (1. - r_squared_i)
return vif
历史文章
本文分享自微信公众号 - 大数据建模的一点一滴(bigdatamodeling)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
【计算机视觉处理三】图像基本处理
图像基本处理 1、图像切片 在前面我们了解到opencv中的图像实际上就是一个ndarray数组,我们对ndarray数组进行操作就是对图像进行操作。我们先来看一下切片查找,这是我们非常常用的一个操作。 (1)一维数组的切片 我们来看看切片的语法,对于一维的数组我们可以通过下面的操作获取第0个到第4个元素: array[0:5] 从上面可以知道我们的切片操作是左闭右开的。上面的切片操作我们可以简写一下: array[:5] 如果我们没有设置第一个值,则表示从头开始切片。当然我们还可以省略第二个值,这时含义就是取到最后一个元素,比如下面的操作: array[3:] 我们用一个实际的例子来看看切片操作: import numpy as np# 创建一个一维的ndarray数组,数据为[0, 1, 2, 3, 4, 5, 6, 7]array = np.array([0, 1, 2, 3, 4, 5, 6, 7])# 取0到4个元素print(array[0:5])print(array[:5])# 取第3个到最后一个元素print(array[3:]) 输出内容如下: [0 1 2 3 4...
- 下一篇
Boltdb 源码导读(一):Boltdb 数据组织
boltdb 是市面上为数不多的纯 go 语言开发的、单机 KV 库。boltdb 基于 Howard Chu'sLMDB 项目 ,实现的比较清爽,去掉单元测试和适配代码,核心代码大概四千多行。简单的 API、简约的实现,也是作者的意图所在。由于作者精力所限,原 boltdb 已经封版,不再更新。若想改进,提交新的 pr,建议去 etcd 维护的 fork 版本 bbolt。 为了方便,本系列导读文章仍以不再变动的原 repo 为基础。该项目麻雀虽小,五脏俱全,仅仅四千多行代码,就实现了一个基于 B+ 树索引、支持一写多读事务的单机 KV 引擎。代码本身简约朴实、注释得当,如果你是 go 语言爱好者、如果对 KV 库感兴趣,那 boltdb 绝对是不可错过的一个 repo。 本系列计划分成三篇文章,依次围绕数据组织、索引设计、事务实现等三个主要方面对 boltdb 源码进行剖析。由于三个方面不是完全正交解耦的,因此叙述时会不可避免的产生交织,读不懂时,暂时略过即可,待有全貌,再回来梳理。本文是第一篇, boltdb 数据组织。 引子 一个存储引擎最底层的构成,就是处理数据在各种物理介质...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8编译安装MySQL8.0.19
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS关闭SELinux安全模块
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- CentOS7设置SWAP分区,小内存服务器的救世主
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库