Chapter 2 End-to-End Machine Learning Project

在這一章,你將會走完一個完整的機器學習項目。主要步驟如下:

  1. 對所需解決的問題有一個總體的思路

2. 獲取數據

3. 通過數據可視化來得到對數據潛在規律的一些思考

4. 在訓練模型之前先對數據進行預處理

5. 選擇一個合適的模型進行訓練

6. 調整並找到最合適的模型參數

7. 長期監督並維護你的學習系統

上一篇寫了1和2,這篇來寫後面的。(怎麼感覺這篇也寫不完???哈哈哈算了先寫著吧)

3. 通過數據可視化來得到對數據潛在規律的一些思考:

上一篇文章我們已經對數據集有了大致的了解,第三步我們要做的是把測試集扔在一邊不要管,然後來探索一下訓練集的數據潛在邏輯,我們複製一份訓練集數據以免破壞原數據:

housing = strat_train_set.copy()

我們觀察到數據集中包含了一個地理信息(經緯度),讓我們可視化來看看:

這樣其實還是不好分辨他的分布規律,我們可以設置參數 alpha:

我這裡的 alpha 設置的是0.2,原書是0.1,大家可以自己試試別的數值,越接近零,透明度越高;設置了 alpha 以後,分布規律就變得很顯然了,顏色深的地方密度更大。

現在我們加入更多的屬性來看,設置每個圓點半徑表示某地區的人口,圓點顏色表示房價,用一個定義好的colormap(jet)來表示房價的高低:

這一輪探索讓我們發現房價跟地理位置以及人口數量的關係。

接下來我們進一步探索屬性之間的相關性,可以用 corr() 方法來簡單的計算 Pearson 相關係數,然後查看每個屬性與房價的相關性:

能看到中值收入(median_income)跟房價的相關性很高。

另一種查看相關性的方法是用 Pandas 庫的 scatter_matrix 函數,它會畫出每個數值型屬性之間的散點圖,因為屬性太多,我們只選擇幾個相關度較高的屬性來進一步探索:

對角線上如果畫出散點圖應該是一條直線,就沒什麼意義,所以 Pandas 就畫出該屬性的直方圖來替代。從上面的散點圖來看,很顯然是中值收入(median_income)跟房價的相關性最高,所以接下來我們專註於這一個屬性來進行探索:

可以看到收入和房價的相關度很高,散點圖中點比較聚集,呈現正向趨勢;並且房價有一個很明顯的上限在 $500000 左右,除此之外,其實我們也能發現在 $450000 和 $350000 的位置也有一條水平線,後來的這兩條水平線很有可能是我們想要消除的數據噪音,這一點有待大家深入探索。

在進行數據預處理前我們的最後一步是嘗試去組合出新的特徵,在這個例子中,我們可能會想要用總房間數(total_rooms)和房屋數(households)組合出每個房屋的房間數量(rooms_per_household),還有類似的每個房間的卧室數量(bedrooms_per_room),每個房屋的人數(population_per_household)等,下面我們來嘗試組合出這些特徵並查看分析他們與房價的相關性:

看起來還不錯,新特徵每個房間的卧室數量(bedrooms_per_room)與房價的相關度比房間總數以及卧室總數都要高,呈現的是負相關;每個房屋的房間數量(rooms_per_household)與房價的相關度也明顯比組合前要高。

4. 在訓練模型之前先對數據進行預處理:

處理之前我們先把訓練集的特徵和標籤(房價)分離開:

housing = strat_train_set.drop("median_house_value", axis=1)
housing_labels = strat_train_set["median_house_value"].copy()

之前我們發現屬性 total_bedrooms 有一些空值,我們有三個方法來解決這個問題;一是刪除有空值的行,二是刪除有空值的列(這裡就是刪除total_bedrooms這一列),三是給空值填充一些合適的值(例如零值、平均值、中值等):

housing.dropna(subset=["total_bedrooms"]) #方法一 刪除有空值的行
housing.drop("total_bedrooms",axis=1) #方法二 刪除有空值的列
median = housing["total_bedrooms"].median()
housing["total_bedrooms"].fillna(median) #方法三 給空值填充一些合適的值

如果我們選擇第三種方法,要記得把中值保存以便後續給測試集填充。

sklearn 提供了一個類 Imputer 讓我們更方便的填充空值:

我們可以看到,我們先是創建了一個類 Imputer,然後用它去 fit 我們的數據集,fit 以後的這個 Imputer 就從數據集中學習到了一些參數,這時候就可以用來 transform 了;這是 sklearn 庫的統一的介面設計。

transform 之後我們得到的值是 Numpy 的 array 類型,我們可以轉化成 Pandas 的 Dataframe 類型:

housing_tr = pd.DataFrame(X, colums=housing_num.colums)

接下來我們來看一下怎麼處理文本型或者確定類別型屬性。

我們需要先把這些屬性轉化成數值,sklearn 提供了 LabelEncoder 類:

這個例子中,』<1H OCEAN』 被編碼為0,INLAND』為1,ISLAND』為2,NEAR BAY』為3,『NEAR OCEAN』為4。

但是用這個方法有個問題,機器學習演算法通常認為數值相近表示這兩個屬性相似,但事實上用以上方法編碼並不能表示這一點;sklearn 提供了另一個類 OneHotEncoder 來做二分類解決這個問題,它使用的是獨熱編碼(one-hot encoding),它編碼出來的是一個矩陣:

我們得到的是一個稀疏矩陣,每行只有一個1,表示在這個位置的值是存在的,其他都是零表示其他都不存在。例如第一行就表示』<1H OCEAN』為1,『INLAND』、』『ISLAND』、『NEAR BAY』、NEAR OCEAN』都為0。

sklearn 還提供了一個類可以一步解決上面的兩步:

雖然 sklearn 提供了很多轉換函數(transformers),但有時我們還是需要自定義我們自己的 transformer,比如之前我們嘗試的構造新的屬性或者自定義的數據清洗。為了跟 sklearn 其他類或函數無縫結合(可以互相調用),我們自定義的類應該包含三個方法:fit(),transform(),fit_transform()(如果你使用 TransformerMixin 作為基類就可以不用手動定義第三個方法 fit_transform),同時也建議使用 BaseEstimator 作為基類,那你就會獲得兩個方法(get_params() 和 set_params()),這兩個方法能幫助你調節超參數。現在,讓我們來自定義一個類組合出新的特徵:

這個類即實現了我們之前嘗試的三個新組合的特徵:每個房屋的房間數量(rooms_per_household),每個房間的卧室數量(bedrooms_per_room),每個房屋的人數(population_per_household)。在這裡我們的超參數是是否要添加新特徵每個房間的卧室數量(bedrooms_per_room),你還可以設置其他超參數,大家可以自由探索。

接下來是數據預處理里最重要的一步轉換:特徵縮放(feature scaling)。由於不同特徵有不同的尺度,機器學習演算法面對這些不同尺度的特徵總是不能表現的很好;比如,在本書的房價預測例子中,總房間數尺度為6-39320,而中值收入的尺度為0-15;我們需要使得這些特徵尺度一致,才能讓我們的演算法更好的做預測。

Min-Max 歸一化是比較簡單的一種,數值被線性的縮放到0-1;sklearn 提供了一個類 MinMaxScaler 實現這個轉換,你可以調節超參數 feature_range 實現別的範圍(如果你不想要0-1)。

標準化(standardization)可以使得特徵值的平均值為零,並且方差為單位方差。標準化不會把值限制在0-1,這有時候可能是個問題(神經網路常常需要0-1的輸入值);但標準化是更穩固的,他不容易受到異常值的影響,所以標準化應用相對廣泛些。

最後,我們可以利用 sklearn 提供的 Pipeline 類把之前做的所有的數據預處理過程封裝為一個轉換流程(原書寫的是 transformation pipeline,我也不知道該怎麼翻譯合適,大家明白就好)。下面給了一個例子,把之前我們提的三個過程封裝起來了(用中值填充特徵空值,組合出新的特徵,標準化特徵):

在這個 pipeline 里,你開始 fit 的時候,他就會按照順序首先訓練第一個 tranformer 並把參數傳給下一個,依次進行。

這樣你可以一次性處理完所有的數值型特徵,但是如果你要同時處理類別型特徵呢?sklearn 提供了一個 FeatureUnion 類,它允許你把多個 transformer 或 pipeline 組合起來,調用 transform 的時候所有的 transformer 會同時運行,等結果出來以後再將所有的結果連接起來。下面的例子是把我們之前的數值型的 pipeline 和類別型的編碼轉換器組合起來:

這篇寫完了3和4啦,下篇應該是真的可以寫完這一章了。。。


推薦閱讀:
相关文章