这篇博客,伤到我的脑细胞了——线性回归分析案例


一、背景介绍

 在宏观经济学的理论中,投资是构成GDP的一部分,我国经济增长一般都用我国的GDP总量来衡量。从这一点来说,投资与经济增长之间应该存在着相关关系。由于投资与经济增长存在着相互作用,因此,从理论上讲固定资产投资对经济增长存在着相互作用、相互影响的关系。固定资产投资的增加可以推动经济总量的增长,同时经济增长的水平在一定程度上也决定着固定资产总量的水平。为了探讨其具体的定量关系,本文将根据北京市统计年鉴的2005年-2018年各行业固定资产投资额和GDP数据,进行回归分析,探讨行业固定资产投资额对行业GDP的贡献情况,并分析全市GDP数据与各行业投资额之间的量化关系。
在这里插入图片描述
数据来源:北京市统计局1

下述代码 阅读/运行 须知:
为了第二、第三及第四部分的内容展示上稍微精简一些,将部分可能重复用到的代码进行了打包工作,统一在第五部分展示,即 分析函数化Codes 部分,因此如需运行第二、第三及第四部分的代码,请先运行第五部分的代码。

二、数据探索

# 读取数据
sheet_names = ["北京市投资与gdp","各行业gdp","各行业固定资产投资"]
names = ["年份","全市","建筑业","批发和零售业","交通运输、仓储和邮政业","住宿和餐饮业" ,
         "信息传输、软件和信息技术服务业","金融业","房地产业","租赁和商务服务业",
         "科学研究和技术服务业","水利、环境和公共设施管理业","居民服务、修理和其他服务业",
         "教育","卫生和社会工作","文化、体育和娱乐业","公共管理、社会保障和社会组织"]

# data = pd.read_excel('20200306 各行业投资与经济增长回归(慕).xls',sheet_name=sheet_names[1],
#                      skiprows=3,names =names,index_col=0,dtypes={names[1]:np.float})
industry_gdp_data = pd.read_excel('20200306 各行业投资与经济增长回归(慕).xls',sheet_name=sheet_names[1],
                     header=0,index_col=0)
industry_fac_data = pd.read_excel('20200306 各行业投资与经济增长回归(慕).xls',sheet_name=sheet_names[2],
                     header=0,index_col=0)

可视化了解各行业GDP与固定资产投资的关系

# 画散点图
fig = plt.figure(figsize=(180,70))
for i in range(1,len(names)):
    ax = fig.add_subplot(2,8,i)
    ax.scatter(industry_fac_data[names[i]],industry_gdp_data[names[i]],s=500)
    plt.title(names[i],fontsize=56)
    plt.xlabel(names[i]+'投资额',fontsize=48)
    plt.ylabel(names[i]+'GDP',fontsize=48)
    plt.xticks(fontsize=48)
    plt.yticks(fontsize=48)
plt.show()
# fig.tight_layout() #自动调整格式

在这里插入图片描述

# 全市各行业的GDP与对应行业投资额的相关性
corr_gdp_industry_list = []
for i in range(1,len(names)):
    corr_gdp_industry_list.append(industry_fac_data[names[i]].corr(industry_gdp_data[names[i]]))

figure = plt.figure(figsize=(20,10))
corr_bar = plt.bar(names[1:len(names)],corr_gdp_industry_list)
plt.xticks(rotation=60,fontsize=12)
for bar in corr_bar:
    height = bar.get_height()
    plt.text(bar.get_x() + bar.get_width() / 2, height, str(('%.2f')%height), ha='center', va='bottom',fontsize=14)
plt.axhline(0.9,color='r')
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.title('全市各行业的GDP与对应行业投资额相关性条形图',fontsize=16)
plt.show()

在这里插入图片描述
小结:
通过上图各行业GDP与固定资产投资的关系散点图、相关性结果可知

  • 交通运输仓储和邮政业、信息传输软件和信息技术服务业、房地产业、水利环境和公共设施管理业 4个行业的投资额与其各自的GDP,具有较好的相关性,超过0.9,其他行业的gdp和投资额的相关性还需要进一步来判断。
  • 另外,全市的投资额和GDP,也具有很强的相关性。

箱型图,了解各行业GDP数据分布情况

title_name = '各行业GDP数据箱线图'
sub_ylabel = "GDP"
industry_boxplot_mu(industry_gdp_data,title_name,sub_ylabel)

在这里插入图片描述


plt.figure(figsize=(15,10))
industry_gdp_data.ix[:,1:].boxplot(vert=False,
                                   showmeans=True, # 以点的形式显示均值
                                  meanprops = {'marker':'D','markerfacecolor':'indianred','linewidth':1} # 设置均值点的属性,点的形状、填充色
                                  )

plt.xlabel('GDP',fontsize=14)
plt.ylabel('行业',fontsize=14)
plt.xticks(rotation=0,fontsize=12)
plt.yticks(fontsize=12)
plt.title('各行业GDP数据箱线图',fontsize=18)

在这里插入图片描述
小结:
通过各行业GDP的箱线图可知,各行业的GDP数据均无异常,但部分行业的GDP存在左偏或者右偏现象。

  • 批发和零售业、住宿和餐饮业、左偏现象比较明显;
  • 信息传输软件和信息服务业、金融业、科学研究和技术服务业、水利环境额 公共设施管理业、教育、卫生和社会工作,右偏现象较明显

箱型图,了解各行业投资额数据分布情况

title_name = '各行业 投资额数据箱线图'
sub_ylabel = "投资额"
industry_boxplot_mu(industry_fac_data,title_name,sub_ylabel)

在这里插入图片描述


plt.figure(figsize=(15,10))
industry_fac_data.ix[:,1:].boxplot(vert=False,
                                   showmeans=True, # 以点的形式显示均值
                                  meanprops = {'marker':'D','markerfacecolor':'indianred','linewidth':1} # 设置均值点的属性,点的形状、填充色
                                  )
plt.title('各行业投资额数据箱线图',fontsize=16)
plt.xlabel('GDP',fontsize=14)
plt.ylabel('行业',fontsize=14)
plt.xticks(rotation=0,fontsize=12)
plt.yticks(fontsize=12)

plt.show()

在这里插入图片描述
小结:
通过各行业投资额的箱线图可知,行业的投资额历年数据,也存在一定的偏态,并且部分行业的投资额变化较大。

  • 诸如建筑业、批发和零售业、交通运输仓储和邮政业、信息传输软件和信息技术服务业、租赁和商务服务业、文化体育和娱乐业,根据箱线图判断,存在异常数据;
  • 除过上述含异常值的行业,其余行业中,金融业、房地产业、科学研究和技术服务业、教育、卫生和社会工作,投资额存在左偏现象;
  • 而水利环境和公共设施管理业、居民服务修理和其他服务业、公共管理社会保障和社会组织,投资额存在右偏现象。
    可视化了解各行业GDP之间的关系
    (1)画矩阵散点图
'''
kdeplot(核密度估计图):核密度估计(kernel density estimation)是在概率论中用来估计未知的密度函数,
              属于非参数检验方法之一。通过核密度估计图可以比较直观的看出数据样本本身的分布特征。
distplot :displot()集合了matplotlib的hist()与核函数估计kdeplot的功能,
              增加了rugplot分布观测条显示与利用scipy库fit拟合参数分布的新颖用途。
'''
g = sns.PairGrid(industry_gdp_data)
g.map_diag(sns.distplot) #设置对角线图表
g.map_upper(plt.scatter, color = 'r')  #设置对角线上端图表
g.map_lower(sns.kdeplot, cmap='Blues_d') #设置对角线下端图表

在这里插入图片描述
(2) 画相关系数矩阵图

gdp_corr = industry_gdp_data.corr()  # gdp相关系数矩阵

vmax=gdp_corr.max().max()
vmin=gdp_corr.min().min()
print("最小相关系数:",vmin)

plt.figure(figsize=(15,15))

'''
annot=True,意思是显式热力图上的数值大小
square=True,意思是将图变成一个正方形,默认是一个矩形
cmap="Blues"是一种模式,就是图颜色配置方案
vmax是显示最大值
'''
sns.heatmap(gdp_corr,annot=True,vmax=vmax,vmin=vmin,square=True,cmap='Blues')

在这里插入图片描述
小结:
通过散点图和相关系数矩阵图,均可以发现,各行业的GDP之间具有较强的正相关,普遍相关系数,均在0.8以上。

可视化了解各行业固定资产投资的关系
(1) 画矩阵散点图

'''
kdeplot(核密度估计图):核密度估计(kernel density estimation)是在概率论中用来估计未知的密度函数,
              属于非参数检验方法之一。通过核密度估计图可以比较直观的看出数据样本本身的分布特征。
distplot :displot()集合了matplotlib的hist()与核函数估计kdeplot的功能,
              增加了rugplot分布观测条显示与利用scipy库fit拟合参数分布的新颖用途。
'''
g = sns.PairGrid(industry_fac_data)
g.map_diag(sns.distplot) #设置对角线图表
g.map_upper(plt.scatter, color = 'r')  #设置对角线上端图表
g.map_lower(sns.kdeplot, cmap='Blues_d') #设置对角线下端图表

在这里插入图片描述
(2)画相关系数矩阵图

fac_corr = industry_fac_data.corr()  # gdp相关系数矩阵

vmax=fac_corr.max().max()
vmin=fac_corr.min().min()
print("最小相关系数:",vmin)
# print("最大相关系数:",vmax)


plt.figure(figsize=(15,15))
sns.heatmap(fac_corr,annot=True,vmax=vmax,vmin=vmin,square=True,cmap='Blues')
plt.title("各行业固定资产投资的关系相关系数矩阵图",fontsize=18)

在这里插入图片描述
小结:
对于各行业的投资额,通过散点图矩阵和相关系数矩阵可以发现,

  • 行业间的投资额的相关性,相对行业GDP的相关性要弱一些,并且部分行业间投资额具有负相关性。
  • 建筑业、文化体育和娱乐业、公共管理社会保障和社会组织,相对来说,普遍与其他行业的相关性较弱。

通过上述分析,信息传输软件和信息技术服务业、房地产业、水利环境和公共设施管理业 3个行业的投资额与其各自的GDP,具有较好的线性关系;大部分行业的历年GDP和投资额,存在左偏或者右偏现象;行业GDP之间相关性普遍较强,而行业投资额间相关性则分化比较大。

