【菜菜的sklearn课堂笔记】逻辑回归与评分卡-用逻辑回归制作评分卡-异常值和样本不均衡处理

视频作者:菜菜TsaiTsai
链接:【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili

描述性统计处理异常值

现实数据永远都会有一些异常值,首先我们要去把他们捕捉出来,然后观察他们的性质。注意,我们并不是要排除掉所有异常值,相反很多时候,异常值是我们的重点研究对象,比如说,双十一中购买量超高的品牌,或课堂上让很多学生都兴奋的课题,这些是我们要重点研究观察的。
日常处理异常值,我们使用箱线图或者 3 σ 3\sigma 3σ法则来找到异常值。但在银行数据中,我们希望排除的“异常值”不是一些超高或超低的数字,而是一些不符合常理的数据:比如,收入不能为负数,但是一个超高水平的收入却是合理的,可以存在的。所以在银行业中,我们往往就使用普通的描述性统计来观察数据的异常与否与数据的分布情况。注意,这种方法只能在特征量有限的情况下进行,如果有几百个特征又无法成功降维或特征选择不管用,那还是用 3 σ 3\sigma 3σ比较好。

data.describe([0.01,0.1,0.25,0.5,0.75,0.9,0.99]).T

年龄的最小值居然有0,这不符合银行的业务需求,即便是儿童账户也要至少8岁,我们可以查看一下年龄为0的人有多少

(data['age'] == 0).sum()
---
1

发现只有一个人年龄为0,可以判断这肯定是录入失误造成的,可以当成是缺失值来处理,直接删除掉这个样本

data = data[data['age'] != 0]

另外,有三个指标看起来很奇怪:
“NumberOfTime30-59DaysPastDueNotWorse”
“NumberOfTime60-89DaysPastDueNotWorse”
“NumberOfTimes90DaysLate”
这三个指标分别是“过去两年内出现35-59天逾期但是没有发展的更坏的次数”,“过去两年内出现60-89天逾期但是没有发展的更坏的次数”,“过去两年内出现90天逾期的次数”。这三个指标,在99%的分布的时候依然是2,最大值却是98,看起来非常奇怪。一个人在过去两年内逾期35~59天98次,一年6个60天,两年内逾期98次这是怎么算出来的?
我们可以去咨询业务人员,请教他们这个逾期次数是如何计算的。如果这个指标是正常的,那这些两年内逾期了98次的客户,应该都是坏客户。在我们无法询问他们情况下,我们查看一下有多少个样本存在这种异常:

data[data.loc[:,'NumberOfTimes90DaysLate'] > 90].shape
---
(225, 11)

data.loc[:,'NumberOfTimes90DaysLate'].value_counts().sort_index()
# sort_index(),按索引排序,默认升序,设置ascending=False降序
---
0     141107
1       5232
2       1555
3        667
4        291
5        131
6         80
7         38
8         21
9         19
10         8
11         5
12         2
13         4
14         2
15         2
17         1
96         5
98       220
Name: NumberOfTimes90DaysLate, dtype: int64

set(data.loc[data.loc[:,'NumberOfTimes90DaysLate'] > 90,'SeriousDlqin2yrs'].values)
---
{0, 1}

有225个样本存在这样的情况,并且这些样本,我们观察一下,标签并不都是1,他们并不都是坏客户。因此,我们基本可以判断,这些样本是某种异常,应该把它们删除。

data = data[data.loc[:,'NumberOfTimes90DaysLate'] < 90]
data.index = range(data.shape[0])

data.info()
---
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 149165 entries, 0 to 149164
Data columns (total 11 columns):
SeriousDlqin2yrs                        149165 non-null int64
RevolvingUtilizationOfUnsecuredLines    149165 non-null float64
age                                     149165 non-null int64
NumberOfTime30-59DaysPastDueNotWorse    149165 non-null int64
DebtRatio                               149165 non-null float64
MonthlyIncome                           149165 non-null float64
NumberOfOpenCreditLinesAndLoans         149165 non-null int64
NumberOfTimes90DaysLate                 149165 non-null int64
NumberRealEstateLoansOrLines            149165 non-null int64
NumberOfTime60-89DaysPastDueNotWorse    149165 non-null int64
NumberOfDependents                      149165 non-null float64
dtypes: float64(4), int64(7)
memory usage: 12.5 MB

为什么不统一量纲,也不标准化数据分布?

在描述性统计结果中,我们可以观察到数据量纲明显不统一,而且存在一部分极偏的分布,虽然逻辑回归对于数据没有分布要求,但是我们知道如果数据服从正态分布的话梯度下降可以收敛得更快。但在这里,我们不对数据进行标准化处理,也不进行量纲统一
无论算法有什么样的规定,无论统计学中有什么样的要求**,我们的最终目的都是要为业务服务**。现在我们要制作评分卡,评分卡是要给业务人员们使用的基于新客户填写的各种信息为客户打分的一张卡片,而为了制作这张卡片,我们需要对我们的数据进行一个“分档”,比如说,年龄2030岁为一档,年龄3050岁为一档,月收入1W以上为一档,5000~1W为一档,每档的分数不同。
一旦我们将数据统一量纲,或者标准化了之后,数据大小和范围都会改变,统计结果是漂亮了,但是对于业务人员来说,他们完全无法理解,标准化后的年龄在0.003280.00467之间为一档是什么含义。并且,新客户填写的信息,天生就是量纲不统一的,我们的确可以将所有的信息录入之后,统一进行标准化,然后导入算法计算,但是最终落到业务人员手上去判断的时候,他们会完全不理解为什么录入的信息变成了一串统计上很美但实际上根本看不懂的数字。**由于业务要求,在制作评分卡的时候,我们要尽量保持数据的原貌**,年龄就是8110的数字,收入就是大于0,最大值可以无限的数字,即便量纲不统一,我们也不对数据进行标准化处理

样本不均衡问题

X = data.iloc[:,1:]
y = data.iloc[:,0]

y.value_counts()
---
0    139292
1      9873
Name: SeriousDlqin2yrs, dtype: int64

y.value_counts()/X.shape[0]
---
0    0.933812
1    0.066188
Name: SeriousDlqin2yrs, dtype: float64

可以看出,样本严重不均衡。虽然大家都在努力防范信用风险,但实际违约的人并不多。并且,银行并不会真的一棒子打死所有会违约的人。对于银行来说,只要你最后能够把钱还上,我都愿意借钱给你。所以,对于银行来说,真正想要被判别出来的其实是”恶意违约“的人,而这部分人数非常非常少,样本就会不均衡。这一直是银行业建模的一个痛点:我们永远希望捕捉少数类。

之前提到过,逻辑回归中使用最多的是上采样方法来平衡样本
imblearn是专门用来处理不平衡数据集的库,在处理样本不均衡问题中性能高过sklearn很多。

from imblearn.over_sampling import SMOTE
# imblearn里面也是一个个的类,也需要进行实例化,fit拟合,和sklearn用法相似

sm = SMOTE(random_state=42)
X,y = sm.fit_sample(X,y)

X.shape
---
(278584, 10)

y.shape
---
(278584,)

pd.Series(y).value_counts()/y.shape[0]
---
1    0.5
0    0.5
Name: SeriousDlqin2yrs, dtype: float64

如此,我们就实现了样本平衡,样本量也增加了。

关于安装imblearn

安装imblearn模块可以使用如下命令:

pip install imbalanced-learn -i https://pypi.douban.com/simple

但是有可能会出现版本问题或其他bug,建议指定安装版本为0.6.0,本例使用的Python版本为3.7
修改命令为:

pip install imbalanced-learn==0.6.0 --user -i https://pypi.douban.com/simple

关闭Python再打开Python进行测试即可

链接:安装imblearn模块_Mabel-mql的博客-CSDN博客_imblearn安装

这里说一下上采样原理

SMOTE(Synthetic Minority Oversampling Technique),合成少数类过采样技术.它是基于随机过采样算法的一种改进方案,由于随机过采样采取简单复制样本的策略来增加少数类样本,这样容易产生模型过拟合的问题,即使得模型学习到的信息过于特别(Specific)而不够泛化(General),SMOTE算法的基本思想是对少数类样本进行分析并根据少数类样本人工合成新样本添加到数据集中,具体如下图所示,算法流程如下。

  • 对于少数类中的一个样本 x x x,以欧氏距离为标准计算它到少数类样本集中所有样本的距离,得到其k近邻。
  • 根据样本不平衡比例设置一个采样比例以确定采样倍率N,对于每一个少数类样本 x x x,从其k近邻中随机选择若干个样本,假设选择的近邻为 o i o_{i} oi。 图中选中了3个近邻样本
    【菜菜的sklearn课堂笔记】逻辑回归与评分卡-用逻辑回归制作评分卡-异常值和样本不均衡处理_第1张图片
  • 从近邻 o i o_{i} oi选出一个近邻 o o o,与原样本按照公式 o ( n e w ) = o + r a n d ( 0 , 1 ) × ( x − o ) o(new)=o+rand(0,1)\times (x-o) o(new)=o+rand(0,1)×(xo)
    构建新的样本。其中 o ( n e w ) o(new) o(new)表示新样本的坐标, o o o表示被选中的近邻的坐标, ( x − o ) (x-o) (xo)表示选定少数类样本,与选定近邻的欧氏距离
    【菜菜的sklearn课堂笔记】逻辑回归与评分卡-用逻辑回归制作评分卡-异常值和样本不均衡处理_第2张图片

链接:过采样算法之SMOTE - wqbin - 博客园 (cnblogs.com)

你可能感兴趣的:(菜菜的sklearn课堂,逻辑回归,sklearn,算法,python)