數據科學與機器學習管道中預處理的重要性(一):中心化、縮放和K近鄰

http://geek.csdn.net/news/detail/75243


原文鏈接:The importance of preprocessing in data science and the machine learning pipeline I: centering, scaling and k-Nearest Neighbours 
作者:Hugo Bowne-Anderson 
譯者:劉翔宇 審校:劉帝偉 
責編:周建丁([email protected]) 
未經許可,謝絕轉載!

數據預處理是一個概括性術語,它包括一系列的操作,數據科學家使用這些方法來將原始數據處理成更方便他們進行分析的形式。例如,在對推特數據進行情感分析之前,你可能想去掉所有的HTML標籤,空格,展開縮寫詞,將推文分割成詞彙列表。在分析空間數據的時候,你可能要對其進行縮放,使其與單位無關,也就是說算法不關心原始的度量是英里還是釐米。然後,數據預處理並不是憑空產生的。預處理只是一種達到目的的手段,並沒有硬性、簡便的規則:我們將會看到這有標準的做法,你也會瞭解到哪些可以起作用,但最終,預處理一般是面向結果管道的一部分,它的性能需要根據上下文來判斷。

在這篇文章中,我將通過縮放數值數據(數值數據:包含數字的數據,而不是包含類別/字符串;縮放:使用基本的算術方法來改變數據的範圍;下面會詳細描述)來向你展示將預處理作爲機器學習管道結構一部分的重要性。爲此,我們將會使用一個實際的例子,在此例子中縮放數據可以提升模型的性能。在文章的最後,我也會列出一些重要的術語。

首先,我將介紹機器學習中的分類問題以及K近鄰,它是解決這類問題時使用到的最簡單的算法之一。在這種情形下要體會縮放數值數據的重要性,我會介紹模型性能度量方法和訓練測試集的概念。在接下來的試驗中你將會見識到這些所有的概念和實踐,我將使用一個數據集來分類紅酒的質量。我同樣會確保我把預處理使用在了刀刃上——在一次數據科學管道迭代開始的附近。這裏所有的樣例代碼都由Python編寫。如果你不熟悉Python,你可以看看我們的DataCamp課程。我將使用pandas庫來處理數據以及scikit-learn 來進行機器學習。

機器學習中分類問題簡介

給現象世界中的事物進行分類和標記是一門古老的藝術。在公元前4世紀,亞里士多德使用了一套系統來分類生物,這套系統使用了2000年。在現代社會中,分類通常作爲一種機器學習任務,具體來說是一種監督式學習任務。監督式學習的基本原理很簡單:我們有一堆有預測變量和目標變量組成的數據。監督式學習的目標是構建一個“擅長”通過預測變量來預測目標變量的模型。如果目標變量包含類別(例如“點擊”或“不是”,“惡性”或“良性”腫瘤),我們稱這種學習任務爲分類。如果目標是一個連續變化的變量(例如房屋價格),那麼這是一個迴歸任務。

以一個例子進行說明:考慮心臟病數據集,其中有75個預測變量,例如“年齡”,“性別”和“是否吸菸”,目標變量爲心臟病出現的可能性,範圍從0(沒有心臟病)到4。此數據集的許多工作都集中於區分會出現心臟病的數據和不會出現心臟病的數據。這是一個分類任務。如果你是要預測出目標變量具體的值,這就是一個迴歸問題了(因爲目標變量是有序的)。我將會在下一篇文章中討論迴歸。在這裏我將集中於講述分類任務中最簡單的算法之一,也就是K近鄰算法。

機器學習中K近鄰分類

假如我們有一些標記了的數據,比如包含紅酒特性的數據(比如酒精含量,密度,檸檬酸含量,pH值等;這些是預測變量)和目標變量“質量”和標籤“好”和“壞”。然後給出一條新的未標記的紅酒特性數據,分類任務就是預測這條數據的“質量”。當所有的預測變量都是數值類型時(處理分類數據還有其他的方法),我們可以將每一行/紅酒看作是n維空間中的一點,在這種情形下,不管在理論上還是計算上,K近鄰(k-NN)都是一種簡單的分類方法:對於每條新的未標記的紅酒數據,計算一個整數k,是在n維預測變量空間中距離最近的k個質心。然後我們觀察這k個質心的標籤(即“好”或“壞”),然後將最符合的標籤分配給這條新的紅酒數據(例如,如果k=5,3的質心給出的是“好”,k=2的質心給出的是“壞”,那麼模型將新紅酒數據標記爲“好”)。需要注意的是,在這裏,訓練模型完全由存儲數據構成:沒有參數需要調整!

K近鄰可視化描述

下圖是2維k-NN算法的樣例:你怎麼分類中間那個數據點?如果k=3,那麼它是紅色,如果k=5,那麼它是綠色。

from IPython.display import Image
Image(url= 'http://36.media.tumblr.com/d100eff8983aae7c5654adec4e4bb452/tumblr_inline_nlhyibOF971rnd3q0_500.png')

圖片描述

Python(scikit-learn)實現k-NN

現在我們來看一個k-NN實戰例子。首先我們要導入紅酒質量數據:我們把它導入到pandas的dataframe中,然後用直方圖繪製預測變量來感受下這些數據。

import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('ggplot')
df = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv ' , sep = ';')
X = df.drop('quality' , 1).values # drop target variable
y1 = df['quality'].values
pd.DataFrame.hist(df, figsize = [15,15]);

圖片描述
首先看看預測變量的範圍:“遊離二氧化硫(free sulfur dioxide)”從0到70,“揮發性酸(volatile acidity)”大約從0到1.2。具體而言,前者比後者大兩個數量級。任何關心數據點之間距離的算法,如k-NN,都會直接不公平的處理這些更大範圍的變量,如“遊離二氧化硫”,它可能包含噪聲。這促使我們縮放數據,我們很快會講到。

現在目標變量是“質量”,等級(rating)範圍從3到8。爲便於解釋,我們把它分爲兩類,包含“好”的變量(rating>5)和“壞”的變量(rating<=5)。同樣我們使用直方圖來繪製這兩種目標變量來獲得直觀體驗。

y = y1 <= 5 # is the rating <= 5?
# plot histograms of original target variable
# and aggregated target variable
plt.figure(figsize=(20,5));
plt.subplot(1, 2, 1 );
plt.hist(y1);
plt.xlabel('original target value')
plt.ylabel('count')
plt.subplot(1, 2, 2);
plt.hist(y)
plt.xlabel('aggregated target value')
plt.show()

圖片描述

現在我們可以進行K近鄰操作了。首先,如果我們要比較經預處理和沒經預處理得到的模型的性能,我們需要知道如何衡量一個模型的“好壞”:

K近鄰:它執行效果如何?

對於分類任務有許多性能度量措施。需要注意的是,性能度量的選擇很大程度上取決於具體的領域和問題。在類別分佈平衡的數據集上(所有的目標值都同樣表示),數據科學家通常將準確率作爲性能度量。事實上,我們將會看到在scikit-learn中準確率是k-NN和邏輯迴歸默認的性能度量方法。那麼什麼是準確率呢?它就是由正確預測的數目除以總預測數得來。

圖片描述

注意:準確率同樣可以用混淆矩陣來定義,而且通常爲二元分類中的真陽性和假陰性定義;從混淆矩陣衍生出的其他一些常見的模型性能度量方法有精度(precision),用真陽性樣例數目除以真和假陽性樣例數目,召回率(recall),用真陽性樣例數目除以真陽性和假陰性樣例數目;還有另外一個度量方式,F1-score,是精度和召回率的調和平均數。參見machine learning mastery 來了解這些度量方式;同樣可以在Wikipedia上了解關於混淆矩陣和F1 score的相關信息。

k-NN:實際性能和訓練測試拆分

使用諸如精度的性能度量的確不錯,但是如果用所有的數據來擬合模型,我們用哪些數據來生成精度報告呢?請記住,我們需要一個對新數據具有良好泛化的模型。因此,如果我們在數據集D上訓練模型,使用同樣的數據集D來生成此模型的精度,這樣可能會比實際情況下的產生的精度要高。這被稱爲過度擬合。爲了解決這個問題,數據科學家通常用數據集的子集來訓練模型,這個子集叫做訓練集,然後使用剩下的數據來評估性能,被稱爲測試集。這正是我們要在這裏做的!一般的經驗法則是使用大約80%的數據作爲訓練數據,20%的數據作爲測試數據。現在我們來拆分紅酒質量數據集:

from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

我們現在建立k-NN模型,在測試集上進行預測,然後將這些預測與實際結果進行對比來度量模型的性能。

from sklearn import neighbors, linear_model
knn = neighbors.KNeighborsClassifier(n_neighbors = 5)
knn_model_1 = knn.fit(X_train, y_train)
print('k-NN accuracy for test set: %f' % knn_model_1.score(X_test, y_test))
k-NN accuracy for test set: 0.612500

值得重申的是scikit-learn中k-NN默認的計分方法是精度。61%的精度不算太好,但是沒有經過預處理而生成的模型可以達到這個精度還算不錯。要查看其它各種指標,我們可以使用scikit-learn中的分類報告:

from sklearn.metrics import classification_report
y_true, y_pred = y_test, knn_model_1.predict(X_test)
print(classification_report(y_true, y_pred))
             precision    recall  f1-score   support

      False       0.66      0.64      0.65       179
       True       0.56      0.57      0.57       141

avg / total       0.61      0.61      0.61       320

現在我們來介紹縮放和中心化,它們是預處理數值型數據最基本的方法,看看它們如何影響模型的性能。

預處理機制:縮放和中心化

在運行模型前,比如迴歸(預測連續變量)或分類(預測離散變量),你幾乎總想要對數據做一些預處理工作。對於數值型變量,通常會對數據進行標準化或規範化。這些術語是什麼意思?

所有的標準化操作就是將數據集縮放,使其最小值爲0,最大值爲1。爲實現這一目標,我們將數據點x變換成 
圖片描述
規範化略有不同;它將數據向0集中,使用標準差進行縮放: 
圖片描述
其中μ和σ分別表示數據集的平均值和標準差。首先要注意的是,這些變換僅僅改變數據的範圍而沒有改變其分佈。之後你可能會使用其他的變換,比如log變換或者Box-Cox變換,讓數據更像高斯分佈(如鐘形曲線)。在進一步講述之前,我們首先弄清楚這麼一個問題:我們爲什麼縮放數據?有沒有在某個情形下更適合縮放數據呢?比如,在分類問題中使用縮放數據比在迴歸中更重要?

首先我們來看看在分類問題中縮放數據對k-NN性能的影響:

預處理:縮放實戰

在這裏,我首先(i)縮放數據,(ii)使用k-NN,(iii)檢查模型的性能。我將使用scikit-learn的scale函數,它對輸入的數組中所有的特徵(列)進行縮放。

from sklearn.preprocessing import scale
Xs = scale(X)
from sklearn.cross_validation import train_test_split
Xs_train, Xs_test, y_train, y_test = train_test_split(Xs, y, test_size=0.2, random_state=42)
knn_model_2 = knn.fit(Xs_train, y_train)
print('k-NN score for test set: %f' % knn_model_2.score(Xs_test, y_test))
print('k-NN score for training set: %f' % knn_model_2.score(Xs_train, y_train))
y_true, y_pred = y_test, knn_model_2.predict(Xs_test)
print(classification_report(y_true, y_pred))
k-NN score for test set: 0.712500
k-NN score for training set: 0.814699
             precision    recall  f1-score   support

      False       0.72      0.79      0.75       179
       True       0.70      0.62      0.65       141

avg / total       0.71      0.71      0.71       320

所有的這些度量值都提升了0.1,提高了16%,太顯著了!從上面可以看出,在縮放數據之前,有許多不同量級範圍的預測變量,意味着它們其中的一或兩個在算法中占主導地位,比如k-NN。縮放數據的兩個主要原因是:

  1. 預測變量可能包含非常不同的範圍,並且在某些情況下,比如使用k-NN時,這些變量值需要進行削減以免某些特徵在算法中占主導地位;
  2. 你希望你的特徵是單位獨立的,也就是說,不涉及單位度量:例如,你可能有一些以米爲單位的特徵,我可能有用釐米表示的同樣的特徵。如果我們各自縮放數據,這些特徵對我們來說都會是一樣的。

我們已經通過縮放和中心化預處理形式知道了數據科學管道中的關鍵部分,並且我們通過這些方法改進了機器學習問題時使用到的方法。在以後的文章中,我希望將此話題延伸到其他類型的預處理,比如數值數據的變換和分類數據的預處理,它們都是數據科學家工具箱中不可或缺的方式。在此之前,下一篇文章我將介紹縮放在用於分類的迴歸模型中的作用。我將分析邏輯迴歸,你將會發現這個結果與剛纔在k-NN中看到的結果截然不同。

在下面的交互式窗口中,你可以玩轉你的數據。首先改變變量n_neig的值,它表示的是k-NN算法中質心的個數。同樣如果你願意的話,你可以通過設定sc=True來縮放數據。然後運行整個腳本來得到模型的準確率報告和分類報告。

# Set the the number of neighbors for k-NN
n_neig = 5

# Set sc = True if you want to scale your features
sc = False

# Load data
df = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv ' , sep = ';')
X = df.drop('quality' , 1).values # drop target variable

# Here we scale, if desired
if sc == True:
X = scale(X)

# Target value
y1 = df['quality'].values # original target variable
y = y1 <= 5 # new target variable: is the rating <= 5?

# Split the data into a test set and a training set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Train k-NN model and print performance on the test set
knn = neighbors.KNeighborsClassifier(n_neighbors = n_neig)
knn_model = knn.fit(X_train, y_train)
y_true, y_pred = y_test, knn_model.predict(X_test)
print('k-NN accuracy for test set: %f' % knn_model.score(X_test, y_test))
print(classification_report(y_true, y_pred))
<script.py> output:
    k-NN accuracy for test set: 0.612500
                 precision    recall  f1-score   support

          False       0.66      0.64      0.65       179
           True       0.56      0.57      0.57       141

    avg / total       0.61      0.61      0.61       320

術語表

監督式學習(Supervised learning):從預測變量中推斷目標變量。比如從“年齡”,“性別”和“是否吸菸”這樣的預測變量中推斷目標變量“患心臟病”。

分類任務(Classfication task):如果目標變量包含類別(比如“點擊”或“不是”,“惡性”或“良性”腫瘤),那麼這種監督式學習任務就是一個分類任務。

迴歸任務(Regression task):如果目標變量包含連續變化變量(比如房屋價格)或是有序的分類變量,比如“紅酒質量級別”,那麼這種監督式學習任務就是一個迴歸任務。

K近鄰(k-Nearest Neighbors):分類任務的一種算法,一個數據點的標籤由離它最近的k個質心投票決定。

預處理:數據科學家會使用的任何操作,將原始數據轉換成更適合他們工作的形式。例如,在對推特數據進行情感分析之前,你可能想去掉所有的HTML標籤,空格,展開縮寫詞,將推文分割成詞彙列表。

中心化和縮放:這都是數值數據預處理方式,這些數據包含數字,而不是類別或字符;對一個變量進行中心化就是減去所有數據點的平均值,讓新變量的平均值爲0;縮放變量就是對每個數據點乘以一個常數來改變數據的範圍。想知道這些操作的重要性,參見全文以及案例。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章