实用指南-在python中使用Scikit-learn进行数据预处理

摘要:本文主要关注python中的数据预处理技术。学习算法对哪些类型的数据更加适合, 当使用不规则或者不标准的特征时,这些算法只能得出非常粗糙的预测。像XGBoost这样的算法会具体要求虚拟编码数据,而像决策树这样的算法则并不需要考虑这些(在某些情况下)。

简单来说,预处理是指在将数据输入到算法之前对数据进行的转换。Python里的scikit-learn库在sklearn.preprocessing下有预构建的数据预处理函数。当然还有很多有待我们探索的预处理选项。

学习完本文后,你会习得基本的数据预处理技术以及对它们的深入理解。方便起见,我附加了一些资源用于深入学习机器学习算法,并设计了少量练习,以便更好地掌握这些概念。

可用的数据集

本文我使用了一个贷款预测数据集的子集(缺失观察值被丢弃)。你可以从这里下载训练集和测试集:下载

注意:提供给您的测试数据是“贷款预测”问题的训练数据的子集。现在让我们从导入重要的包和数据集开始吧。

# Importing pandas

>> import pandas as pd

# Importing training data set

>> X_train=pd.read_csv(‘X_train.csv’)

>> Y_train=pd.read_csv(‘Y_train.csv’)

# Importing testing data set

>> 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 CoapplicantIncomeLoanAmountLoan_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和Coapplantantcome在几乎相同的范围(0-50000 $)中,而LoanAmount是以千为单位,其范围从0到600 $。 Loan_Amount_Term则与其他变量完全不同,因为它的单位是月,其他变量的单位则是美元。

如果我们尝试对这些特征应用基于距离的方法,例如KNN,则具有最大范围的特征将主导预测结果,因此我们将获得不准确的预测。 我们可以使用特征缩放来克服这个问题。 让我们实践看看。

学习资源:查看这篇关于KNN的文章,以更好地理解。

让我们尝试用KNN算法来使用数据集,以了解它的性能。

# Initializing and Fitting a k-NN model

>> 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.294271Name: 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的数学公式为:

Screenshot from 2016-06-29 14-16-29

让我们尝试使用这个工具。

# Importing MinMaxScaler and initializing it

>> 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算法并检查其准确性。

# Fitting k-NN on our scaled data set

>> knn=KNeighborsClassifier(n_neighbors=5)

>> knn.fit(X_train_minmax,Y_train)

# Checking the model’s accuracy

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

Out : 0.75

太棒了!我们的准确度从61%提高到了75%。这意味着一些具有较大范围的特征主导了基于距离的方法(KNN)的预测结果。

应该记住,在执行基于距离的方法时,我们必须尝试缩放数据,使得具有较小重要性的特征不会由于其较大的范围而主导目标函数。此外,具有不同单位的特征也应该被缩放,从而赋予每个特征相等的初始权重,从而在最终获得更好的预测模型。

练习一

尝试使用逻辑回归模型(参数:penalty =’l2’,C = 0.01)进行相同的练习,并在注释中注明缩放之前和之后的预测准确性。

特征标准化

阅读本节之前,我建议你先完成练习一。

在上一节里,我们研究了贷款预测数据,并在数据集上拟合了一个KNN学习器。在缩放数据之后,我们的准确率达到了75%,这已经相当好了。我尝试用逻辑回归进行了同样的练习,得到了下面的结果:

缩放数据前:61%

缩放数据后:63%

缩放后获得的正确率接近我们通过猜测所做的预测,这一结果并不尽如人意。所以这里发生了什么呢?为什么正确率没有像在KNN算法中提升那么大呢?

学习资源:通过这篇文章来更好的理解逻辑回归logistic regression

这里是答案:

在逻辑回归中,每个特征会被赋予一个权重或者系数。如果存在具有较大范围的特征,并且其在目标函数中是没有显著影响的,那么逻辑回归本身将对其系数分配非常低的值,从而中和该特定特征的主导效应,而基于距离的方法例如KNN 没有这个内置策略,因此它需要缩放。

我们是不是忘记了什么?我们的逻辑模型仍然维持着接近猜测的正确率。现在我将在这里引入一个新的概念,称为标准化。Sklearn中的许多机器学习算法需要标准化数据,指具有零均值和单位方差的数据。

标准化是特征值被重新缩放的过程,是的他们具有期望为0,标准差为1的标准正态分布的属性。标准分数(也成为z分数)的计算公式如下:

Screenshot from 2016-06-29 14-06-42

诸如线性模型中的l1,l2正则化器(logistic正是在该类别下)和在学习器SVM中的RBF核函数所认为的那样,所有特征以零为中心并且具有相同阶数的方差。

具有较大方差阶数的特征将主导目标函数,就像前文中里具有大范围的特征就是这样。 正如我们在练习1中看到的,对数据没有任何预处理的准确率是61%,让我们标准化我们的数据然后再应用逻辑回归。 Sklearn提供scale函数来标准化数据。

# Standardizing the train and test data

>> 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’]])

# Fitting logistic regression on our standardized data set

>> from sklearn.linear_model import LogisticRegression

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

>> log.fit(X_train_scale,Y_train)

# Checking the model’s accuracy>> accuracy_score(Y_test,log.predict(X_test_scale))

Out : 0.75

我们再次得到了我们在缩放后使用KNN获得的最大准确率。这意味着当使用具有l1或l2正则化的估计器时标准化数据有助于我们提高预测模型的准确性。 其他学习器如KNN与欧几里德距离测量,k均值,SVM,感知器,神经网络,线性判别分析,主成分分析在标准化数据上具有更好的预测性能。

然而我还是建议你先去理解你的数据和将要使用的算法有何特征; 在一段时间后,您将能够判断是否标准化您的数据。

在缩放和标准化之间进行选择,通常会让人觉得很困惑。你必须深入了解你的数据和学习器,然后才能做出决定。对于初学者,你可以尝试这两种方法并比较交叉验证正确率以作出选择。

资源:阅读这篇文章来更好地理解交叉验证cross validation

练习二

尝试使用SVM模型进行相同的练习,并在注释部分中提供标准化之前和之后的准确率。

资源:阅读这篇文章来理解SVM support vector machines

标签编码

在前面几节,我们对连续型数据进行了预处理。但是我们的数据集也会有诸如性别、是否已婚、家属、职业和教育等特征值。这些分类特征的值均是字符串。例如,性别有两个值:male(男)和female(女)。让我们在逻辑回归模型中使用这些值。

# Fitting a logistic regression model on whole data

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

>> log.fit(X_train,Y_train)

# Checking the model’s accuracy

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

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

我们看到了一个报错,说它不能将字符串转换为浮点数。 所以,实际情况是Sklearn中的学习器,如逻辑回归,基于距离的方法,如KNN,支持向量机,基于树的方法等需要数值数组。 这些学习器不能处理具有字符串值的特性。

Sklearn提供了一个非常有效的工具,用于将分类特征的级别编码为数值。 LabelEncoder函数将标签值编码为0到属性个数值-1之间的值。

让我们来对分类标签进行编码。

# Importing LabelEncoder and initializing it

>> from sklearn.preprocessing import LabelEncoder

>> le=LabelEncoder()

# Iterating over all the common columns in train and test

>> for col in X_test.columns.values:

# Encoding only categorical variables

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

# Using whole data to form an exhaustive list of levels

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()来查看更新后的数据集。我们将看看编码之前和之后的性别频率分布。

Before : Male 318

Female 66 Name: Gender, dtype: int64

After : 1  318

0   66

Name: Gender, dtype: int64

既然我们已经完成了标签编码,现在让我们对具有分类和连续特征的数据集应用逻辑回归模型。

# Standardizing the features

>> X_train_scale=scale(X_train)

>> X_test_scale=scale(X_test)

# Fitting the logistic regression model

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

>> log.fit(X_train_scale,Y_train)

# Checking the models accuracy

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

Out : 0.75

现在模型起作用了。但是正确率和我们对连续型变量标准化后得到的正确率一样。这意味着我们添加的分类特征在我们的目标函数中不是非常重要。

练习三

尝试将所有特征作为独立变量来使用决策树分类器,并在评论里写下您的准确性。

资源:阅读这篇文章来理解决策树decision trees

一位有效编码

一位有效编码将每个具有n个可取值的分类特征的值转换为n位二进制特征值,其中只有一位有效(置1,其余位为0)。

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

让我们来看看贷款预测数据集的一个例子。 特征家属(dependents)具有4个可能的值0,1,2和3+,然后在不失去0,1,2和3的一般性的情况下进行编码。

然后,我们在线性分类器中为该特征分配权重“W”,其将基于约束W * Dependents + K> 0或等效地W * Dependents <K来做出决定。

令f(w)= W*Dependents。

等式可取的值为0,W,2W和3W。 这个方程的问题是权重“W”不能基于四个选择做出决定。它可以通过以下方式达成一项决定:

  • 所有输入做出同样的决定(所有的f(w)<k 或者>k)
  • 3:1的比例划分(决策边界是 f(w)>2W)
  • 2:2的比例划分(决策边界是f(w)>W)

在这里我们可以看到,我们失去了许多不同的可能的决定,例如“0和“2W”应该给予相同的标签,“3W”和“W”则应该删去一个。

这个问题可以通过一位有效编码来解决,因为它有效地将特征“家属”(dependents)的维度从一变为四,因此特征“家属”中的每个值将具有它们自己的权重。 用于判定的更新方程将是f’(w)<K。

其中f'(w) = W1*D_0 + W2*D_1 + W3*D_2 + W4*D_3。每个变量的值是0或者1。

同样的事情发生在基于距离的方法,如KNN。 未编码的情况下,家属的“0”和“1”值之间的距离是1,而“0”和“3+”之间的距离将是3,这不是我们期望的,因为两个距离应该相似。编码之后,值将是新的特征(列的序列是0,1,2,3+):[1,0,0,0]和[0,0,0,1](最初我们发现距离 “0”和“3+”),现在的距离将是 。

对于基于树的方法,同样的情况(一个特征有两个以上的值)可能影响结果的范围,但是如果像随机森林这样的方法足够深,它可以不使用一位有效编码就能处理分类变量。

现在让我们来看看各种算法中一位有效编码的实现方法。

让我们在不使用一位有效编码的情况下,来构建一个逻辑回归模型,并对其进行分类。

# We are using scaled variable as we saw in previous section that

# scaling will effect the algo with l1 or l2 reguralizer

>> X_train_scale=scale(X_train)

>> X_test_scale=scale(X_test)

# Fitting a logistic regression model

>> log=LogisticRegression(penalty=’l2′,C=1)

>> log.fit(X_train_scale,Y_train)

# Checking the model’s accuracy

>> 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:

# creating an exhaustive list of all possible categorical values

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

# Fitting One Hot Encoding on train data

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

# Changing the encoded features into a data frame with new column names       temp=pd.DataFrame(temp,columns=[(col+”_”+str(i)) for i in data[col]

.value_counts().index])

# In side by side concatenation index values should be same      

# Setting the index values similar to the X_train data frame

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

# adding the new One Hot Encoded varibales to the train data frame

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

# fitting One Hot Encoding on test data

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

# changing it into data frame and adding column names

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

.value_counts().index])

# Setting the index for proper concatenation

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

# adding the new One Hot Encoded varibales to test data frame

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

现在我们对编码过的数据使用逻辑回归模型。

# Standardizing the data set

>> X_train_scale=scale(X_train_1)

>> X_test_scale=scale(X_test_1)

# Fitting a logistic regression model

>> log=LogisticRegression(penalty=’l2′,C=1)

>> log.fit(X_train_scale,Y_train)

# Checking the model’s accuracy

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

Out : 0.75

在这里,我们再次得到我们到目前为止得到的最大准确率0.75。 在这种情况下,逻辑回归正则化(C)参数1,而较早时我们使用C = 0.01。

结束语

本文的目的是让您熟悉基本的数据预处理技术,并更深入地了解应用这些技术的情况。

当算法的基本假设满足时这些方法会起作用。 这里绝不是详尽的方法列表。 我鼓励你尝试这些方法,因为它们可以根据手头的问题进行大量修改。

我计划在我的下一篇文章中提供更先进的数据预处理技术,例如管道模型和减噪,所以请继续关注以深入了解数据预处理。

你喜欢阅读这篇文章吗? 你使用了不同的方法/包/库来进行这些预处理吗? 我很愿意与你在评论中交流。

原文链接:https://www.analyticsvidhya.com/blog/2016/07/practical-guide-data-preprocessing-python-scikit-learn/

数据分析网翻译小组翻译,翻译成员——丁杨。

翻译小组

翻译小组

数据分析网翻译小组,文章编译自外文,未经许可谢绝任何形式转载,授权请联系邮箱afenxi@afenxi.com
翻译小组

注:数据分析网遵循行业规范,任何转载的稿件都会明确标注作者和来源,若标注有误或遗漏,请联系主编邮箱:afenxi@afenxi.com

分享到:更多

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址