三、信息传输、软件和信息技术服务业回归分析

1. 投资额和GDP可视化

industry_name = "信息传输、软件和信息技术服务业" 
ytrain = industry_gdp_data[industry_name]
xtrain = industry_fac_data[industry_name]

2. 回归分析

(1)模型一:原始数据

model,y_pre = simple_regression_mu(ytrain,xtrain)
model.summary()

在这里插入图片描述
在这里插入图片描述
小结
模型通过检验,模型的系数通过检验,但是模型的常数项没有通过检验。另外,D.W.的值为2.152,根据DW检验表,DW取值在(dU, 4- dU)之间,接受原假设H0 ,认为ut 非自相关,即在信息传输、软件和信息技术服务业,残差非自相关,但也有可能残差具有较高的自相关性。

# 拟合结果可视化
visual_regression_result(range(len(ytrain)),ytrain,y_pre)
# visual_regression_result(model,sm.add_constant(xtrain))

在这里插入图片描述
** 残差分析**

线性模型的残差通常具有正太分布。我们可以绘制残差密度来检查正态性。


fig = plt.figure(figsize=(15,5))
ax = fig.add_subplot(121)
# model.resid.plot.density()  #残差密度图
model.resid.hist(bins=5,alpha = 0.5)
model.resid.plot(kind = 'kde', secondary_y=True)
ax.set_title('密度直方图')
# plt.grid()

ax2 = fig.add_subplot(122)
# qq图
stats.probplot(model.resid, dist="norm", plot=plt)
plt.show()

在这里插入图片描述

# 残差正态性检验

from scipy.stats import kstest    # K-S检验:特点是比较严格,基于的原理是CDF,理论上可以检验任何分布
ks_result = kstest(model.resid,'norm')
print('kstest检验:',ks_result)
 
from scipy.stats import shapiro   # Shapiro检验:专门用来检验正态分布  shapiro 不适合做样本数>5000的正态性检验,检验结果的P值可能不准确
shap_result = shapiro(model.resid)
print('shapiro检验:',shap_result)

from scipy.stats import normaltest  # Normal检验:原理是基于数据的skewness和kurtosis
norm_result = normaltest(model.resid,axis=None)
print('normaltest检验:',norm_result)

kstest检验2: KstestResult(statistic=0.5714285714285714, pvalue=7.456196123263218e-05)
shapiro检验: (0.901134729385376, 0.11714380979537964)
normaltest检验: NormaltestResult(statistic=6.129670593453145, pvalue=0.04666152653777272)

# 定量判断 残差同方差检验
# White's Test
white_test = sm.stats.diagnostic.het_white(model.resid, exog = model.model.exog)

print('模型方差齐性检验统计量:%.2f,P值:%.4f,Fvalue:%.2f,F_pvalue:%.2f:' %(white_test))
# model.model.exog

# 定性判断  残差同方差检验   及残差的自相关性判断
# 判断标准:如果残差在参考线两侧均匀分布,则意味着异方差性较弱;而如果呈现出明显的不均匀分布,则意味着存在明显的异方差性。
residual_scatter_mu(model)

模型方差齐性检验统计量:1.95,P值:0.3779,Fvalue:0.89,F_pvalue:0.44
在这里插入图片描述
小结:
根据怀特检验,残差通过方差齐性检验,但是通过残差序列图可以发现,残差还是存在一定的异方差情况;另外,根据残差序列图和残差的散点图,可以发现残差具有一定的自相关性

模型评价

print('评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):%.3f'
      %(mean_absolute_per_err(y_pre,ytrain)))

长度: 14
评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):0.134

(2) 模型二:消除异方差

#  通过对变量取对数消除异方差
log_ytrain = np.log(ytrain)
log_xtrain = np.log(xtrain)

gdp_fac_graph_mu(log_ytrain,log_xtrain)

在这里插入图片描述

model2 ,log_y_pre= simple_regression_mu(log_ytrain,log_xtrain)
model2.summary()

在这里插入图片描述

# 拟合结果可视化
visual_regression_result(range(len(log_ytrain)),ytrain,np.exp(log_y_pre))

在这里插入图片描述
残差分析

fig = plt.figure(figsize=(15,5))
ax = fig.add_subplot(121)
# model.resid.plot.density()  #残差密度图
model2.resid.hist(bins=5,alpha = 0.5)
model2.resid.plot(kind = 'kde', secondary_y=True)
ax.set_title('密度直方图')
# plt.grid()

ax2 = fig.add_subplot(122)
# qq图
stats.probplot(model2.resid, dist="norm", plot=plt)
plt.show()

在这里插入图片描述

# 残差正态性检验

from scipy.stats import kstest    # K-S检验:特点是比较严格,基于的原理是CDF,理论上可以检验任何分布
ks_result = kstest(model2.resid,'norm')
print('kstest检验:',ks_result)
 
from scipy.stats import shapiro   # Shapiro检验:专门用来检验正态分布  shapiro 不适合做样本数>5000的正态性检验,检验结果的P值可能不准确
shap_result = shapiro(model2.resid)
print('shapiro检验:',shap_result)

