python 方差膨胀因子 检验_从零开始学Python【22】--线性回归诊断(第一部分)

本文介绍了如何在Python中进行线性回归模型的诊断,包括线性性检验、多重共线性检验(通过方差膨胀因子VIF)和异常值检测。使用CCPP数据集,通过散点图、Pearson相关系数和VIF因子判断变量关系和共线性。结果显示,自变量与因变量存在线性关系,无多重共线性问题,并通过异常值检测进行了处理,提高了模型的准确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

往期回顾

前言

在上一期中,关于线性回归模型的创建,我们对比了Python和R语言的具体代码实现,受到了很多网友的关注。也有一些朋友问到,关于线性回归模型的那些前提假设为什么没有作分享,这期和下期我们就来回答一下这个问题。由于线性回归模型的偏回归系数通过最小二乘法(OLS)实现的,关于最小二乘法的使用是有一些假设前提的,具体是:自变量与因变量之间存在线性关系;

自变量之间不存在多重共线性;

回归模型的残差服从正态分布;

回归模型的残差满足方差齐性(即方差为某个固定值);

回归模型的残差之间互相独立;

当然,除了上面提到的5点之外,我们还需要注意的是,线性回归模型对异常值是非常敏感的,模型预测的结果非常容易受到异常值的影响,所以,我们还需要对原始数据进行异常点识别和处理。在本期中,我们先针对上面提到的前三个假设做判别,此外再分享一下关于异常点的相关内容。本次分享的数据集来自于UCI【高炉煤气联合循环发电(CCPP)数据集(数据来源:http://archive.ics.uci.edu/ml/datasets/combined+cycle+power+plant)】。

线性性检验

线性回归模型,顾名思义,首先要保证自变量与因变量之间存在线性关系。关于线性关系的判断,我们可以通过图形或Pearson相关系数来识别,具体Python代码如下:# 导入第三方包import pandas as pdimport numpy as npfrom patsy import dmatricesfrom statsmodels.stats.outliers_influence import variance_inflation_factorimport statsmodels.api as smimport scipy.stats as statsfrom sklearn.metrics import mean_squared_errorimport seaborn as snsimport matplotlib.pyplot as pltimport matplotlib.mlab as mlab# 数据读取ccpp = pd.read_excel('CCPP.xlsx')

ccpp.describe()# AT:温度# V:压力# AP:相对湿度# RH:排气量# PE:发电量# 绘制各变量之间的散点图sns.pairplot(ccpp)

plt.show()

从上面的散点图来看,似乎AP(相对湿度)和RH(排气量)与PE(发电量)之间并不存在明显的线性关系,具体我们还需要看一下PE与其余变量之间的Pearson相关系数值。# 发电量与自变量之间的相关系数ccpp.corrwith(ccpp.PE)

从返回的结果来看,PE(发电量)与AT(温度)和V(压力)之间的相关系数还是蛮高的,而PE与AP(相对湿度)和RH(排气量)之间的相关系数就明显小很多。一般情况下,当Pearson相关系数低于0.4,则表明变量之间存在弱相关关系;当Pearson相关系数在0.4~0.6之间,则说明变量之间存在中度相关关系;当相关系数在0.6以上时,则反映变量之间存在强相关关系。经过对比发现,PE与RH之间的为弱相关关系,故不考虑将该变量纳入模型。当然,变量之间不存在线性关系并不代表不存在任何关系,可能是二次函数关系、对数关系等,所以一般还需要进行检验和变量转换。

多重共线性检验

先来了解一下,如果模型的自变量之间存在严重的多重共线性的话,会产生什么后果呢?导致OLS估计量可能无效;

增大OLS估计量的方差;

变量的显著性检验将失去意义;

模型缺乏稳定性;

所以,多重共线性检验就显得非常重要了,关于多重共线性的检验可以使用方差膨胀因子(VIF)来鉴定,如果VIF大于10,则说明变量存在多重共线性。一旦发现变量之间存在多重共线性的话,可以考虑删除变量和重新选择模型(岭回归法)。# 将因变量PE,自变量AT,V,AP和截距项(值为1的1维数组)以数据框的形式组合起来y, X = dmatrices('PE~AT+V+AP', data = ccpp, return_type='dataframe')# 构造空的数据框vif = pd.DataFrame()

vif["VIF Factor"] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]

vif["features"] = X.columns

vif

结果显示,所有自变量的VIF均低于10,说明自变量之间并不存在多重共线性的隐患。

异常点检测

在异常点检测之前,我们需要对现有的数据,进行线性回归模型的构造。具体操作如下,与上一期文章中回归模型的建模一致:# 构造PE与AT、V和AP之间的线性模型fit = sm.formula.ols('PE~AT+V+AP',data = ccpp).fit()

fit.summary()# 计算模型的RMSE值pred = fit.predict()

np.sqrt(mean_squared_error(ccpp.PE, pred))

