金融商业算法建模:基于Python和SAS
上QQ阅读APP看书,第一时间看更新

2.1.2 Python案例:线性回归建模

本节就如何使用线性回归模型预测客户价值进行举例。信用卡部门拥有的客户个人信息和信用卡支出信息存放在creditcard_exp.csv表中,目前尚有一些客户注册后没有开卡,部门业务人员希望能够预测其开卡后的消费情况,同时用于推断的样本外数据存放在creditcard_exp_out_of_sample.csv中。数据集的字段如表2-1所示。

表2-1 信用卡客户价值预测数据集字段说明

creditcard_exp.csv保存了上一期的数据,Acc、avg_exp、avg_exp_ln为观察期内得到的结果,可以作为分析中的因变量,剩余字段为分析窗口(观察期之前)的自变量取值。

creditcard_exp_out_of_sample.csv保存了本期分析窗口内的自变量,其因变量需要通过模型输出。

本数据集可用于预测观察期内用户是否会开卡,并预测用户开卡后的信用卡支出(客户价值的体现)。

1.数据探索

引入常用的包,为了方便学习,后续根据需要逐步引入其他包:


import matplotlib.pyplot as plt
%matplotlib inline
import os
import numpy as np
import pandas as pd

pd.set_option('display.max_columns', 8)

因为数据显示的问题,使用pd.set_option限制Pandas显示数据表的列数为8列,然后读取用于训练的数据和样本外的待预测数据:


raw_data = pd.read_csv('creditcard_exp.csv', skipinitialspace=True)
out_of_sample_data = pd.read_csv('creditcard_exp_out_of_sample.csv', skipinitial-
space=True)
raw_data.head()

使用Jupyter Notebook时,每个Cell的最后一行的对象会被自动打印出来,并根据对象类型在输出结果上进行一些优化,而无须使用print语句进行打印。因此,上述代码运行后会输出一个可读性较好的pandas.DataFrame对象,如图2-5所示。

图2-5 pandas.DataFrame对象

其中,Acc为0,表示用户未开卡,所对应的avg_exp和avg_exp_ln(月均信用卡支出及其对数值)为空值NaN。对应的样本外数据out_of_sample_data是当前的观察期数据,缺少Acc和avg_exp等字段,是需要我们预测的。

在raw_data中删除未开卡用户,同时因为age2(age的平方)与age是接近完全线性相关的,所以删除age2字段,然后对数据进行统计量的描述:


train = raw_data[raw_data['avg_exp'].notnull()].copy().iloc[:, 2:]\
    .drop('age2',axis=1)
oos_data = out_of_sample_data.copy()\
    .drop('age2',axis=1)
train.describe(include='all')

本数据集样本容量为70,各变量的均值、中位数等统计量如图2-6所示。

图2-6 运行结果

几个主要的连续变量的相关性计算如下:


train[['Income', 'avg_exp', 'Age', 'dist_home_val']].corr(method='pearson')

得到的pandas.DataFrame对象结果如图2-7所示。

图2-7 pandas.DataFrame对象

可以发现,avg_exp与Income的相关性较高。二者的散点图如图2-8所示,相关性计算代码如下:


fig, ax = plt.subplots(figsize=(8, 6))
ax.set_ylabel(..., fontsize=15)
ax.set_xlabel(..., fontsize=15)
train.plot('Income', 'avg_exp', kind='scatter', ax=ax)
plt.show()

图2-8 散点图

2.使用statsmodels建立简单线性回归模型

statsmodels是一个专业的用于统计分析的框架,包含丰富的统计建模和检验功能,使用它进行线性回归建模十分方便。


import statsmodels.api as sm
from statsmodels.formula.api import ols

simple_linear_model = ols(formula='avg_exp ~ Income', data=train).fit()
print(simple_linear_model.params)

输出模型参数的估计值如下:


Intercept      258.049498
Income            97.728578
dtype: float64

ols用于进行最小二乘求解,其中传入的formula参数是一个字符串,表示回归方程,波浪线前面的部分是因变量,后面部分表示自变量。建立的模型使用fit函数即可自行训练,训练完成的对象包含的params属性中保存了模型的参数估计。本例中,Income字段的系数为97.73,截距项为258.05,因此模型可表示为:

在建立多元线性回归时,仅需要在formula当中指定多个自变量即可,各个自变量使用加号连接:


multiple_linear_model = ols(
    formula='avg_exp ~Income + dist_home_val + dist_avg_income',
    data=train).fit()
print(multiple_linear_model.params)

输出的模型参数如下:


Intercept          2.350664
Income          -164.437844
dist_home_val      1.539601
dist_avg_income  260.752162
dtype: float64

该多元线性回归方程为:


avg_exp = 2.35 – 164.44×Income + 1.54×dist_home_val + 260.75×dist_avg_income

statsmodels提供了丰富的可对模型进行检验的统计量,要输出这些统计量和检验结果,仅需要调用模型的summary方法即可。以简单线性回归为例:


summary = simple_linear_model.summary()

3.summary

模型的summary对象包含两个属性:tables属性包含模型统计检验结果,extra_txt属性用于解释说明。其中,tables属性会给出一个列表,包括模型概况与检验、参数检验、其他检验,我们可以使用循环将这三个对象打印出来,在Jupyter Notebook中,仅需在Cell的最后一行将summary对象输出,即能自动打印(就如上述代码所示)。其输出结果如下:

我们在后续章节会逐步介绍这些统计检验结果。

4.模型的解释

线性回归模型具有良好的可解释性。对于简单线性回归来说,线性回归模型可直观地解释为:当X增加1个单位时,因变量Y会增加个单位。例如上述通过收入预测信用卡支出的案例中,我们可以认为当年收入增加1万元时,信用卡月均支出增加97.73元。

多元线性回归模型的解释与此类似,可被解释为:当控制其他自变量之后,选定的自变量变化会导致因变量产生固定比例的变化。例如上述多元线性回归案例中,当控制地区房价与地区平均收入这两个变量后,年收入每增加1万元,信用卡月均支出反而下降164.44元。这个结论是否可靠呢?一方面需要通过业务经验来判断,另一方面需要检验模型本身。关于模型优化,我们会在后续章节中详细说明。

另外,线性回归模型可以有多种形式,即在线性方程中对Y或X做任何简单的初等函数变换,我们仅需要将变换后的结果看作是一个新变量,最终形式仍然是线性回归,例如:

这几个方程对变量做了简单的初等函数变换,但它们仍然属于线性回归,其业务解释也与一般形式的模型类似。特别需要说明的是取对数后的方程,以因变量取对数为例,对于i和j两条记录,考虑到:

其中,可视作j相较于i增长的倍数,减1后相当于j相较于i增长的百分比。因此,我们可以认为当X增加1个单位时,Y会增加一个固定的倍数或百分比(具体来说是)。

类似地,对于X取对数的线性回归,可解释为:X增加固定的倍数或百分比,会导致Y增加固定的值;对于X和Y均取对数的线性回归,可解释为:当增加一个倍数或百分比,会导致增加一个固定的倍数和百分比,这在经济学中被称为Y相对X的弹性。

我们在案例中建立了信用卡支出的对数与收入的线性回归模型,并求解其参数:


Print(ols('avg_exp_ln ~ Income', train).fit().params)

结果如下:


Intercept    6.181076
Income        0.086557
dtype: float64

这说明当收入增加1万元时,信用卡支出会增长9.04%

再建立一个信用卡支出的对数与收入的对数的线性回归模型,并求解其参数:


train['Income_ln'] = np.log(train['Income'])

#样本外数据做同样变换
oos_data['Income_ln'] = np.log(oos_data['Income'])

print(ols('avg_exp_ln ~ Income_ln', train).fit().params)

结果如下:


Intercept    5.312341
Income_ln    0.780397
dtype: float64

这说明,当收入增加10%时,信用卡支出增加7.72%。显然,这个解释更符合业务直觉。(你能想象年入千万的富豪,因为收入增加了1万元,而导致信用卡支出增加97.73元,或者信用卡支出增加9.04%吗?)

从上例可以看到,取对数后的线性回归模型仍然具有良好的可解释性,这也是统计学家们偏爱对数变换的原因之一。

5.模型预测

模型预测是指仅需要将X的值代入回归方程即可获取Y的预测值。需要注意的是,如果在建模时对做了函数变换,那么预测后需要对结果做逆变换,以获取正确估计。仍然以最早建立的未做对数变换的模型为例:


print(simple_linear_model.predict(oos_data)[:5])

结果如下:


0          982.218260
1          749.624245
2          649.941095
3          631.372665
4          661.668525
dtype: float64

也可以在训练集上进行预测,并观察预测与真实值的残差:


train_prediction = simple_linear_model.predict(train)
train_resid = simple_linear_model.resid
pd.DataFrame(
    [train_predict, train_resid], 
    index=['Pred_avg_exp', 'resid']
).T.head()

结果如下: