Python数据分析与应用----财政收入预测分析、实训(企业所得税预测)
本案例按照1994年我国财政体制改革后至2013年的数据进行分析并预测未来两年财政收入变化情况。主要按照财政收入分析预测模型流程进行~
目录:
财政收入预测分析
一、对原始数据进行探索性分析,了解原始特征之间的相关性
二、利用Lasso特征选择模型进行特征提取
三、建立单个特征的灰色预测模型以及支持向量回归预测模型
四、使用支持向量回归预测2014-2015的财政收入
一、对原始数据进行探索性分析,了解原始特征之间的相关性
特征名 | 说明 |
---|---|
x1 | 社会从业人数 |
x2 | 在岗职工工资总额 |
x3 | 社会消费品零售总额 |
x4 | 城镇居民人均可支配收入 |
x5 | 城镇居民人均消费性支出 |
x6 | 年末总人口 |
x7 | 全社会固定资产投资额 |
x8 | 地区生产总值 |
x9 | 第一产业产值 |
x10 | 税收 |
x11 | 居民消费价格指数 |
x12 | 第三产业与第二产业产值比 |
x13 | 居民消费水平 |
y | 财政收入 |
相关性分析是指对两个或多个具备相关型的特征元素进行分析,从而衡量两个特征因素的相关密切程度。在统计学中,常用到Pearson相关系数来进行相关性分析。Pearson相关系数可用来度量两个特征间的相互关系(线性相关强弱),是最简单的一种相关系数,常用r或ρ来表示,取值范围在[-1,1].
当 r=1 时,表示x与y完全正相关;
当 0<r<1时,表示x与y呈现正相关;
当 r=0 时,表示x与y不相关;
当 -1<r<0时,表示x与y呈现负相关;
当 r=-1 时,表示x与y完全负相关;
|r| 越接近于 1 ,表示x与y的差距越小,相关性越大。
Pearson相关系数的一个关键特性就是,他不会随着特征的位置会是大小变化而变化。
DataFrame.corr(method='pearson', min_periods=1)
参数说明:
method:可选值为{‘pearson’, ‘kendall’, ‘spearman’}
pearson:Pearson相关系数来衡量两个数据集合是否在一条线上面,即针对线性数据的相关系数计算,针对非线性数据便会有误差。
kendall:用于反映分类变量相关性的指标,即针对无序序列的相关系数,非正太分布的数据
spearman:非线性的,非正太分析的数据的相关系数
min_periods:样本最少的数据量
import pandas as pd
import numpy as np
# 读取数据
data = pd.read_csv('data/data.csv',encoding='gbk')
print(data.shape)
//(20, 14)
#计算各特征之间的pearson相关系数
p_data = data.corr(method='pearson')
print('各特征之间的pearson相关系数的形状为:\n',p_data.shape)
//各特征之间的pearson相关系数的形状为:
// (14, 14)
#保留两位小数
p_data = np.round(p_data,2)
print('各特征之间的pearson相关系数为:\n',p_data)
从表中不难看出,除了x11(居民消费价格指数)外,其余特征均与y(财政收入呈现高度的正相关关系);同时,各特征之间存在着严重的多重共线性,甚至是完全的共线性。综上,可以利用相关性高的特征作为财政收入预测的关键特征进行分析。
二、利用Lasso特征选择模型进行特征提取
数据探索性分析时引入的特征太多,要直接利用其建模,需要进一步的筛选特征,在这里我们采用最近广泛使用的Lasso特征选择方法进一步筛选特征。
Lasso回归方法
概念:
Lasso回归方法属于正则化方法的一种,是压缩估计通过构造一个惩罚函数得到一个较为精炼的模型。使用它压缩一些系数,同时设定一些系数为0,保留了子集收缩的有点,是一种处理具有复共线性数据的有偏估计。(有偏估计(biased estimate)是指由样本值求得的估计值与待估参数的真值之间有系统误差,其期望值不是待估参数的真值。)
基本原理:
Lasso以缩小特征集(降阶)为思想,是一种收缩估计方法。Lasso方法可以将特征系数进行压缩并使得某些回归系数变为0,进而达到特征选择的目的,可以应用于模型改进与选择—通过选择惩罚函数,借用Lasso思想和方法实现特征选择;模型选择本质上是寻求模型系数表达的过程,可以通过优化一个“损失”+“惩罚”的函数问题来完成。
适用场景:
当原始数据中存在多重共线性时,Lasso回归是个不错的选择。在机器学习中,面对众多的数据,首先想到的就是降维,从某个意义上说,Lasso模型进行特征选择也是一种有效的降维方式。一般来说,Lasso对数据类型没有太大的要求,可以接受任何数据类型,并且一般不需对特征进行标准化。优点与缺点:
Lasso回归方法可以弥补最小二乘估计法和逐步回归局部最优估计的不足,能很好地选择特征,有效的解决特征之间存在的多重共线性问题。
缺点是当存在一组高度相关的特征三,Lasso回归方法会选择其中一个,而忽视其他所有的特征,可能会导致结果的不稳定。
语法:Lasso(alpha=1.0, fit_intercept=True, normalize=False, precompute=False, copy_X=True, max_iter=1000, tol=0.0001, warm_start=False, positive=False, random_state=None, selection=‘cyclic’)
• alphas: 指定λ\lambdaλ值,默认为1。
• fit_intercept:bool类型,是否需要拟合截距项,默认为True。
• normalize: bool类型,建模时是否对数据集做标准化处理,默认为False。
• precompute: bool类型,是否在建模前计算Gram矩阵提升运算速度,默认为False。
•copy_X: bool类型,是否复制自变量X的数值,默认为True。
• max_iter: 指定模型的最大迭代次数。
•tol: 指定模型收敛的阈值,默认为0.0001。
•warm_start: bool类型,是否将前一次训练结果用作后一次的训练,默认为False。
•positive: bool类型,是否将回归系数强制为正数,默认为False。
• random_state: 指定随机生成器的种子。
•selection: 指定每次迭代选择的回归系数,如果为’random’,表示每次迭代中将随机更新回归系数;如果为’cyclic’,则每次迭代时回归系数的更新都基于上一次运算。
import pandas as pd
import numpy as np
from sklearn.linear_model import Lasso
# 读取数据
data = pd.read_csv('data/data.csv')
# 使用lasso回归方法进行关键特征的选取
lasso = Lasso(1000,random_state=1234)
lasso.fit(data.iloc[:,0:13],data['y']) 这里主要是选取与财政收入相关的特征
print('相关系数为:',np.round(lasso.coef_,5))
//相关系数为:
[-1.8000e-04 -0.0000e+00 1.2414e-01 -1.0310e-02 6.5400e-02 1.2000e-04
3.1741e-01 3.4900e-02 -0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00
-4.0300e-02]
# 计算相关系数非0的个数
print('相关系数非零的个数为:',np.sum(lasso.coef_!=0))
//相关系数非零的个数为: 8
# 返回一个相关系数是否为0的布尔数组
mask = lasso.coef_!=0
print('相关系数是否为0:',mask)
//相关系数是否为0:
[ True False True True True True True True False False False False
True]
mask = np.append(mask,True)
new_reg_data = data.iloc[:,mask]
#new_reg_data.to_csv('tmp/new_reg_data.csv')
print('输出的数据维度为:',new_reg_data.shape)
//输出的数据维度为: (20, 9)
np.round(lasso.coef_,5) #返回参数向量,保留5位小数
这里要注意的是下面代码:
mask = np.append(mask,True)
new_reg_data = data.iloc[:,mask]
在一开始没有加上一行时会报错,原因是你的得到的mask返回值是除了财政收入(y)的,共计13个,而原始数据data共有14列,会导致列数不对应,所以这里要用append方法加一个,true或false,两个值会影响得出的数据中是否包含有y列,由于后续操作需要其保留y列,此处应为True。当然是用False也并不错。只是后续操作时要将y列数据提取并添加至表格中,注意看后面代码注释部分。
三、建立单个特征的灰色预测模型
基于灰色预测对小样本数据集的优良性能,首先对单个特征建立灰色预测模型,得到各特征2014-2015年的预测值。然后对2013年以前的训练数据建立支持向量回归预测模型,将建立好的模型与灰色预测模型结合,对2014和2015年的财政收入进行预测。
灰色预测法:
概念:
灰色预测法是一种对含有不确定性因素的系统进行预测的方法。在建立灰色预测模型之前,需要对原始时间序列进行处理,经过处理的时间序列称为生成列。灰色系统常用的处理数据方式有累加和累减两种。基本原理:
检验参照:
适用场景:
灰色预测法的通用性比较强,一般时间序列场合都可以使用,尤其那些规律性差且不清楚数据产生机理的情况。优点与缺点:
优点是预测精度高,模型可检验,参数估计方法简单,对小数据集有较好的效果 缺点是对原始数据序列的光滑度要求很高
import pandas as pd
import numpy as np
# 引入自编的灰色预测函数
def GM11(x0): #自定义灰色预测函数
x1 = x0.cumsum() #1-AGO序列
z1 = (x1[:len(x1)-1] + x1[1:])/2.0 #紧邻均值(MEAN)生成序列
z1 = z1.reshape((len(z1),1))
B = np.append(-z1, np.ones_like(z1), axis = 1)
Yn = x0[1:].reshape((len(x0)-1, 1))
[[a],[b]] = np.dot(np.dot(np.linalg.inv(np.dot(B.T, B)), B.T), Yn) #计算参数
f = lambda k: (x0[0]-b/a)*np.exp(-a*(k-1))-(x0[0]-b/a)*np.exp(-a*(k-2)) #还原值
delta = np.abs(x0 - np.array([f(i) for i in range(1,len(x0)+1)]))
C = delta.std()/x0.std()
P = 1.0*(np.abs(delta - delta.mean()) < 0.6745*x0.std()).sum()/len(x0)
return f, a, b, x0[0], C, P #返回灰色预测函数、a、b、首项、方差比、小残差概率
# 读取数据
data = pd.read_csv('data/data.csv',encoding='gbk')
new_reg_data = pd.read_csv('tmp/new_reg_data1.csv')
# 自定义提取特征后数据的索引
new_reg_data.index = range(1994,2014)
# print(new_reg_data.index)
new_reg_data.loc[2014] = None
new_reg_data.loc[2015] = None
l = ['x1','x3','x4','x5','x6','x7','x8','x13']
for i in l:
f = GM11(new_reg_data.loc[range(1994,2014),i].as_matrix())[0]
new_reg_data.loc[2014,i] = f(len(new_reg_data)-1)
new_reg_data.loc[2015,i] = f(len(new_reg_data))
new_reg_data[i] = new_reg_data[i].round(2) # 保留2位小数
//以下几行可以不用,因为之前在Lasso回归时,我们使用mask添加了TRUE,保留了y列
//y = list(data['y'].values) # 提取财政收入列,合并至新数据框内
//y.extend([np.nan,np.nan])
//new_reg_data['y '] = y
new_reg_data.to_excel('tmp/new_reg_data_GM11.xls')
print('预测结果为:\n',new_reg_data.loc[2014:2015,:])
//预测结果为:
Unnamed: 0 x1 x3 x4 x5 x6 \
2014 NaN 8142148.24 7042.31 43611.84 35046.63 8505522.58
2015 NaN 8460489.28 8166.92 47792.22 38384.22 8627139.31
x7 x8 x13 y
2014 4600.40 18686.28 44506.47 NaN
2015 5214.78 21474.47 49945.88 NaN
这里使用灰色预测算法采用遍历并对各个特征进行2014和2015年的预测:
首先添加行数并设定索引为年份
# 自定义提取特征后数据的索引
new_reg_data.index = range(1994,2014)
# print(new_reg_data.index)
new_reg_data.loc[2014] = None
new_reg_data.loc[2015] = None
其次,当i=l[i],进入对应列从1994-2013遍历,然后根据1994-2013年的数据预测出2014和2015年的值并将其保存至数据表中。
l = ['x1','x3','x4','x5','x6','x7','x8','x13']
for i in l:
f = GM11(new_reg_data.loc[range(1994,2014),i].as_matrix())[0]
print('i:',i)
print(new_reg_data.loc[range(1994,2014),i])
new_reg_data.loc[2014,i] = f(len(new_reg_data)-1)
print(new_reg_data.loc[2014,i])
new_reg_data.loc[2015,i] = f(len(new_reg_data))
print(new_reg_data.loc[2015,i])
new_reg_data[i] = new_reg_data[i].round(2) # 保留2位小数
print("*"*50)
四、支持向量回归预测模型及其使用—预测2014-2015的财政收入
SVR算法:
基本原理:
方法及主要参数:
优点与缺点:
相比于其他方法,支持向量回归的优点是不仅支持适用于线性模型,对于数据和特征之间的非线性关系也能很好抓住;不需要担心多重共线性问题,可以避免局部极小化问题,提高泛化性能,解决高维问题;虽然不会再过程中排出异常点,但是会使得由异常点引起的偏差更小。
缺点是计算复杂程度高,面临大量数据时,计算耗时长。
import pandas as pd
import numpy as np
from sklearn.svm import LinearSVR
import matplotlib.pyplot as plt
from sklearn.metrics import explained_variance_score,mean_absolute_error,mean_squared_error,median_absolute_error,r2_score
data = pd.read_excel('tmp/new_reg_data_GM11.xls',index_col=0) //读取文件是设定第一列为索引,否则默认为0开始,后面会报错找不到索引
feature = ['x1','x3','x4','x5','x6','x7','x8','x13']
print(data.index)
# 取2014年之前的数据建模
data_train = data.loc[range(1994,2014)].copy()
data_std = data_train.std() # 取标准差
data_mean = data_train.mean() # 取平均值
data_train = (data_train - data_mean)/data_std # 数据标准化
print(data_train.columns)
//Index(['Unnamed: 0.1', 'x1', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x13', 'y '], dtype='object')
x_train = data_train[feature].as_matrix() # 特征数据
y_train = data_train['y'].as_matrix() # 标签数据
linearsvr = LinearSVR().fit(x_train,y_train)
x = ((data[feature]-data_mean[feature])/data_std[feature]).as_matrix() #预测,并还原结果
data[u'y_pred'] = linearsvr.predict(x)*data_std['y'] + data_mean['y']
#SVR预测后保存的结果
#data.to_excel('tmp/new_reg_data_GM11_revenue.xls')
print('真实值与预测值分别为:\n',data[['y','y_pred']])
print('预测图为:',data[['y','y_pred']].plot(subplots = True,
style=['b-o','r-*']))
首先选取数据并对其标准差标准化,这里使用了copy(),copy()方法会创建一个新的数组对象,而不是建立一个对原数组的索引。简单地说,就是原数组和新数组没有任何关系,任何对新数组的改变都不会影响到原数组,这样一来保证了原始数据的完整性,可以多次操作。
值得一提的是,这里是按照书上的代码,在现行的版本中.as_matrix()已经不用了,改成.values就可以。还有就是使用pycharm运行时正常,但使用jupyter打开运行时,在读取data_train[‘y’]这里会出现keyError。本人的解决方法是在同一个文件中执行,数据就用上面的:
# 取2014年之前的数据建模
data_train = data.loc[range(1994,2014)].copy()
data_std = data_train.std() # 取标准差
data_mean = data_train.mean() # 取平均值
data_train = (data_train - data_mean)/data_std # 数据标准化
print(data_train.columns)
//Index(['Unnamed: 0.1', 'x1', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x13', 'y '], dtype='object')
x_train = data_train[feature].as_matrix() # 特征数据
y_train = data_train['y'].as_matrix() # 标签数据
接着构建LinearSVR线性支持向量回归模型,将灰色预测法预测的数据代入进行预测,得到2014和2015年的财政收入的预测值。
linearsvr = LinearSVR().fit(x_train,y_train)
//标准差标准化灰色预测值
x = ((data[feature]-data_mean[feature])/data_std[feature]).as_matrix() #预测,并还原结果
data[u'y_pred'] = linearsvr.predict(x) * data_std['y'] + data_mean['y']
ConvergenceWarning说明我们设置的迭代次数不够,参数未收敛,通过设置合理的max_iter属性,可以使模型收敛.
实训(企业所得税预测)
通过上面的学习,我们了解了一般财政收入的预测流程,接下来按照上述流程,实现对某企业2016和2017年的企业所得税预测。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 求解Pearson相关系数
data = pd.read_csv('data/income_tax.csv')
print('相关系数矩阵为:\n',np.round(data.corr(method='pearson'),2))
# 使用Lasso回归选取特征
from sklearn.linear_model import Lasso
# 构建Lasso训练数据
lasso = Lasso(1000,random_state=123).fit(data.iloc[:,1:11],data['y'])
print('相关系数为:\n',np.round(lasso.coef_,5)) # 保留5位小数
//相关系数为:
// [ 6.38000000e-03 -3.89000000e-03 5.48000000e-03 4.39088192e+03
// 1.23900000e-02 -5.45124664e+03 -4.00000000e-05 -1.60000000e-02
// 3.75000000e-03 7.60000000e-04]
# 计算相关系数大于0的个数
print('相关系数大于0的有:',np.sum(lasso.coef_>0))
//相关系数大于0的有: 6
mask = lasso.coef_>0
print('lasso.coef_是否大于0:\n',mask)
mask=np.insert(mask,0,[False]) #第一列为年份,在读入新表格的时候要排除
print(mask)
mask = np.append(mask,True)
print(mask)
new_reg_data = data.iloc[:,mask]
#new_reg_data.to_csv('tmp/new_reg_data1.csv')
print(new_reg_data)
mask = lasso.coef_>0
print('lasso.coef_是否大于0:\n',mask)
mask=np.insert(mask,0,[False]) //第一列为年份,False表示在读入新表格的时候要排除,但是此处必须得写
print(mask)
mask = np.append(mask,True) //保留y列
print(mask)
以上代码与前面案例有所不同,这里经过Lasso回归后的数据仅有正负之分,我们利用为正数的特征进行操作。并且在选择特征提取时,要注意添加第一列为False
。如果我们直接按照之前的做,会发现报错:new_reg_data = data.iloc[:,mask] 当下的数目与原数据数目不匹配!
。之前不用加是因为得到的Lasso回归系数为0列+y列=表格总列数
,而现在得到的Lasso回归系数大于0列+y列!=表格总列数(少了第一列年份的布尔值)
。
# 引入自编的灰色预测函数
def GM11(x0): #自定义灰色预测函数
import numpy as np
x1 = x0.cumsum() #1-AGO序列
z1 = (x1[:len(x1)-1] + x1[1:])/2.0 #紧邻均值(MEAN)生成序列
z1 = z1.reshape((len(z1),1))
B = np.append(-z1, np.ones_like(z1), axis = 1)
Yn = x0[1:].reshape((len(x0)-1, 1))
[[a],[b]] = np.dot(np.dot(np.linalg.inv(np.dot(B.T, B)), B.T), Yn) #计算参数
f = lambda k: (x0[0]-b/a)*np.exp(-a*(k-1))-(x0[0]-b/a)*np.exp(-a*(k-2)) #还原值
delta = np.abs(x0 - np.array([f(i) for i in range(1,len(x0)+1)]))
C = delta.std()/x0.std()
P = 1.0*(np.abs(delta - delta.mean()) < 0.6745*x0.std()).sum()/len(x0)
return f, a, b, x0[0], C, P #返回灰色预测函数、a、b、首项、方差比、小残差概率
# 设置索引为年份
new_reg_data.index = range(2004,2016)
print(new_reg_data)
# 添加2016、2017行
new_reg_data.loc[2016] = None
new_reg_data.loc[2017] = None
print(new_reg_data)
# 设定遍历对象为列名
l = ['x1', 'x3', 'x4', 'x5', 'x9', 'x10']
# 遍历特征使用灰色预测法预测2016、2017
for i in l:
f = GM11(new_reg_data.loc[range(2004,2016),i].values)[0]
new_reg_data.loc[2016,i] = f(len(new_reg_data)-1)
new_reg_data.loc[2017,i] = f(len(new_reg_data))
new_reg_data[i] = new_reg_data[i].round(2)
print(new_reg_data)
#new_reg_data.to_excel('tmp/new_reg_data_GM11_1.xls')
# 构建支持向量回归预测模型
from sklearn.svm import LinearSVR
feature = ['x1', 'x3', 'x4', 'x5', 'x9', 'x10']
// 提取2015年之前的数据建模
data_train = new_reg_data.loc[range(2004,2016)].copy()
data_mean = data_train.mean()
data_std = data_train.std()
// 数据标准差标准化
data_train = (data_train - data_mean)/data_std
x_train = data_train[feature].values //特征数据
y_train = data_train['y'].values //y标签数据
// 调用LinearSVR函数
linearsvr = LinearSVR()
linearsvr.fit(x_train,y_train)
x = ((new_reg_data[feature]-data_mean[feature])/data_std[feature]).values
//print(len(x))
//print(len(new_reg_data))
new_reg_data[u'y_pred'] = linearsvr.predict(x)*data_std['y'] + data_mean['y']
//SVR预测后保存的结果
new_reg_data.to_excel('tmp/new_reg_data_GM11_revenue_1.xls')
print('真实值与预测值分别为:\n',new_reg_data[['y','y_pred']])
print('预测图为:',new_reg_data[['y','y_pred']].plot(subplots = True,
style=['b-o','r-*']))
本文相关源码下载:https://download.csdn.net/download/qq_45797116/74467274