通过上面的建模结果来看,一切都显得那么的完美(模型的显著性检验通过,偏回归系数的显著性检验通过;R方值也达到了0.9以上)。尽管这样,我们还是需要基于这个模型,完成异常点的检测。

关于异常点的检测方法,一般可以通过高杠杆值点(帽子矩阵)或DFFITS值、学生化残差、cook距离和covratio值来判断。这些值的具体计算脚本如下:# 离群点检验outliers = fit.get_influence()# 高杠杆值点(帽子矩阵)leverage = outliers.hat_matrix_diag# dffits值dffits = outliers.dffits[0]# 学生化残差resid_stu = outliers.resid_studentized_external# cook距离cook = outliers.cooks_distance[0]# covratio值covratio = outliers.cov_ratio# 将上面的几种异常值检验统计量与原始数据集合并contat1 = pd.concat([pd.Series(leverage, name = 'leverage'),pd.Series(dffits, name = 'dffits'),

pd.Series(resid_stu,name = 'resid_stu'),pd.Series(cook, name = 'cook'),

pd.Series(covratio, name = 'covratio'),],axis = 1)

ccpp_outliers = pd.concat([ccpp,contat1], axis = 1)

ccpp_outliers.head()

通过参考薛毅老师的《统计建模与R软件》书可知,当高杠杆值点(或帽子矩阵)大于2(p+1)/n时,则认为该样本点可能存在异常(其中p为自变量的个数,n为观测的个数);当DFFITS统计值大于2sqrt((p+1)/n)时,则认为该样本点可能存在异常;当学生化残差的绝对值大于2,则认为该样本点可能存在异常;对于cook距离来说,则没有明确的判断标准,一般来说,值越大则为异常点的可能性就越高;对于covratio值来说,如果一个样本的covratio值离数值1越远,则认为该样本越可能是异常值。这里我们就以学生化残差作为评判标准,因为其包含了帽子矩阵和DFFITS的信息。# 计算异常值数量的比例outliers_ratio = sum(np.where((np.abs(ccpp_outliers.resid_stu)>2),1,0))/ccpp_outliers.shape[0]

outliers_ratio# 删除异常值ccpp_outliers = ccpp_outliers.loc[np.abs(ccpp_outliers.resid_stu)<=2,]

结果显示,确实存在异常值点,且异常值的数量占了3.7%。对于异常值的处理,我们可以考虑下面几种办法:当异常比例极低时(如5%以内),可以考虑直接删除;

当异常比例比较高时,可以考虑将异常值衍生为哑变量,即异常值对应到1,非异常值则对应到0;

将单独把异常值提取出来,另行建模;

这里为了简单起见,我们将3.7%的异常值作删除处理。# 重新建模fit2 = sm.formula.ols('PE~AT+V+AP',data = ccpp_outliers).fit()

fit2.summary()# 计算模型的RMSE值pred2 = fit2.predict()

np.sqrt(mean_squared_error(ccpp_outliers.PE, pred2))

通过对比fit和fit2,将异常值删除后重新建模的话,效果会更理想一点,具体表现为:信息准则(AIC和BIC)均变小,同时RMSE(误差均方根)也由原来的4.89降低到4.26。

正态性检验

当模型的残差服从正态性假设时,才能保证模型偏回归系数对于的t值和模型的F值是有效的。故模型建好后,要对模型的残差进行正态性检验。关于正态性检验由两类方法,即定性的图形法(直方图、PP图和QQ图)和定量的非参数法(Shapiro检验和K-S检验)。# 残差的正态性检验(直方图法)resid = fit2.resid# 中文和负号的正常显示plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']

plt.rcParams['axes.unicode_minus'] = Falseplt.hist(resid, # 绘图数据

bins = 100, # 指定直方图条的个数

normed = True, # 设置为频率直方图

color = 'steelblue', # 指定填充色

edgecolor = 'k') # 指定直方图的边界色# 设置坐标轴标签和标题plt.title('残差直方图')

plt.ylabel('密度值')# 生成正态曲线的数据x1 = np.linspace(resid.min(), resid.max(), 1000)

normal = mlab.normpdf(x1, resid.mean(), resid.std())# 绘制正态分布曲线plt.plot(x1,normal,'', linewidth = 2, label = '正态分布曲线')

# 生成核密度曲线的数据kde = mlab.GaussianKDE(resid)

x2 = np.linspace(resid.min(), resid.max(), 1000)# 绘制核密度曲线plt.plot(x2,kde(x2),'', linewidth = 2, label = '核密度曲线')# 去除图形顶部边界和右边界的刻度plt.tick_params(top='off', right='off')# 显示图例plt.legend(loc='best')# 显示图形plt.show()

从残差的直方图来看,核密度曲线与理论的正态分布曲线的趋势还是比较吻合的,即使残差不服从正态分布,也能反映其基本近似于正态分布。# 残差的正态性检验(PP图和QQ图法)pp_qq_plot = sm.ProbPlot(resid)