from scipy.stats import normaltest  # Normal检验:原理是基于数据的skewness和kurtosis
norm_result = normaltest(model2.resid,axis=None)
print('normaltest检验:',norm_result)

kstest检验: KstestResult(statistic=0.403305160372756, pvalue=0.014364366464748599)
shapiro检验: (0.931269645690918, 0.3178831934928894)
normaltest检验: NormaltestResult(statistic=1.9191948456802586, pvalue=0.3830470609372596)

# 定量判断 残差同方差检验(残差和自变量之间)
# White's Test
white_test = sm.stats.diagnostic.het_white(model2.resid, exog = model2.model.exog)

print('模型方差齐性检验统计量:%.2f,P值:%.4f,Fvalue:%.2f,F_pvalue:%.2f:' %(white_test))
# model.model.exog

# 定性判断  残差同方差检验   及残差的自相关性判断
# 判断标准:如果残差在参考线两侧均匀分布,则意味着异方差性较弱;而如果呈现出明显的不均匀分布,则意味着存在明显的异方差性。
residual_scatter_mu(model2)

模型方差齐性检验统计量:1.46,P值:0.4829,Fvalue:0.64,F_pvalue:0.55
在这里插入图片描述
模型评价

print('评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):%.3f'
      %(mean_absolute_per_err(log_y_pre,log_ytrain)))

re_log_y_pre = np.exp(log_y_pre)
print('还原数据后,评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):%.3f'
      %(mean_absolute_per_err(re_log_y_pre,ytrain)))

长度: 14
评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):0.018
长度: 14
还原数据后,评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):0.130

(3)模型三:模型变换 加入一阶滞后项,消除自相关


test = industry_fac_data[industry_name][1:]
test2 = pd.Series(industry_fac_data[industry_name][:-1])
test2.index = test.index

add_xtrain = pd.concat([test,test2],axis=1)
add_xtrain.columns = [industry_name,'滞后一年']

add_ytrain = industry_gdp_data[industry_name][1:]


# industry_FAC = sm.add_constant(industry_FAC) # 线性回归增加常数项 y=kx+b

# model = sm.OLS(industry_GDP, industry_FAC) # 普通最小二乘模型,ordinary least square model
# model = model.fit()    #res.model.endog
# # 模型检验及系数检验
# print(industry_name+" 的回归模型检验及系数检验结果:\n")
# model.summary()

model3 ,add_y_pre= simple_regression_mu(add_ytrain,add_xtrain)
model3.summary()

在这里插入图片描述

# 拟合结果可视化
visual_regression_result(range(len(add_ytrain)),add_ytrain,add_y_pre)

在这里插入图片描述
残差分析

# plt.figure()
# model.resid.plot.density()  #残差密度图
# model.resid.hist(bins=5,alpha = 0.5)
# model.resid.plot(kind = 'kde', secondary_y=True)

fig = plt.figure(figsize=(15,5))
ax = fig.add_subplot(121)
# model.resid.plot.density()  #残差密度图
model3.resid.hist(bins=5,alpha = 0.5)
model3.resid.plot(kind = 'kde', secondary_y=True)
ax.set_title('密度直方图')
# plt.grid()

ax2 = fig.add_subplot(122)
# qq图
stats.probplot(model3.resid, dist="norm", plot=plt)
plt.show()

在这里插入图片描述

# 残差正态性检验

from scipy.stats import kstest    # K-S检验:特点是比较严格,基于的原理是CDF,理论上可以检验任何分布
ks_result = kstest(model3.resid,'norm')
print('kstest检验:',ks_result)
 
from scipy.stats import shapiro   # Shapiro检验:专门用来检验正态分布
shap_result = shapiro(model3.resid)
print('shapiro检验:',shap_result)

from scipy.stats import normaltest  # Normal检验:原理是基于数据的skewness和kurtosis
norm_result = normaltest(model3.resid)
print('normaltest检验:',norm_result)

kstest检验: KstestResult(statistic=0.5384615384615384, pvalue=0.0004708705798459567)
shapiro检验: (0.9762569069862366, 0.9561669230461121)
normaltest检验: NormaltestResult(statistic=0.21037569966411002, pvalue=0.9001554126600356)

# 定性判断  残差同方差检验   及残差的自相关性判断
# 判断标准:如果残差在参考线两侧均匀分布,则意味着异方差性较弱;而如果呈现出明显的不均匀分布,则意味着存在明显的异方差性。
residual_scatter_mu(model3)

# 定量判断 残差的同方差检验
# White's Test
white_test = sm.stats.diagnostic.het_white(model3.resid, exog = model3.model.exog)

print('模型方差齐性检验统计量:%.2f,P值:%.4f,Fvalue:%.2f,F_pvalue:%.2f:' %(white_test))
# model.model.exog

模型方差齐性检验统计量:5.58,P值:0.3498,Fvalue:1.05,F_pvalue:0.46
在这里插入图片描述
模型评价

print('评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):%.3f'
      %(mean_absolute_per_err(add_y_pre,add_ytrain)))

长度: 13
评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):0.093

(4)模型四 加入一阶滞后项和数据取对数

  • 模型变换 加入一阶滞后项,消除自相关;
  • 取对数,消除异方差
log_add_xtrain = np.log(add_xtrain)
log_add_ytrain = np.log(add_ytrain)

model4 ,log_add_y_pre= simple_regression_mu(log_add_ytrain,log_add_xtrain)
model4.summary()

在这里插入图片描述


# 拟合结果可视化
visual_regression_result(range(len(log_add_ytrain)),log_add_ytrain,log_add_y_pre)

在这里插入图片描述
残差分析

fig = plt.figure(figsize=(15,5))
ax = fig.add_subplot(121)
# model.resid.plot.density()  #残差密度图
model4.resid.hist(bins=5,alpha = 0.5)
model4.resid.plot(kind = 'kde', secondary_y=True)
ax.set_title('密度直方图')
# plt.grid()

ax2 = fig.add_subplot(122)
# qq图
stats.probplot(model4.resid, dist="norm", plot=plt)
plt.show()

在这里插入图片描述

# 残差正态性检验

from scipy.stats import kstest    # K-S检验:特点是比较严格,基于的原理是CDF,理论上可以检验任何分布
ks_result = kstest(model4.resid,'norm')
print('kstest检验:',ks_result)
 
from scipy.stats import shapiro   # Shapiro检验:专门用来检验正态分布
shap_result = shapiro(model4.resid)
print('shapiro检验:',shap_result)

from scipy.stats import normaltest  # Normal检验:原理是基于数据的skewness和kurtosis
norm_result = normaltest(model4.resid)
print('normaltest检验:',norm_result)

kstest检验: KstestResult(statistic=0.4434958990037281, pvalue=0.007560196567781911)
shapiro检验: (0.9548967480659485, 0.6739445924758911)
normaltest检验: NormaltestResult(statistic=0.5897760812235786, pvalue=0.744614949433436)

# 定性判断  残差同方差检验   及残差的自相关性判断
# 判断标准:如果残差在参考线两侧均匀分布,则意味着异方差性较弱;而如果呈现出明显的不均匀分布,则意味着存在明显的异方差性。
residual_scatter_mu(model4)

# 定量判断 残差的同方差检验
# White's Test
white_test = sm.stats.diagnostic.het_white(model4.resid, exog = model4.model.exog)

print('模型方差齐性检验统计量:%.2f,P值:%.4f,Fvalue:%.2f,F_pvalue:%.2f:' %(white_test))
# model.model.exog

模型方差齐性检验统计量:3.26,P值:0.6606,Fvalue:0.47,F_pvalue:0.79
在这里插入图片描述

print('评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):%.3f'
      %(mean_absolute_per_err(log_add_y_pre,log_add_ytrain)))

re_log_add_y_pre = np.exp(log_add_y_pre)
print('还原数据后,评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):%.3f'
      %(mean_absolute_per_err(re_log_add_y_pre,add_ytrain)))

长度: 13
评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):0.012
长度: 13
还原数据后,评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):0.090

(5)单位根、协整、格兰杰因果关系

# 单位根检验
# 单位根检验是指检验序列中是否存在单位根,因为存在单位根就是非平稳时间序列了。
# 单位根就是指单位根过程,可以证明,序列中存在单位根过程就不平稳,会使回归分析中存在伪回归

x = diff_adf_test(log_xtrain,zhixindu='5%')
y = diff_adf_test(log_ytrain,zhixindu='5%')

序列1阶平稳,统计量为:-4.2812 ,p值为0.0005, 5%临界值为:-3.3672
序列1阶平稳,统计量为:-4.4592 ,p值为0.0002, 5%临界值为:-3.1894

# 协整检验
print(coint(y,x))
print(coint(x,y))

(-3.499788711567408, 0.03241412320391135, array([-5.04192472, -3.89268694, -3.41677222]))
(-0.141916031919859, 0.9820000262274053, array([-5.04192472, -3.89268694, -3.41677222]))

# 格兰杰因果关系检验
grangercausalitytests(pd.DataFrame([x,y]).T,2)

在这里插入图片描述

# 格兰杰因果关系检验
grangercausalitytests(pd.DataFrame([y,x]).T,2)

在这里插入图片描述

四、多元回归分析

4.1 可视化北京市GDP与各行业投资额的关系

fig = plt.figure(figsize=(60,50))
for i in range(2,len(names)):
    ax = fig.add_subplot(3,5,i-1)
    ax.scatter(industry_fac_data[names[i]],industry_gdp_data[names[1]],s=500)
#     plt.title(names[i],fontsize=56)
    plt.xlabel(names[i]+'投资额',fontsize=48)
    plt.ylabel(names[1]+'GDP',fontsize=48)
    plt.xticks(fontsize=48)
    plt.yticks(fontsize=48)
plt.show()

在这里插入图片描述

# 北京市GDP与各行业投资额的相关系数
corr_gdp_industry_list = []
for i in range(1,len(names)):
    corr_gdp_industry_list.append(industry_gdp_data[names[1]].corr(industry_fac_data[names[i]]))
# corr_series = pd.Series(corr_gdp_industry_list,index=names[2:len(names)])

figure = plt.figure(figsize=(15,5))
corr_bar = plt.bar(names[1:len(names)],corr_gdp_industry_list)
plt.xticks(rotation=60,fontsize=12)
for bar in corr_bar:
    height = bar.get_height()
    plt.text(bar.get_x() + bar.get_width() / 2, height, str(('%.2f')%height), ha='center', va='bottom',fontsize=14)
plt.axhline(0.8,color='r')
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.title('全市GDP与各行业投资额相关性条形图',fontsize=16)
plt.show()

在这里插入图片描述
小结:
通过上述北京市GDP和各行业的投资额散点图可知,交通运输仓储和邮政业、信息传输软件和信息技术服务业、房地产业、水利环境和公共设施管理业、教育、卫生和社会工作等6个行业,具有较强的相关性,达到0.8以上。

4.2 多元回归分析全市GDP和行业投资的关系

筛选上述相关性较强的六个行业与全市GDP关系进行回归分析。

# 
flag = pd.Series(corr_gdp_industry_list)>0.8  
x_name = [names[i] for i in range(2,len(names)) if flag[i-1]]
X = industry_fac_data[x_name]
X = sm.add_constant(X)
Y = industry_gdp_data[names[1]]
model = sm.OLS(Y,X)
model = model.fit()
model.summary()
# industry_gdp_data.index.names

在这里插入图片描述
根据上述结果,剔除交通运输仓储和邮政业、房地产业、卫生和社会工作,重新进行拟合。

x_name = ["信息传输、软件和信息技术服务业","水利、环境和公共设施管理业","教育"]

X = industry_fac_data[x_name]
X = sm.add_constant(X)
Y = industry_gdp_data[names[1]]
model = sm.OLS(Y,X)
model = model.fit()
model.summary()

在这里插入图片描述
对比未剔除交通运输仓储和邮政业、房地产业、卫生和社会工作的回归模型,剔除后,模型效果更好。

Y_p = model.predict(X)
# 拟合结果可视化
visual_regression_result(range(len(Y)),Y,Y_p)
# visual_regression_result(model,sm.add_constant(xtrain))

在这里插入图片描述

fig = plt.figure(figsize=(15,5))
ax = fig.add_subplot(121)
# model.resid.plot.density()  #残差密度图
model.resid.hist(bins=5,alpha = 0.5)
model.resid.plot(kind = 'kde', secondary_y=True)
ax.set_title('密度直方图')
# plt.grid()

ax2 = fig.add_subplot(122)
# qq图
stats.probplot(model.resid, dist="norm", plot=plt)
plt.show()

在这里插入图片描述

# 残差正态性检验

from scipy.stats import kstest    # K-S检验:特点是比较严格,基于的原理是CDF,理论上可以检验任何分布
ks_result = kstest(model.resid,'norm')
print('kstest检验:',ks_result)
 
from scipy.stats import shapiro   # Shapiro检验:专门用来检验正态分布  shapiro 不适合做样本数>5000的正态性检验,检验结果的P值可能不准确
shap_result = shapiro(model.resid)
print('shapiro检验:',shap_result)

from scipy.stats import normaltest  # Normal检验:原理是基于数据的skewness和kurtosis
norm_result = normaltest(model.resid,axis=None)
print('normaltest检验:',norm_result)

kstest检验: KstestResult(statistic=0.5714285714285714, pvalue=7.456196123263218e-05)
shapiro检验: (0.9852579236030579, 0.9947238564491272)
normaltest检验: NormaltestResult(statistic=0.3540289636912072, pvalue=0.8377676520133555)

# 定量判断 残差同方差检验
# White's Test
white_test = sm.stats.diagnostic.het_white(model.resid, exog = model.model.exog)

print('模型方差齐性检验统计量:%.2f,P值:%.4f,Fvalue:%.2f,F_pvalue:%.2f:' %(white_test))
# model.model.exog

模型方差齐性检验统计量:6.77,P值:0.6608,Fvalue:0.42,F_pvalue:0.87

print('评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):%.3f'
      %(mean_absolute_per_err(Y_p,Y)))

长度: 14
评价模型标准-相对误差绝对值平均MAPE (Mean Absolute Percentage Error):0.031

五、分析函数化Codes

import pandas as pd
import numpy as np
import scipy
import  matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns
import statsmodels.api as sm # 最小二乘
from statsmodels.stats.outliers_influence import summary_table # 获得汇总信息
import statsmodels.formula.api as smf

from scipy import stats
from sklearn.metrics import mean_absolute_error

from statsmodels.tsa.stattools import adfuller   # ADF检验
from statsmodels.tsa.stattools import coint     # 协整检验
from statsmodels.tsa.stattools import grangercausalitytests  # 格兰杰因果关系检验

import warnings
warnings.filterwarnings("ignore")# 忽略静态警告

mpl.style.use('seaborn')

# 为了画图中文可以正常显示
plt.rcParams['font.sans-serif'] = ['simhei'] #指定默认字体
plt.rcParams['axes.unicode_minus'] = False  #解决保存图像时负号'-'显示为方块的问题

###########   函数定义  区域  ###############################################

def industry_boxplot_mu(data,title_name,sub_ylabel):
    '''
    title_name: boxplot的title 
    '''
    fig = plt.figure(figsize=(100,60))
    plt.title(title_name,fontsize=56)
    for i in range(1,len(names)):
        ax = fig.add_subplot(2,8,i)
#         ax.boxplot(industry_gdp_data[names[i]],
        ax.boxplot(data[names[i]],
                   patch_artist=True, # 要求用自定义颜色填充盒形图,默认白色填充
                   showmeans=True, # 以点的形式显示均值
                   boxprops = {'color':'black','facecolor':'#ffffff','linewidth':3}, # 设置箱体属性,填充色和边框色
                   flierprops = {'marker':'o','markerfacecolor':'red','color':'black','linestyle':'-','linewidth':3}, # 设置异常值属性,点的形状、填充色和边框色
                   meanprops = {'marker':'D','markerfacecolor':'indianred','linewidth':15}, # 设置均值点的属性,点的形状、填充色
                   medianprops = {'linestyle':'-','color':'red','linewidth':3}) # 设置中位数线的属性,线的类型和颜色
        # plt.title(names[i],fontsize=56)
        plt.xlabel(names[i],fontsize=48)
        # plt.ylabel(names[i]+'GDP',fontsize=48)
        plt.ylabel(names[i]+sub_ylabel,fontsize=48)
        plt.xticks(fontsize=48)
        plt.yticks(fontsize=48)
    plt.show()

'''
可视化行业的历年GDP、历年投资额,以及投资额和GDP的散点图
'''
def gdp_fac_graph_mu(ytrain,xtrain):
    '''
    ytrain:行业GDP数据
    xtrain:行业投资额数据
    '''
#     industry_GDP = industry_gdp_data[industry_name]
#     industry_FAC = industry_fac_data[industry_name]

    # 画图
    figure = plt.figure(figsize=(20,5))
    ax = figure.add_subplot(121)
    ax.plot(xtrain.index,xtrain,'rp-',label='投资额')
    ax.set_ylabel('投资额')
    ax.set_xlabel('年份')
    ax.legend(loc=0)
    
    ax = ax.twinx()
    ax.plot(ytrain.index,ytrain,'*-',label='GDP')
    ax.set_ylabel('GDP')
    # ax.set_xlabel('年份')
    ax.legend(loc=1)
    ax.set_title('时间序列图',fontsize=14)
    plt.xticks(fontsize=12)
    plt.yticks(fontsize=12)


    ax2 = figure.add_subplot(122)
    ax2.scatter(xtrain,ytrain,s=50)
    plt.title('投资额与GDP关系散点图',fontsize=14)
    plt.xlabel('投资额',fontsize=12)
    plt.ylabel('GDP',fontsize=12)
    plt.xticks(fontsize=12)
    plt.yticks(fontsize=12)
    
    plt.show()
    
'''
对各行业的投资额和GDP,进行一元回归建模
'''
def simple_regression_mu(ytrain,xtrain):
    '''
    params
    ytrain:行业GDP数据
    xtrain:行业投资额数据
    
    return 
    model: 拟合的回归模型
    '''
#     industry_GDP = industry_gdp_data[industry_name]
#     industry_FAC = industry_fac_data[industry_name]
    
    xtrain = sm.add_constant(xtrain) # 线性回归增加常数项 y=kx+b

    model = sm.OLS(ytrain, xtrain) # 普通最小二乘模型,ordinary least square model
    model = model.fit()    #res.model.endog
    # 模型检验及系数检验
#     print(industry_name+" 的回归模型检验及系数检验结果:\n",model.summary())
    y_pre = model.predict(xtrain)
    return model,y_pre

# '''
# 对各行业的投资额和GDP取自然对数后,进行一元回归建模
# '''
# def simple_regression_log_mu(ytrain,xtrain):
#     '''
#     params
#     ytrain:行业GDP数据
#     xtrain:行业投资额数据
    
#     return 
#     model: 拟合的回归模型
#     '''
#     industry_GDP = np.log(industry_gdp_data[industry_name])
#     industry_FAC = np.log(industry_fac_data[industry_name])
    
#     industry_FAC = sm.add_constant(industry_FAC) # 线性回归增加常数项 y=kx+b

#     model = sm.OLS(industry_GDP, industry_FAC) # 普通最小二乘模型,ordinary least square model
#     model = model.fit()    #res.model.endog
#     # 模型检验及系数检验
# #     print(industry_name+" 取自然对数后,回归模型检验及系数检验结果:\n",model.summary())
#     return model,industry_FAC

'''
回归结果可视化
'''
def visual_regression_result(xtrain,ytrain,y_pre):
    '''
    xtrain: 训练数据x
    ytrain:训练数据y
    y_pre:训练预测值
    '''
#     ytest =model.predict(xtrain)

    #绘制拟合结果和误差图
    figure = plt.figure(figsize=(10,5))
    plt.scatter(xtrain,ytrain,marker = 'd',color = 'k',label='原始值')
    plt.scatter(xtrain,y_pre,marker = 'p',color = 'g',label='预测值')

    plt.plot(xtrain,y_pre,color = 'r',label='预测线')
    plt.plot([xtrain,xtrain],[ytrain,y_pre] ,color = 'grey')
    plt.legend(fontsize = 14)
    plt.xticks(fontsize=12)
    plt.yticks(fontsize=12)
    plt.xlabel("序列",fontsize=12)
    plt.ylabel(industry_name+"GDP",fontsize=12)
    plt.title(industry_name+'线性回归拟合',fontsize=16)
    plt.show()

    
#     '''
# 回归结果可视化
# '''
# def visual_regression_result(xtrain,ytrain,y_pre):
#     '''
#     xtrain: 训练数据x
#     ytrain:训练数据y
#     y_pre:训练预测值
#     '''
# #     ytest =model.predict(xtrain)

#     #绘制拟合结果和误差图
#     figure = plt.figure(figsize=(12,7))
#     plt.scatter(xtrain,ytrain,marker = 'd',color = 'k',label='原始值')
#     plt.scatter(xtrain,y_pre,marker = 'p',color = 'g',label='预测值')

#     plt.plot(xtrain,y_pre,color = 'r',label='预测线')
#     plt.plot([xtrain,xtrain],[ytrain,y_pre],
#              color = 'grey')
#     plt.legend(fontsize = 14)
#     plt.xticks(fontsize=12)
#     plt.yticks(fontsize=12)
#     plt.xlabel(industry_name+"投资额",fontsize=12)
#     plt.ylabel(industry_name+"GDP",fontsize=12)
#     plt.title(industry_name+'线性回归拟合',fontsize=16)
#     plt.show()
'''
可视化回归后的残差散点图
'''
# def residual_scatter_mu(industry_name,model):
def residual_scatter_mu(model):
    '''
    industry_name:str,行业名称
    model: 拟合的模型
    '''
    # 残差均值  0
    err_mean = np.mean(model.resid)
    # 残差标准差
    err_std = np.std(model.resid)

    # 残差图
    figure = plt.figure(figsize=(20,5))
    ax = figure.add_subplot(121)
    plt.scatter(model.resid.index,model.resid,marker='d',color='k')
    plt.plot(model.resid.index,model.resid)
    plt.axhline(err_std)
    plt.axhline(-err_std)
    plt.axhline(0,color='r')
    
    plt.xlabel("年份",fontsize=12)
    plt.ylabel("残差",fontsize=12)
    plt.title(industry_name+"残差序列图",fontsize=14)
    
    ax2 = figure.add_subplot(122)
    plt.scatter(model.resid[:len(model.resid)-1],model.resid[1:len(model.resid)])
    plt.xlabel("滞后残差",fontsize=12)
    plt.ylabel("残差",fontsize=12)
    plt.title("一阶滞后变量的散点图",fontsize=14)
#     ax2 = figure.add_subplot(122)
#     plt.scatter(industry_gdp_data[industry_name],model.resid)
#     plt.axhline(err_std)
#     plt.axhline(-err_std)
#     plt.xlabel(industry_name+"GDP",fontsize=12)
#     plt.ylabel("残差",fontsize=12)
#     plt.title(industry_name+"残差散点图",fontsize=14)
    plt.show()


'''
相对误差绝对值平均
'''
def mean_absolute_per_err(y_pre,y): 
    '''
    y_pre:预测值
    y: 原始数据
    '''
    result = 0
    for i in range(len(y_pre)):
        result = result + np.abs((y_pre[i]-y[i])/y[i])
    result = result/len(y_pre)
    print('长度:',len(y_pre))
    return result

'''adfuller()返回值
df : float
    Test statistic
pvalue : float
    MacKinnon's approximate p-value based on MacKinnon (1994, 2010)
usedlag : int
    Number of lags used
nobs : int
    Number of observations used for the ADF regression and calculation of
    the critical values
critical values : dict
    Critical values for the test statistic at the 1 %, 5 %, and 10 %
    levels. Based on MacKinnon (2010)
'''
def diff_adf_test(data,max_jieshu=3,zhixindu='5%'):
    '''
    data:检验序列
    max_jieshu:差分的最高阶数
    '''
    adf_result = adfuller(data)
    if adf_result[0] < adf_result[4]['10%']:  # 平稳性判断
        print('原序列平稳,统计量为:%.4f ,p值为%.4f, %s临界值为:%.4f'%(adf_result[0],adf_result[1],zhixindu,adf_result[4][zhixindu]))
        return data
    for i in range(1,max_jieshu+1):
        temp = data.diff(i)[i:]
        adf_result = adfuller(temp)
        if adf_result[0] < adf_result[4]['10%']:  # 平稳性判断
            print('序列%d阶平稳,统计量为:%.4f ,p值为%.4f, %s临界值为:%.4f'%(i,adf_result[0],adf_result[1],zhixindu,adf_result[4][zhixindu]))
            return temp
    print('原序列在差分%d阶以内,均不平稳'%max_jieshu)
    
########################################################################

六、题外话

这部分的分析工作用了很长时间,也查看过一些资料,当真正准备把它当一个分析报告想展示的时候,自己突然发现不知道该展示什么,或者说要来说明什么问题。这也是自己第一次尝试分享展示这种分析案例,有很多粗糙的地方和不足,多多练手,多多参考大家的作品,提升自己的实力,并希望能够不断的分享新的有帮助的内容给阅读者。


  1. 北京市统计局 ↩︎

  2. Python做假设检验 ↩︎

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

积跬步,慕至千里

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值