利用 Scikit Learn的Python数据预处理实战指南

简介:



简而言之,预处理是指在你将数据“喂给”算法之前进行的一系列转换操作。在Python中,scikit-learn库在sklearn.preprocessing下有预装的功能。有更多的选择来进行预处理,这将是我们要探索的。


读完本文,你将具备数据预处理的基本技能并对其有更深入的理解。为了方便起见,我附上了进一步学习机器学习算法的一些资源,并且为更好地掌握这些概念,设计了几个小练习。


可用数据集

本文中,我使用了部分的贷款预测数据,缺失观测值的数据已被移除(需要数据的读者朋友,请在评论区留下电邮地址,我们会把数据发给你——译者注)。


备注:贷款预测问题中,测试集数据是训练集的子集。


现在,让我们从导入重要的包和数据集开始。


导入pandas

>> import pandas as pd

导入训练用的数据集

>> X_train=pd.read_csv('X_train.csv')

>> Y_train=pd.read_csv('Y_train.csv')

导入测试数据集

>> X_test=pd.read_csv('X_test.csv')

>> Y_test=pd.read_csv('Y_test.csv')

对我们的数据集进行仔细观察。

>> print (X_train.head())

     Loan_ID Gender Married Dependents Education Self_Employed

15   LP001032   Male      No          0  Graduate            No   

248  LP001824   Male     Yes          1  Graduate            No   

590  LP002928   Male     Yes          0  Graduate            No   

246  LP001814   Male     Yes          2  Graduate            No   

388  LP002244   Male     Yes          0  Graduate            No   

 
 

     ApplicantIncome  CoapplicantIncome  LoanAmount  Loan_Amount_Term

15              4950                0.0       125.0             360.0   

248             2882             1843.0       123.0             480.0   

590             3000             3416.0        56.0             180.0   

246             9703                0.0       112.0             360.0   

388             2333             2417.0       136.0             360.0   

 
 

     Credit_History Property_Area  

15              1.0         Urban  

248             1.0     Semiurban  

590             1.0     Semiurban  

246             1.0         Urban  

388             1.0         Urban


特征缩放

特征缩放是用来限制变量范围的方法,以让它们能在相同的尺度上进行比较。这是在连续变量上操作的。让我们输出数据集中所有连续变量的分布。


>> import matplotlib.pyplot as plt

>> X_train[X_train.dtypes[(X_train.dtypes=="float64")|(X_train.dtypes=="int64")]

                        .index.values].hist(figsize=[11,11])




理解以上图示后,我们推断ApplicantIncome(申请人收入) 和CoapplicantIncome(共同申请人收入) 有相似的尺度范围(0-50000$),LoanAmount(贷款额度) 以千为单位,范围在0 到 600$之间,而Loan_Amount_Term(贷款周期)与其它变量完全不同,因为它的单位是月份,而其它变量单位是美元。


如果我们尝试应用基于距离的算法,如KNN,在这些特征上,范围最大的特征会决定最终的输出结果,那么我们将得到较低的预测精度。我们可通过特征缩放解决这个问题。让我们实践一下。


资料:阅读这篇关于KNN的文章获得更好的理解。(https://www.analyticsvidhya.com/blog/2014/10/introduction-k-neighbours-algorithm-clustering/)

让我们在我们的数据集中试试KNN,看看它表现如何。

# 初始化和拟合一个KNN模型

>> from sklearn.neighbors import KNeighborsClassifier

>> knn=KNeighborsClassifier(n_neighbors=5)

>> knn.fit(X_train[['ApplicantIncome', 'CoapplicantIncome','LoanAmount', 

                   'Loan_Amount_Term', 'Credit_History']],Y_train)

# Checking the performance of our model on the testing data set

# 检查我们的模型在测试数据集上的性能

>> from sklearn.metrics import accuracy_score

>> accuracy_score(Y_test,knn.predict(X_test[['ApplicantIncome', 'CoapplicantIncome',

                             'LoanAmount', 'Loan_Amount_Term', 'Credit_History']]))


Out : 0.61458333333333337


我们得到了大约61%的正确预测,这不算糟糕,但在真正实践中,这是否足够?我们能否将该模型部署于实际问题中?为回答该问题,让我们看看在训练集中关于Loan_Status(贷款状态) 的分布。

>> Y_train.Target.value_counts()/Y_train.Target.count()


Out : Y 0.705729

     N 0.294271

Name: Loan_Status, dtype: float64


大约有70%贷款会被批准,因为有较高的贷款批准率,我们就建立一个所有贷款都通过的预测模型,继续操作并检测我们的预测精度。


 >> Y_test.Target.value_counts()/Y_test.Target.count()


Out :  Y 0.635417

      N 0.364583

Name: Loan_Status, dtype: float64


哇!通过猜测,我们获得63%的精度。这意味着,该模型比我们的预测模型得到更高的精度?


这可能是因为某些具有较大范围的无关紧要的变量主导了目标函数。我们可以通过缩小所有特征到同样的范围来消除该问题。Sklearn提供了MinMaxScaler 工具将所有特征的范围缩小到0-1之间,MinMaxScaler 的数学表达式如下所示:


让我们在我们的问题中试试该工具。

# 导入MinMaxScaler并初始化

>> from sklearn.preprocessing import MinMaxScaler

>> min_max=MinMaxScaler()# Scaling down both train and test data set

>> X_train_minmax=min_max.fit_transform(X_train[['ApplicantIncome', 'CoapplicantIncome',

                'LoanAmount', 'Loan_Amount_Term', 'Credit_History']])

>> X_test_minmax=min_max.fit_transform(X_test[['ApplicantIncome', 'CoapplicantIncome',

                'LoanAmount', 'Loan_Amount_Term', 'Credit_History']])


现在,我们已经完成缩放操作,让我们在缩放后的数据上应用KNN并检测其精度。


在我们缩小后的数据集上拟合KNN

>> knn=KNeighborsClassifier(n_neighbors=5)

>> knn.fit(X_train_minmax,Y_train)

# 检查该模型的精度

>> accuracy_score(Y_test,knn.predict(X_test_minmax))


Out : 0.75


太好了!我们的精度从61%提升到了75%。这意味在基于距离的方法中(如:KNN),一些大范围的特征对预测结果有决定性作用。


应当牢记,当使用基于距离的算法时,我们必须尝试将数据缩放,这样较不重要的特征不会因为自身较大的范围而主导目标函数。此外,具有不同度量单位的特征也应该进行缩放,这样给每个特征具有相同的初始权重,最终我们会得到更好的预测模型。


练习1:


尝试利用逻辑回归模型做相同的练习(参数: penalty=’l2′,C=0.01), 并请在评论区留下缩放前后的精度。


特征标准化

在进入这部分内容前,我建议你先完成练习1。


在之前的章节,我们在贷款预测数据集之上操作,并在其上拟合出一个KNN学习模型。通过缩小数据,我们得到了75%的精度,这看起来十分不错。我在逻辑回归模型上尝试了同样的练习, 并得到如下结果:

Before Scaling : 61%

After Scaling : 63%

缩放前:61%

缩放后:63%


缩放后的精度与我们凭猜测得到的预测精度相近,这并不是很了不起的成就。那么,这是怎么回事呢?在精度上,为什么不像用KNN一样有令人满意的提升?


资料:阅读本文(https://www.analyticsvidhya.com/blog/2015/08/comprehensive-guide-regression/)获得对逻辑回归更好的理解。


答案在此:


在逻辑回归中,每个特征都被分配了权重或系数(Wi)。如果某个特征有相对来说比较大的范围,而且其在目标函数中无关紧要,那么逻辑回归模型自己就会分配一个非常小的值给它的系数,从而中和该特定特征的影响优势,而基于距离的方法,如KNN,没有这样的内置策略,因此需要缩放。


我们是否忘了什么?我们的逻辑模型的预测精度和猜测的几乎接近。


现在,我将在此介绍一个新概念,叫作标准化。很多Sklearn中的机器学习算法都需要标准化后的数据,这意味数据应具有零均值和单位方差。


标准化(或Z-score正则化)是对特征进行重新调整,让数据服从基于 μ=0 和 σ=1的标准正态分布,其中μ是均值(平均值)而σ是关于均值的标准偏差。样本的标准分数(也称为z-scores)按如下所示的方法计算:



线性模型中因子如l1,l2正则化和学习器的目标函数中的SVM中的RBF核心假设所有的特征都集中在0周围并且有着相同顺序的偏差。


有更大顺序的方差的特征将在目标函数上起决定作用,因为前面的章节中,有着更大范围的特征产生过此情形。 正如我们在练习1中看到的,没进行任何预处理的数据之上的精度是61%,让我们标准化我们的数据,在其上应用逻辑回归。Sklearn提供了尺度范围用于标准化数据。


# 标准化训练和测试数据

>> from sklearn.preprocessing import scale

>> X_train_scale=scale(X_train[['ApplicantIncome', 'CoapplicantIncome',

                'LoanAmount', 'Loan_Amount_Term', 'Credit_History']])

>> X_test_scale=scale(X_test[['ApplicantIncome', 'CoapplicantIncome',

               'LoanAmount', 'Loan_Amount_Term', 'Credit_History']])

# 在我们的标准化了的数据集上拟合逻辑回归

>> from sklearn.linear_model import LogisticRegression

>> log=LogisticRegression(penalty='l2',C=.01)

>> log.fit(X_train_scale,Y_train)

# 检查该模型的精度

>> accuracy_score(Y_test,log.predict(X_test_scale))


Out : 0.75


我们再次达到缩放后利用KNN所能达到的我们最大的精度。这意味着,当使用l1或l2正则化估计时,标准化数据帮助我们提高预测模型的精度。其它学习模型,如有欧几里得距离测量的KNN、k-均值、SVM、感知器、神经网络、线性判别分析、主成分分析对于标准化数据可能会表现更好。


尽管如此,我还是建议你要理解你的数据和对其将要使用的算法类型。过一段时间后,你会有能力判断出是否要对数据进行标准化操作。


备注:在缩放和标准化中二选一是个令人困惑的选择,你必须对数据和要使用的学习模型有更深入的理解,才能做出决定。对于初学者,你可以两种方法都尝试下并通过交叉验证精度来做出选择。


资料:阅读本文(https://www.analyticsvidhya.com/blog/2015/11/improve-model-performance-cross-validation-in-python-r/)会对交叉验证有更好的理解



练习2


尝试利用SVM模型做相同的练习,并请在评论区留下标准化前后的精度。


资料:阅读本文(https://www.analyticsvidhya.com/blog/2015/10/understaing-support-vector-machine-example-code/)会对SVM有更好的理解。


标签编码

在前面的章节里,我们对连续数字特征做了预处理。但是,我们的数据集还有其它特征,如性别(Gender)、婚否(Married)、供养人(Dependents)、自雇与否(Self-Employed)和教育程度(Education)。所有这些类别特征的值是字符型的。例如,性别(Gender)有两个层次,或者是男性(Male),或者是女性(Female)。让我们把这些特征放进我们的逻辑回归模型中。


#在整个数据集上拟合放逻辑回归模型

>> log=LogisticRegression(penalty='l2',C=.01)

>> log.fit(X_train,Y_train)

#检查模型的精度

>> accuracy_score(Y_test,log.predict(X_test))


Out : ValueError: could not convert string to float: Semiurban


我们得到一个错误信息:不能把字符型转换成浮点型。因此,这里真正在发生的事是像逻辑回归和基于距离的学习模式,如KNN、SVM、基于树的方法等等,在Sklearn中需要数字型数组。拥有字符型值的特征不能由这些学习模式来处理。


Sklearn提供了一个非常有效的工具把类别特征层级编码成数值。LabelEncoder用0到n_classes-1之间的值对标签进行编码。


让我们对所有的类别特征进行编码。


#导入LabelEncoder并初始化

>> from sklearn.preprocessing import LabelEncoder

>> le=LabelEncoder()

#遍历在训练和测试集中所有的公共列

>> for col in X_test.columns.values:

        #只对类别变量编码

       if X_test[col].dtypes=='object':

        #利用全部数据形成一个所有层次的详尽清单

       data=X_train[col].append(X_test[col])

       le.fit(data.values)

       X_train[col]=le.transform(X_train[col])

       X_test[col]=le.transform(X_test[col])


我们所有的类别特征都已编码。用X_train.head()可以查看更新了的数据集。我们将看下性别(Gender)在编码前后的频率分布。

Before : Male 318 

         Female 66 

Name: Gender, dtype: int64


After : 1 318 

        0 66 

Name: Gender, dtype: int64


现在我们已经完成了标签编码,让我们在同时有着类别和连续特征的数据集上运行逻辑回归模型。


#特征标准化

>> X_train_scale=scale(X_train)

>> X_test_scale=scale(X_test)

#拟合逻辑回归模型

>> log=LogisticRegression(penalty='l2',C=.01)

>> log.fit(X_train_scale,Y_train)

#检查模型的精度

>> accuracy_score(Y_test,log.predict(X_test_scale))


Out : 0.75


现在可以用了。但是,精度仍然和我们从数字特征标准化之后用逻辑回归得到的一样。这意味着我们加入的类别特征在我们的目标函数中不是非常显著。


练习3

试试用所有的特征作为非独立变量进行决策树分类,并评论一下你得到的精度。


资料:浏览本文(https://www.analyticsvidhya.com/blog/2016/04/complete-tutorial-tree-based-modeling-scratch-in-python/)中关于决策树的内容以更好地理解。


一位有效编码(One-Hot-Encoding,主要是采用位状态寄存器来对某个状态进行编码,每个状态都有自己独立的寄存器位,并且在任意时候只有一位有效——译者注)。


一位有效编码把每个带有n个可能值的类别特征转换成n个二进制特征,只有一个是有效的。


大多数机器学习算法不是为每个特征设置单个权重就是计算样本之间的距离。如线性模型算法(例如:逻辑回归)属于第一类。


让我们看一看一个来自loan_prediction数据集的例子。特征从属(Feature Dependents)有4个可能的值:0、1、2和3+,这些是编过码的,没有丢掉0、1、2和3的一般性。


在线性分类器中,我们就分配一个权重“W”给这个特征,这将在W*Dependents+K>0或相当于W*Dependents < span="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important;"> <>

Let f(w)= W*Dependents

让f(w)=W*Dependents

Possible values that can be attained by the equation are 0, W, 2W and 3W. A problem with this equation is that the weight “W” cannot make decision based on four choices. It can reach to a decision in following ways:

由方程获得的可能值是0、W、2W和3W。这个方程的一个问题是权重W不能在4个选择的基础上得到。它可以用下面的方法来决定:

•        所有导致同样的决定(所有的值 < span="" style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important;"> <>

•        3:2的层级分配(当f(w)>2W时的决策区间)

•        2:2的层级分配(当f(w)>W时的决策区间)


这里我们可以看到丢失了许多不同的可能决策,比如:“0”和“2W”应该给予相同的标签,“3W”和“W”是额外的。


这个问题可以通过一位有效编码来解决,因为它有效地把特征“从属”的维度从1变成4,这样特征“从属”的每个值将有自己的权重。更新了的决策方程将是f'(w) < K。


这里,f'(w) = W1*D_0 + W2*D_1 + W3*D_2 + W4*D_3


所有4个新变量有布尔型值(0或1)。


同样的事发生在基于距离的方法中,如KNN。没有编码,“0”和“1”从属值之间的距离是1,在“0”和“3+”之间的距离是3,这不是所期望的,因为这两个距离应该类似。在编码后,值将有新特征(列序列是0,1,2,3+):[1,0,0,0]和[0,0,0,1](最初我们找到的在“0”和“3+”之间的距离),现在这个距离将会是√2。


对于基于树的方法,同样的情况(在一个特征中有2个以上的值)可能在一定程度上影响输出,但是如果像随机森林的方法,若有足够深的深度,无需一位有效编码就能够处理类别变量。


现在,让我们看下不同算法中的一位有效编码的实现。


让我们创建一个逻辑回归模型用于分类,而不使用一位有效编码。


#我们使用的是缩放后的变量,因为我们看到在上一节中缩放会影响L1L2的正则化算法

>> X_train_scale=scale(X_train)

>> X_test_scale=scale(X_test)

拟合逻辑回归模型

>> log=LogisticRegression(penalty='l2',C=1)

>> log.fit(X_train_scale,Y_train)

检查模型的精度

>> accuracy_score(Y_test,log.predict(X_test_scale))


Out : 0.73958333333333337


现在,我们对数据进行编码。

>> from sklearn.preprocessing import OneHotEncoder

>> enc=OneHotEncoder(sparse=False)

>> X_train_1=X_train

>> X_test_1=X_test

>> columns=['Gender', 'Married', 'Dependents', 'Education','Self_Employed',

          'Credit_History', 'Property_Area']

>> for col in columns:

        #创建一个包含所有可能分类值的详尽列表

       data=X_train[[col]].append(X_test[[col]])

       enc.fit(data)

        #在训练数据上拟合一位有效编码

       temp = enc.transform(X_train[[col]])

        #用新列名把编了码的特征改为数据帧

       temp=pd.DataFrame(temp,columns=[(col+"_"+str(i)) for i in data[col]

            .value_counts().index])

        #在并排级联中,检索值应该是相同的。

        #设置与X_train数据帧类似的索引值

       temp=temp.set_index(X_train.index.values)

        #把新的一位有效编码了的变量加入训练数据帧

       X_train_1=pd.concat([X_train_1,temp],axis=1)

        #在测试数据上拟合一位有效编码

       temp = enc.transform(X_test[[col]])

        #把它变成数据帧并加上列名

       temp=pd.DataFrame(temp,columns=[(col+"_"+str(i)) for i in data[col]

            .value_counts().index])

        #设置合适的级联索引

       temp=temp.set_index(X_test.index.values)

        #把新的一位有效编码了的变量加入到测试数据帧

       X_test_1=pd.concat([X_test_1,temp],axis=1)


现在,让我们在一位有效编码了的数据上应用逻辑回归模型

#标准化数据集

>> X_train_scale=scale(X_train_1)

>> X_test_scale=scale(X_test_1)

#拟合逻辑回归模型

>> log=LogisticRegression(penalty='l2',C=1)

>> log.fit(X_train_scale,Y_train)

#检查模型的精度

>> accuracy_score(Y_test,log.predict(X_test_scale))

Out : 0.75


到此,我们再次得到最大的精度是0.75,这是我们迄今所能得到的。在这个例子中,逻辑回归正则(C)参数是1,早前我们用的是C=0.01。

原文发布时间为:2017-01-22


本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“BigDataDigest”微信公众号

相关文章
|
7天前
|
数据采集 存储 JSON
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第27天】本文介绍了Python网络爬虫Scrapy框架的实战应用与技巧。首先讲解了如何创建Scrapy项目、定义爬虫、处理JSON响应、设置User-Agent和代理,以及存储爬取的数据。通过具体示例,帮助读者掌握Scrapy的核心功能和使用方法,提升数据采集效率。
46 6
|
7天前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
81 44
|
1天前
|
图形学 Python
SciPy 空间数据2
凸包(Convex Hull)是计算几何中的概念,指包含给定点集的所有凸集的交集。可以通过 `ConvexHull()` 方法创建凸包。示例代码展示了如何使用 `scipy` 库和 `matplotlib` 绘制给定点集的凸包。
9 1
|
2天前
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
|
3天前
|
数据采集 Web App开发 iOS开发
如何使用 Python 语言的正则表达式进行网页数据的爬取?
使用 Python 进行网页数据爬取的步骤包括:1. 安装必要库(requests、re、bs4);2. 发送 HTTP 请求获取网页内容;3. 使用正则表达式提取数据;4. 数据清洗和处理;5. 循环遍历多个页面。通过这些步骤,可以高效地从网页中提取所需信息。
|
3天前
|
前端开发 API 开发者
Python Web开发者必看!AJAX、Fetch API实战技巧,让前后端交互如丝般顺滑!
在Web开发中,前后端的高效交互是提升用户体验的关键。本文通过一个基于Flask框架的博客系统实战案例,详细介绍了如何使用AJAX和Fetch API实现不刷新页面查看评论的功能。从后端路由设置到前端请求处理,全面展示了这两种技术的应用技巧,帮助Python Web开发者提升项目质量和开发效率。
11 1
|
3天前
|
缓存 测试技术 Apache
告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
告别卡顿!Python性能测试实战教程,JMeter&Locust带你秒懂性能优化💡
11 1
|
8天前
|
数据可视化 开发者 Python
Python GUI开发:Tkinter与PyQt的实战应用与对比分析
【10月更文挑战第26天】本文介绍了Python中两种常用的GUI工具包——Tkinter和PyQt。Tkinter内置于Python标准库,适合初学者快速上手,提供基本的GUI组件和方法。PyQt基于Qt库,功能强大且灵活,适用于创建复杂的GUI应用程序。通过实战示例和对比分析,帮助开发者选择合适的工具包以满足项目需求。
40 7
|
8天前
|
数据采集 Web App开发 前端开发
Python爬虫进阶:Selenium在动态网页抓取中的实战
【10月更文挑战第26天】动态网页抓取是网络爬虫的难点,因为数据通常通过JavaScript异步加载。Selenium通过模拟浏览器行为,可以加载和执行JavaScript,从而获取动态网页的完整内容。本文通过实战案例,介绍如何使用Selenium在Python中抓取动态网页。首先安装Selenium库和浏览器驱动,然后通过示例代码展示如何抓取英国国家美术馆的图片信息。
29 6
|
6天前
|
Linux 开发者 iOS开发
Python系统调用实战:如何在不同操作系统间游刃有余🐟
本文介绍了 Python 在跨平台开发中的强大能力,通过实际例子展示了如何使用 `os` 和 `pathlib` 模块处理文件系统操作,`subprocess` 模块执行外部命令,以及 `tkinter` 创建跨平台的图形用户界面。这些工具和模块帮助开发者轻松应对不同操作系统间的差异,专注于业务逻辑。
20 2

热门文章

最新文章