pp_qq_plot.ppplot(line = '45')

plt.title('P-P图')

pp_qq_plot.qqplot(line = 'q')

plt.title('Q-Q图')# 显示图形plt.show()

从PP图和QQ图来看,有一部分样本点并没有落在参考线上,但绝大多数样本点还是与参考线保持一致的步调。# 残差的正态性检验(非参数法)standard_resid = (resid-np.mean(resid))/np.std(resid)

stats.kstest(standard_resid, 'norm')

由于shapiro正态性检验对样本量的要求是5000以内;而本次数据集的样本量由9000多,故选择K-S来完成正态性检验。从K-S检验的P值来看,拒绝了残差服从正态分布的假设,即认为残差并不满足正态性假设这个前提。如果残差不服从正态分布的话,建议对Y变量进行box-cox变换处理。由于fit2模型的残差并没有特别明显的偏态(偏度为0.058,接近于0),故这里就不对Y变量进行box-cox变换了。如果需要变换的话,可以以下面的代码为例:import scipy.stats as stats# 找到box-cox变换的lambda系数lamd = stats.boxcox_normmax(your_data_frame.y, method = 'mle')# 对Y进行变换your_data_frame['trans_y'] = stats.boxcox(your_data_frame.y, lamd)# 建模fit = sm.formula.ols('y~x1+x2+...', data = your_data_frame).fit()

fit.summary()

关于线性回归模型的异常点识别、线性性假设、无多重共线性假设和残差的正态性假设在Python中的实现就介绍到这里。下一期,我们将针对线性回归模型残差的方差齐性和独立性假设进行讲解,接下来我们再用R语言对上面的内容复现一遍。

R语言脚本复现# 加载第三方包library(readxl)library(GGally)# 读取数据ccpp

summary(ccpp)

# 绘制各变量之间的散点图与相关系数ggpairs(ccpp)

# 建模fit

summary(fit)# 计算模型的RMSE值RMSE = sqrt(mean(fit$residuals**2))

RMSE

# 多重共线性检验vif(fit)

# 异常点检验# 高杠杆值点(帽子矩阵)leverage

head(leverage)# dffits值Dffits

head(Dffits)# 学生化残差resid_stu

head(resid_stu)# cook距离cook

head(cook)# covratio值Covratio

head(Covratio)# 将上面的几种异常值检验统计量与原始数据集合并ccpp_outliers

head(ccpp_outliers)

# 计算异常值数量的比例outliers_ratio = sum(abs(ccpp_outliers$resid_stu)>2)/nrow(ccpp_outliers)

outliers_ratio# 删除异常值ccpp_outliers = ccpp_outliers[abs(ccpp_outliers$resid_stu)<=2,]# 重新建模fit2 = lm(PE~AT+V+AP,data = ccpp_outliers)

summary(fit2)# 计算模型的RMSE值RMSE2 = sqrt(mean(fit2$residuals**2))

RMSE2

# 正态性检验#绘制直方图hist(x = fit2$residuals, freq = FALSE,

breaks = 100, main = 'x的直方图',

ylab = '核密度值',xlab = NULL, col = 'steelblue')#添加核密度图lines(density(fit2$residuals), col = 'red', lty = 1, lwd = 2)#添加正态分布图x

lines(x, dnorm(x, mean(x), sd(x)),

col = 'blue', lty = 2, lwd = 2.5)#添加图例legend('topright',legend = c('核密度曲线','正态分布曲线'),

col = c('red','blue'), lty = c(1,2),

lwd = c(2,2.5), bty = 'n')

# PP图real_dist

theory_dist

sd = sd(fit2$residuals))# 绘图plot(sort(theory_dist), real_dist, col = 'steelblue',

pch = 20, main = 'PP图', xlab = '理论正态分布累计概率',

ylab = '实际累计概率')# 添加对角线作为参考线abline(a = 0,b = 1, col = 'red', lwd = 2)

# QQ图qqnorm(fit2$residuals, col = 'steelblue', pch = 20,

main = 'QQ图', xlab = '理论分位数',

ylab = '实际分位数')# 绘制参考线qqline(fit2$residuals, col = 'red', lwd = 2)

# shapiro正态性检验# shapiro

mean = mean(fit2$residuals),

sd = sd(fit2$residuals))

ks

结语

OK,今天关于线性回归诊断部分的内容就分享到这里,限于篇幅,不能一次性写完,故在下一期将继续推出诊断的其他内容(残差的方差齐性和残差的独立性检验)。希望对数据挖掘或机器学习比较感兴趣的朋友,能够静下心来好好的复现一遍。如果你有任何问题,欢迎在公众号的留言区域表达你的疑问。同时,也欢迎各位朋友继续转发与分享文中的内容,让更多的朋友学习和进步。

关注“每天进步一点点2015”

相关材料下载链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值