機(jī)器學(xué)習(xí)項(xiàng)目中,通俗地講,一般70%以上的時(shí)間會被用于數(shù)據(jù)的處理,20%的時(shí)間用于訓(xùn)練,10%的時(shí)間用于評估結(jié)果,可見數(shù)據(jù)處理在機(jī)器學(xué)習(xí)中的重要性。有句話說的很好,數(shù)據(jù)和特征決定了機(jī)器學(xué)習(xí)的上限,而模型和算法只是逼近這個上限而已。因此這里對數(shù)據(jù)處理的一些工具和方法做一下記錄。本文使用的數(shù)據(jù)集是UCI的Breast Cancer Wisconsin (Diagnostic) ,該數(shù)據(jù)集用于二分類,使用sklearn.datasets中的load_breast_cancer函數(shù)可以方便地加載它。本文基于這個數(shù)據(jù)集,介紹一些常用的數(shù)據(jù)預(yù)處理方法。
1 數(shù)據(jù)的加載
該數(shù)據(jù)集有569個樣本,30個特征,scikit-learn提供方便的函數(shù)來加載該數(shù)據(jù)集,代碼如下:
from sklearn.datasets import load_breast_cancer
import pandas as pd
import numpy as np
bundle = load_breast_cancer()
X = bundle.data
y = bundle.target
X[11:21, 1] = np.NAN #制造缺失值
c = ['mean_radius', 'mean_texture', 'mean_perimeter', 'mean_area',
'mean_smoothness', 'mean_compactness', 'mean_concavity',
'mean_concave', 'mean_symmetry', 'mean_fractal', 'standard_radius',
'standard_texture', 'standard_perimeter', 'standard_area',
'standard_smoothness', 'standard_compactness', 'standard_concavity',
'standard_concave', 'standard_symmetry', 'standard_fractal', 'worst_radius',
'worst_texture', 'worst_perimeter', 'worst_area', 'worst_smoothness',
'worst_compactness', 'worst_concavity', 'worst_concave', 'worst_symmetry', 'worst_fractal']
dataset = pd.DataFrame(X, columns = c)
dataset_part = dataset[c[0:10]]
由于特征較多,方便展示結(jié)果,這里只選取前10個特征。為了模擬具有缺失值的數(shù)據(jù)集,這里我手動把第11到20個樣本的'mean_texture'特征值刪去了。
2 數(shù)據(jù)的初步探索
2.1 快速查看
1. 查看前五行
dataset_part.head()
結(jié)果如下:

2. 查看某個特征的值的個數(shù),由于篇幅限制,這里只展示前10行:
dataset_part['mean_radius'].value_counts().iloc[0 : 10]
結(jié)果如下:

3. 查看該數(shù)據(jù)集的簡單描述,比如總行數(shù)、每個屬性的類型和非控制的數(shù)量等
dataset_part.info()
結(jié)果如下:

4. 顯示屬性的摘要,包括總數(shù)、中位數(shù)、均值等
dataset_part.describe()
結(jié)果如下:

5. 繪制每個特征的直方圖,橫軸是特征值的范圍,縱軸是實(shí)例的數(shù)量
%matplotlib inline
import matplotlib.pyplot as plt
dataset_part.hist(bins=50, figsize=(20,15))
plt.show()
結(jié)果如下所示:

2.2 特征之間的相關(guān)性
方法一
如果數(shù)據(jù)集不大,可以直接使用DataFrame的corr()方法,它會計(jì)算特征兩兩之間的標(biāo)準(zhǔn)相關(guān)系數(shù)(皮爾遜相關(guān)系數(shù))。相關(guān)系數(shù)的范圍從-1到1,越接近1,表示有越強(qiáng)的正相關(guān)性,接近-1,則表示有強(qiáng)烈的負(fù)相關(guān)性。對dataset_part使用corr()函數(shù),得到下表:

可以看到各個特征與其它特征的相關(guān)度,比如mean_radius就與mean_perimeter具有很強(qiáng)烈的正相關(guān)性,而與mean_smoothness則相關(guān)度不高。
方法二
另一種方法是使用Pandas的scatter_matrix函數(shù),它會繪制每個數(shù)值屬性相對于其他數(shù)值屬性的相關(guān)性。比如以下代碼:
%matplotlib inline
from pandas.plotting import scatter_matrix
attr = ['mean_radius', "mean_texture", "mean_perimeter", "mean_area"]
scatter_matrix(dataset_part[attr], figsize=(20,12))
結(jié)果如下所示:
結(jié)果一目了然,可以看到mean_radius與mean_perimeter和mean_area有較強(qiáng)的正相關(guān)性,而與mean_texture則相關(guān)性很低。同一個特征則展示該特征的分布直方圖,否則會是一條毫無價(jià)值的主對角線。
3 數(shù)據(jù)的清理
對于缺失值的處理,有三種選擇:
1. 放棄這些樣本。Scikit-Learn提供以下方法:
df = dataset_part.dropna(subset=['mean_texture'])
print(len(dataset_part), len(df))
輸出:(569, 559)
2. 放棄這個特征。Scikit-Learn提供以下方法:
df = dataset_part.drop('mean_texture', axis=1)
df
輸出如下,可以看到,mean_texture列已經(jīng)不見了:

3. 將缺失的值設(shè)置為某個值(0、平均值或者中位數(shù)等都可以)。Scikit-Learn提供以下方法:
median = dataset_part['mean_texture'].median()
dataset_part['mean_texture'].fillna(median)[0:21]
輸出如下:

這里scikit-learn還提供了另外一種方便的方法來處理缺失值,那就是Imputer。Imputer調(diào)用fit()方法之后,會將均值存放在statistics_成員變量中,調(diào)用transform()方法會產(chǎn)生一個np.ndarray對象,使用方法如下:
from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy='median')
imputer.fit(dataset_part)
imputer.statistics_
X = imputer.transform(dataset_part)
pd.DataFrame(X).iloc[11:21]
4 測試數(shù)據(jù)集的劃分
一般我們可以將數(shù)據(jù)集劃分為20%的測試數(shù)據(jù)集和80%的訓(xùn)練數(shù)據(jù)集,scikit-learn提供了方便的劃分函數(shù),使用如下:
from sklearn.model_selection import train_test_split
train_set, test_set = train_test_split(dataset_part, test_size=0.2, random_state=42)
print(len(train_set), len(test_set))
輸出:(455, 114)
也提供了根據(jù)某一特征進(jìn)行分層抽樣的數(shù)據(jù)分割方法。什么是分層抽樣呢?比如我們想預(yù)測大盤用戶對某類保險(xiǎn)產(chǎn)品的購買意愿,假設(shè)用戶的收入水平對這類保險(xiǎn)的意愿有很大的影響,用戶的收入水平被劃分成A、B、C、D四個層次,已知大盤用戶收入水平的占比依次是20%、40%、30%、10%,研究方法是從大盤中抽出10W個用戶進(jìn)行訓(xùn)練,我們當(dāng)然希望這10W個用戶的收入水平分布和大盤用戶的一致,這就是分層抽樣。同理,我們對數(shù)據(jù)集進(jìn)行劃分,也希望訓(xùn)練集和測試集對某一特征的分布是一致的,這時(shí)就可以使用Scikit-Learn提供的StratifiedShuffleSplit類,使用方法如下:
dataset_part["radius_cat"] = np.ceil(dataset_part['mean_radius'] / 3)
from sklearn.model_selection import StratifiedShuffleSplit
sss = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
for train_index, test_index in sss.split(dataset_part, dataset_part['radius_cat']):
strat_train_set = dataset_part.loc[train_index]
strat_test_set = dataset_part.loc[test_index]
print(len(strat_train_set), len(strat_test_set))
輸出:(455, 114)
StratifiedShuffleSplit允許對數(shù)據(jù)集進(jìn)行多次劃分,產(chǎn)生多組train/test對,以進(jìn)行交叉驗(yàn)證。在這個例子中,我們只進(jìn)行一次分割。
5 總結(jié)
數(shù)據(jù)處理在機(jī)器學(xué)習(xí)項(xiàng)目中是很大的工程,且涉及很多的內(nèi)容和知識,本文介紹的方法只是冰山一角,后續(xù)有更多內(nèi)容會繼續(xù)加進(jìn)來。