CategoryResourceRepost/极客时间专栏/数据分析实战45讲/第三模块:数据分析实战篇/39丨数据挖掘实战(1):信用卡违约率分析.md
louzefeng d3828a7aee mod
2024-07-11 05:50:32 +00:00

284 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<audio id="audio" title="39丨数据挖掘实战1信用卡违约率分析" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/a5/e3/a54f68fc3605897b0c737dd7ff0b74e3.mp3"></audio>
今天我来带你做一个数据挖掘的项目。在数据挖掘的过程中我们经常会遇到一些问题比如如何选择各种分类器到底选择哪个分类算法是SVM决策树还是KNN如何优化分类器的参数以便得到更好的分类准确率
这两个问题,是数据挖掘核心的问题。当然对于一个新的项目,我们还有其他的问题需要了解,比如掌握数据探索和数据可视化的方式,还需要对数据的完整性和质量做评估。这些内容我在之前的课程中都有讲到过。
今天的学习主要围绕下面的三个目标,并通过它们完成信用卡违约率项目的实战,这三个目标分别是:
<li>
创建各种分类器包括已经掌握的SVM、决策树、KNN分类器以及随机森林分类器
</li>
<li>
掌握GridSearchCV工具优化算法模型的参数
</li>
<li>
使用Pipeline管道机制进行流水线作业。因为在做分类之前我们还需要一些准备过程比如数据规范化或者数据降维等。
</li>
## 构建随机森林分类器
在算法篇中,我主要讲了数据挖掘十大经典算法。实际工作中,你也可能会用到随机森林。
随机森林的英文是Random Forest英文简写是RF。它实际上是一个包含多个决策树的分类器每一个子分类器都是一棵CART分类回归树。所以随机森林既可以做分类又可以做回归。当它做分类的时候输出结果是每个子分类器的分类结果中最多的那个。你可以理解是每个分类器都做投票取投票最多的那个结果。当它做回归的时候输出结果是每棵CART树的回归结果的平均值。
在sklearn中我们使用RandomForestClassifier()构造随机森林模型,函数里有一些常用的构造参数:
<img src="https://static001.geekbang.org/resource/image/35/f9/352035fe3e92d412d652fd55c77f23f9.png" alt=""><br>
当我们创建好之后就可以使用fit函数拟合使用predict函数预测。
## 使用GridSearchCV工具对模型参数进行调优
在做分类算法的时候,我们需要经常调节网络参数(对应上面的构造参数),目的是得到更好的分类结果。实际上一个分类算法有很多参数,取值范围也比较广,那么该如何调优呢?
Python给我们提供了一个很好用的工具GridSearchCV它是Python的参数自动搜索模块。我们只要告诉它想要调优的参数有哪些以及参数的取值范围它就会把所有的情况都跑一遍然后告诉我们哪个参数是最优的结果如何。
使用GridSearchCV模块需要先引用工具包方法如下
```
from sklearn.model_selection import GridSearchCV
```
然后我们使用GridSearchCV(estimator, param_grid, cv=None, scoring=None)构造参数的自动搜索模块,这里有一些主要的参数需要说明下:
<img src="https://static001.geekbang.org/resource/image/70/fd/7042cb450e5dcac9306d0178265642fd.png" alt=""><br>
构造完GridSearchCV之后我们就可以使用fit函数拟合训练使用predict函数预测这时预测采用的是最优参数情况下的分类器。
这里举一个简单的例子我们用sklearn自带的IRIS数据集采用随机森林对IRIS数据分类。假设我们想知道n_estimators在1-10的范围内取哪个值的分类结果最好可以编写代码
```
# -*- coding: utf-8 -*-
# 使用RandomForest对IRIS数据集进行分类
# 利用GridSearchCV寻找最优参数
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_iris
rf = RandomForestClassifier()
parameters = {&quot;n_estimators&quot;: range(1,11)}
iris = load_iris()
# 使用GridSearchCV进行参数调优
clf = GridSearchCV(estimator=rf, param_grid=parameters)
# 对iris数据集进行分类
clf.fit(iris.data, iris.target)
print(&quot;最优分数: %.4lf&quot; %clf.best_score_)
print(&quot;最优参数:&quot;, clf.best_params_)
运行结果如下:
最优分数: 0.9667
最优参数: {'n_estimators': 6}
```
你能看到当我们采用随机森林作为分类器的时候最优准确率是0.9667当n_estimators=6的时候是最优参数也就是随机森林一共有6个子决策树。
## 使用Pipeline管道机制进行流水线作业
做分类的时候往往都是有步骤的比如先对数据进行规范化处理你也可以用PCA方法一种常用的降维方法对数据降维最后使用分类器分类。
Python有一种Pipeline管道机制。管道机制就是让我们把每一步都按顺序列下来从而创建Pipeline流水线作业。每一步都采用(‘名称’, 步骤)的方式来表示。
我们需要先采用StandardScaler方法对数据规范化即采用数据规范化为均值为0方差为1的正态分布然后采用PCA方法对数据进行降维最后采用随机森林进行分类。
具体代码如下:
```
from sklearn.model_selection import GridSearchCV
pipeline = Pipeline([
('scaler', StandardScaler()),
('pca', PCA()),
('randomforestclassifier', RandomForestClassifier())
])
```
那么我们现在采用Pipeline管道机制用随机森林对IRIS数据集做一下分类。先用StandardScaler方法对数据规范化然后再用随机森林分类编写代码如下
```
# -*- coding: utf-8 -*-
# 使用RandomForest对IRIS数据集进行分类
# 利用GridSearchCV寻找最优参数,使用Pipeline进行流水作业
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
rf = RandomForestClassifier()
parameters = {&quot;randomforestclassifier__n_estimators&quot;: range(1,11)}
iris = load_iris()
pipeline = Pipeline([
('scaler', StandardScaler()),
('randomforestclassifier', rf)
])
# 使用GridSearchCV进行参数调优
clf = GridSearchCV(estimator=pipeline, param_grid=parameters)
# 对iris数据集进行分类
clf.fit(iris.data, iris.target)
print(&quot;最优分数: %.4lf&quot; %clf.best_score_)
print(&quot;最优参数:&quot;, clf.best_params_)
运行结果:
最优分数: 0.9667
最优参数: {'randomforestclassifier__n_estimators': 9}
```
你能看到是否采用数据规范化对结果还是有一些影响的有了GridSearchCV和Pipeline这两个工具之后我们在使用分类器的时候就会方便很多。
## 对信用卡违约率进行分析
我们现在来做一个信用卡违约率的项目这个数据集你可以从GitHub上下载[https://github.com/cystanford/credit_default](https://github.com/cystanford/credit_default)。
这个数据集是台湾某银行2005年4月到9月的信用卡数据数据集一共包括25个字段具体含义如下
<img src="https://static001.geekbang.org/resource/image/17/88/1730fb3a809c99950739e7f50e1a6988.jpg" alt=""><br>
现在我们的目标是要针对这个数据集构建一个分析信用卡违约率的分类器。具体选择哪个分类器以及分类器的参数如何优化我们可以用GridSearchCV这个工具跑一遍。
先梳理下整个项目的流程:
<img src="https://static001.geekbang.org/resource/image/92/a5/929c96584cbc25972f63ef39101c96a5.jpg" alt="">
<li>
加载数据;
</li>
<li>
准备阶段探索数据采用数据可视化方式可以让我们对数据有更直观的了解比如我们想要了解信用卡违约率和不违约率的人数。因为数据集没有专门的测试集我们还需要使用train_test_split划分数据集。
</li>
<li>
分类阶段之所以把数据规范化放到这个阶段是因为我们可以使用Pipeline管道机制将数据规范化设置为第一步分类为第二步。因为我们不知道采用哪个分类器效果好所以我们需要多用几个分类器比如SVM、决策树、随机森林和KNN。然后通过GridSearchCV工具找到每个分类器的最优参数和最优分数最终找到最适合这个项目的分类器和该分类器的参数。
</li>
基于上面的流程,具体代码如下:
```
# -*- coding: utf-8 -*-
# 信用卡违约率分析
import pandas as pd
from sklearn.model_selection import learning_curve, train_test_split,GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from matplotlib import pyplot as plt
import seaborn as sns
# 数据加载
data = data = pd.read_csv('./UCI_Credit_Card.csv')
# 数据探索
print(data.shape) # 查看数据集大小
print(data.describe()) # 数据集概览
# 查看下一个月违约率的情况
next_month = data['default.payment.next.month'].value_counts()
print(next_month)
df = pd.DataFrame({'default.payment.next.month': next_month.index,'values': next_month.values})
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.figure(figsize = (6,6))
plt.title('信用卡违约率客户\n (违约1守约0)')
sns.set_color_codes(&quot;pastel&quot;)
sns.barplot(x = 'default.payment.next.month', y=&quot;values&quot;, data=df)
locs, labels = plt.xticks()
plt.show()
# 特征选择去掉ID字段、最后一个结果字段即可
data.drop(['ID'], inplace=True, axis =1) #ID这个字段没有用
target = data['default.payment.next.month'].values
columns = data.columns.tolist()
columns.remove('default.payment.next.month')
features = data[columns].values
# 30%作为测试集,其余作为训练集
train_x, test_x, train_y, test_y = train_test_split(features, target, test_size=0.30, stratify = target, random_state = 1)
# 构造各种分类器
classifiers = [
SVC(random_state = 1, kernel = 'rbf'),
DecisionTreeClassifier(random_state = 1, criterion = 'gini'),
RandomForestClassifier(random_state = 1, criterion = 'gini'),
KNeighborsClassifier(metric = 'minkowski'),
]
# 分类器名称
classifier_names = [
'svc',
'decisiontreeclassifier',
'randomforestclassifier',
'kneighborsclassifier',
]
# 分类器参数
classifier_param_grid = [
{'svc__C':[1], 'svc__gamma':[0.01]},
{'decisiontreeclassifier__max_depth':[6,9,11]},
{'randomforestclassifier__n_estimators':[3,5,6]} ,
{'kneighborsclassifier__n_neighbors':[4,6,8]},
]
# 对具体的分类器进行GridSearchCV参数调优
def GridSearchCV_work(pipeline, train_x, train_y, test_x, test_y, param_grid, score = 'accuracy'):
response = {}
gridsearch = GridSearchCV(estimator = pipeline, param_grid = param_grid, scoring = score)
# 寻找最优的参数 和最优的准确率分数
search = gridsearch.fit(train_x, train_y)
print(&quot;GridSearch最优参数&quot;, search.best_params_)
print(&quot;GridSearch最优分数 %0.4lf&quot; %search.best_score_)
predict_y = gridsearch.predict(test_x)
print(&quot;准确率 %0.4lf&quot; %accuracy_score(test_y, predict_y))
response['predict_y'] = predict_y
response['accuracy_score'] = accuracy_score(test_y,predict_y)
return response
for model, model_name, model_param_grid in zip(classifiers, classifier_names, classifier_param_grid):
pipeline = Pipeline([
('scaler', StandardScaler()),
(model_name, model)
])
result = GridSearchCV_work(pipeline, train_x, train_y, test_x, test_y, model_param_grid , score = 'accuracy')
```
```
运行结果:
(30000, 25)
ID ... default.payment.next.month
count 30000.000000 ... 30000.000000
mean 15000.500000 ... 0.221200
std 8660.398374 ... 0.415062
min 1.000000 ... 0.000000
25% 7500.750000 ... 0.000000
50% 15000.500000 ... 0.000000
75% 22500.250000 ... 0.000000
max 30000.000000 ... 1.000000
[8 rows x 25 columns]
GridSearch最优参数 {'svc__C': 1, 'svc__gamma': 0.01}
GridSearch最优分数 0.8174
准确率 0.8172
GridSearch最优参数 {'decisiontreeclassifier__max_depth': 6}
GridSearch最优分数 0.8186
准确率 0.8113
GridSearch最优参数 {'randomforestclassifier__n_estimators': 6}
GridSearch最优分数 0.7998
准确率 0.7994
GridSearch最优参数 {'kneighborsclassifier__n_neighbors': 8}
GridSearch最优分数 0.8040
准确率 0.8036
```
<img src="https://static001.geekbang.org/resource/image/18/72/187d0233d4fb5f07a9653e5ae4754372.png" alt=""><br>
从结果中我们能看到SVM分类器的准确率最高测试准确率为0.8172。
在决策树分类中我设置了3种最大深度当最大深度=6时结果最优测试准确率为0.8113在随机森林分类中我设置了3个决策树个数的取值取值为6时结果最优测试准确率为0.7994在KNN分类中我设置了3个n的取值取值为8时结果最优测试准确率为0.8036。
## 总结
今天我给你讲了随机森林的概念及工具的使用另外针对数据挖掘算法中经常采用的参数调优也介绍了GridSearchCV工具这个利器。并将这两者结合起来在信用卡违约分析这个项目中进行了使用。
很多时候我们不知道该采用哪种分类算法更适合。即便是对于一种分类算法也有很多参数可以调优每个参数都有一定的取值范围。我们可以把想要采用的分类器以及这些参数的取值范围都设置到数组里然后使用GridSearchCV工具进行调优。
<img src="https://static001.geekbang.org/resource/image/14/16/14f9cddc17d6cceb0b8cbc4381c65216.png" alt=""><br>
今天我们讲了如何使用GridSearchCV做参数调优你可以说说你的理解如果有使用的经验也可以分享下。
另外针对信用卡违约率分析这个项目我们使用了SVM、决策树、随机森林和KNN分类器你能不能编写代码使用AdaBoost分类器做分类呢其中n_estimators的取值有10、50、100三种可能你可以使用GridSearchCV运行看看最优参数是多少测试准确率是多少
欢迎你在评论区与我分享你的答案,如果有问题也可以写在评论区。如果你觉得这篇文章有价值,欢迎把它分享给你的朋友或者同事。