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()
结果如下: