《Scikit-Learn與TensorFlow機(jī)器學(xué)習(xí)實(shí)用指南》 第02章 一個(gè)完整的機(jī)器學(xué)習(xí)項(xiàng)目(上)


(第一部分 機(jī)器學(xué)習(xí)基礎(chǔ))
第01章 機(jī)器學(xué)習(xí)概覽
第02章 一個(gè)完整的機(jī)器學(xué)習(xí)項(xiàng)目(上)
第02章 一個(gè)完整的機(jī)器學(xué)習(xí)項(xiàng)目(下)
第03章 分類(lèi)
第04章 訓(xùn)練模型
第05章 支持向量機(jī)
第06章 決策樹(shù)
第07章 集成學(xué)習(xí)和隨機(jī)森林
第08章 降維
(第二部分 神經(jīng)網(wǎng)絡(luò)和深度學(xué)習(xí))
第9章 啟動(dòng)和運(yùn)行TensorFlow
第10章 人工神經(jīng)網(wǎng)絡(luò)
第11章 訓(xùn)練深度神經(jīng)網(wǎng)絡(luò)(上)
第11章 訓(xùn)練深度神經(jīng)網(wǎng)絡(luò)(下)
第12章 設(shè)備和服務(wù)器上的分布式 TensorFlow
第13章 卷積神經(jīng)網(wǎng)絡(luò)
第14章 循環(huán)神經(jīng)網(wǎng)絡(luò)
第15章 自編碼器
第16章 強(qiáng)化學(xué)習(xí)(上)
第16章 強(qiáng)化學(xué)習(xí)(下)


本章中,你會(huì)作為被一家地產(chǎn)公司雇傭的數(shù)據(jù)科學(xué)家,完整地學(xué)習(xí)一個(gè)項(xiàng)目。下面是主要步驟:

  1. 項(xiàng)目概述。
  2. 獲取數(shù)據(jù)。
  3. 發(fā)現(xiàn)并可視化數(shù)據(jù),發(fā)現(xiàn)規(guī)律。
  4. 為機(jī)器學(xué)習(xí)算法準(zhǔn)備數(shù)據(jù)。
  5. 選擇模型,進(jìn)行訓(xùn)練。
  6. 微調(diào)模型。
  7. 給出解決方案。
  8. 部署、監(jiān)控、維護(hù)系統(tǒng)。

使用真實(shí)數(shù)據(jù)

學(xué)習(xí)機(jī)器學(xué)習(xí)時(shí),最好使用真實(shí)數(shù)據(jù),而不是人工數(shù)據(jù)集。幸運(yùn)的是,有上千個(gè)開(kāi)源數(shù)據(jù)集可以進(jìn)行選擇,涵蓋多個(gè)領(lǐng)域。以下是一些可以查找數(shù)據(jù)的資源:

本章,我們選擇的是StatLib的加州房產(chǎn)價(jià)格數(shù)據(jù)集(見(jiàn)圖2-1)。這個(gè)數(shù)據(jù)集是基于1990年加州普查的數(shù)據(jù)。數(shù)據(jù)已經(jīng)有點(diǎn)老(1990年還能買(mǎi)一個(gè)灣區(qū)不錯(cuò)的房子),但是它有許多優(yōu)點(diǎn),利于學(xué)習(xí),所以假設(shè)這個(gè)數(shù)據(jù)為最新的。為了便于教學(xué),我們添加了一個(gè)分類(lèi)屬性,并除去了一些屬性。

圖2-1 加州房產(chǎn)價(jià)格

項(xiàng)目概覽

歡迎來(lái)到機(jī)器學(xué)習(xí)房地產(chǎn)公司!你的第一個(gè)任務(wù)是利用加州普查數(shù)據(jù),建立一個(gè)加州房?jī)r(jià)模型。這個(gè)數(shù)據(jù)包含每個(gè)分區(qū)組的人口、收入中位數(shù)、房?jī)r(jià)中位數(shù)等指標(biāo)。

分區(qū)組是美國(guó)調(diào)查局發(fā)布樣本數(shù)據(jù)的最小地理單位(一個(gè)分區(qū)通常有600到3000人)。我們將其簡(jiǎn)稱(chēng)為“分區(qū)”。

你的模型要利用這個(gè)數(shù)據(jù)進(jìn)行學(xué)習(xí),然后根據(jù)其它指標(biāo),預(yù)測(cè)任何分區(qū)的的房?jī)r(jià)中位數(shù)。

提示:你是一個(gè)有條理的數(shù)據(jù)科學(xué)家,你要做的第一件事是拿出你的機(jī)器學(xué)習(xí)項(xiàng)目清單。你可以使用附錄B中的清單;這個(gè)清單適用于大多數(shù)的機(jī)器學(xué)習(xí)項(xiàng)目,但是你還是要確認(rèn)它是否滿足需求。在本章中,我們會(huì)檢查許多清單上的項(xiàng)目,但是也會(huì)跳過(guò)一些簡(jiǎn)單的,有些會(huì)在后面的章節(jié)再討論。

劃定問(wèn)題

詢(xún)問(wèn)老板的第一個(gè)問(wèn)題應(yīng)該是商業(yè)目標(biāo)是什么?建立模型可能不是最終目標(biāo)。公司要如何使用、并從模型受益?這非常重要,因?yàn)樗鼪Q定了如何劃定問(wèn)題,要選擇什么算法,評(píng)估模型性能的指標(biāo)是什么,要花多少精力進(jìn)行微調(diào)。

老板告訴你,你的模型的輸出(一個(gè)區(qū)的房?jī)r(jià)中位數(shù))會(huì)傳給另一個(gè)機(jī)器學(xué)習(xí)系統(tǒng)(見(jiàn)圖2-2),也有其它信號(hào)會(huì)傳入后面的系統(tǒng)。這一整套系統(tǒng)可以確定對(duì)某個(gè)區(qū)投資值不值。確定投資與否非常重要,它直接影響利潤(rùn)。

圖2-2 房地產(chǎn)投資的機(jī)器學(xué)習(xí)管道

管道

一系列的數(shù)據(jù)處理組件被稱(chēng)為數(shù)據(jù)管道。管道在機(jī)器學(xué)習(xí)系統(tǒng)中很常見(jiàn),因?yàn)橛性S多數(shù)據(jù)要處理和轉(zhuǎn)換。

組件通常是異步運(yùn)行的。每個(gè)組件吸納進(jìn)大量數(shù)據(jù),進(jìn)行處理,然后將數(shù)據(jù)傳輸?shù)搅硪粋€(gè)數(shù)據(jù)容器中,而后管道中的另一個(gè)組件收入這個(gè)數(shù)據(jù),然后輸出,這個(gè)過(guò)程依次進(jìn)行下去。每個(gè)組件都是獨(dú)立的:組件間的接口只是數(shù)據(jù)容器。這樣可以讓系統(tǒng)更便于理解(記住數(shù)據(jù)流的圖),不同的項(xiàng)目組可以關(guān)注于不同的組件。進(jìn)而,如果一個(gè)組件失效了,下游的組件使用失效組件最后生產(chǎn)的數(shù)據(jù),通??梢哉_\(yùn)行(一段時(shí)間)。這樣就使整個(gè)架構(gòu)相當(dāng)健壯。

另一方面,如果沒(méi)有監(jiān)控,失效的組件會(huì)在不被注意的情況下運(yùn)行一段時(shí)間。數(shù)據(jù)會(huì)受到污染,整個(gè)系統(tǒng)的性能就會(huì)下降。

下一個(gè)要問(wèn)的問(wèn)題是,現(xiàn)在的解決方案效果如何。老板通常會(huì)給一個(gè)參考性能,以及如何解決問(wèn)題。老板說(shuō),現(xiàn)在分區(qū)的房?jī)r(jià)是靠專(zhuān)家手工估計(jì)的,專(zhuān)家隊(duì)伍收集最新的關(guān)于一個(gè)區(qū)的信息(不包括房?jī)r(jià)中位數(shù)),他們使用復(fù)雜的規(guī)則進(jìn)行估計(jì)。這種方法費(fèi)錢(qián)費(fèi)時(shí)間,而且估計(jì)結(jié)果不理想,誤差率大概有15%。

Okay,有了這些信息,你就可以開(kāi)始設(shè)計(jì)系統(tǒng)了。首先,你需要?jiǎng)澏▎?wèn)題:監(jiān)督或非監(jiān)督,還是強(qiáng)化學(xué)習(xí)?這是個(gè)分類(lèi)任務(wù)、回歸任務(wù),還是其它的?要使用批量學(xué)習(xí)還是線上學(xué)習(xí)?繼續(xù)閱讀之前,請(qǐng)暫停一下,嘗試自己回答下這些問(wèn)題。

你能回答出來(lái)嗎?一起看下答案:很明顯,這是一個(gè)典型的監(jiān)督學(xué)習(xí)任務(wù),因?yàn)槟阋褂玫氖怯袠?biāo)簽的訓(xùn)練樣本(每個(gè)實(shí)例都有預(yù)定的產(chǎn)出,即分區(qū)的房?jī)r(jià)中位數(shù))。并且,這是一個(gè)典型的回歸任務(wù),因?yàn)槟阋A(yù)測(cè)一個(gè)值。講的更細(xì)些,這是一個(gè)多變量回歸問(wèn)題,因?yàn)橄到y(tǒng)要使用多個(gè)變量進(jìn)行預(yù)測(cè)(要使用分區(qū)的人口,收入中位數(shù)等等)。在第一章中,你只是根據(jù)人均GDP來(lái)預(yù)測(cè)生活滿意度,因此這是一個(gè)單變量回歸問(wèn)題。最后,沒(méi)有連續(xù)的數(shù)據(jù)流進(jìn)入系統(tǒng),沒(méi)有特別需求需要對(duì)數(shù)據(jù)變動(dòng)作出快速適應(yīng)。數(shù)據(jù)量不大可以放到內(nèi)存中,因此批量學(xué)習(xí)就夠了。

提示:如果數(shù)據(jù)量很大,你可以要么在多個(gè)服務(wù)器上對(duì)批量學(xué)習(xí)做拆分(使用MapReduce技術(shù),后面會(huì)看到),或是使用線上學(xué)習(xí)。

選擇性能指標(biāo)

下一步是選擇性能指標(biāo)?;貧w問(wèn)題的典型指標(biāo)是均方根誤差(RMSE)。均方根誤差測(cè)量的是系統(tǒng)預(yù)測(cè)誤差的標(biāo)準(zhǔn)差。例如,RMSE等于50000,意味著,68%的系統(tǒng)預(yù)測(cè)值位于實(shí)際值的50000以?xún)?nèi)。95%的預(yù)測(cè)值位于實(shí)際值的100000以?xún)?nèi)。等式2-1展示了計(jì)算RMSE的方法。

等式2-1 均方根誤差(RMSE)

符號(hào)的含義

這個(gè)方程引入了一些常見(jiàn)的貫穿本書(shū)的機(jī)器學(xué)習(xí)符號(hào):

  • m是測(cè)量RMSE的數(shù)據(jù)集中的實(shí)例數(shù)量。
    例如,如果用一個(gè)含有2000個(gè)分區(qū)的驗(yàn)證集求RMSE,則m = 2000。
  • x(i)是數(shù)據(jù)集第ith個(gè)實(shí)例的所有特征值(不包含標(biāo)簽)的矢量,y(i)是它的標(biāo)簽(這個(gè)實(shí)例的輸出值)。
    例如,如果數(shù)據(jù)集中的第一個(gè)分區(qū)位于經(jīng)度–118.29°,緯度33.91°,有1416名居民,收入中位數(shù)是38372美元,房?jī)r(jià)中位數(shù)是$156400(不考慮其它特征),則有:

    和,
  • X是包含數(shù)據(jù)集中所有實(shí)例的所有特征值(不包含標(biāo)簽)的矩陣。每一行是一個(gè)實(shí)例,第ith行是x(i)的轉(zhuǎn)置,標(biāo)記為(x(i))T
    例如,仍然是前面的第一區(qū),矩陣X就是:
  • h是系統(tǒng)的預(yù)測(cè)函數(shù),也稱(chēng)為假設(shè)(hypothesis)。當(dāng)系統(tǒng)收到一個(gè)實(shí)例的特征矢量x(i),就會(huì)輸出這個(gè)實(shí)例的一個(gè)預(yù)測(cè)值?(i) = h(x(i))(?讀作y-hat)。
    例如,如果系統(tǒng)預(yù)測(cè)第一區(qū)的房?jī)r(jià)中位數(shù)是$158400,則?(1) = h(x(1)) = 158400。預(yù)測(cè)誤差是?(1) – y(1) = 2000。
    RMSE(X,h)是使用假設(shè)h在樣本集上測(cè)量的損失函數(shù)。

我們使用小寫(xiě)斜體表示標(biāo)量值(例如my(1))和函數(shù)名(例如h),小寫(xiě)粗體表示矢量(例如x(i)),大寫(xiě)粗體表示矩陣(例如X)。(譯者注:MarkDown表示粗體斜體太麻煩了,忽略字體。)

雖然大多數(shù)時(shí)候RMSE是回歸任務(wù)可靠的性能指標(biāo),在有些情況下,你可能需要另外的函數(shù)。例如,假設(shè)存在許多異常的分區(qū)。此時(shí),你可能需要使用絕對(duì)平均誤差(Mean Absolute Error,也稱(chēng)作平均絕對(duì)偏差,見(jiàn)等式2-2):

等式 絕對(duì)平均誤差

RMSE和MAE都是測(cè)量預(yù)測(cè)值和目標(biāo)值兩個(gè)矢量距離的方法。有多種測(cè)量距離的方法,或范數(shù):

  • 計(jì)算對(duì)應(yīng)歐幾里得范數(shù)的平方和的根(RMSE):這個(gè)距離介紹過(guò)。它也稱(chēng)作?2范數(shù),標(biāo)記為// · //2(或只是// · //)。

  • 計(jì)算對(duì)應(yīng)于?1(標(biāo)記為// · //1)范數(shù)的絕對(duì)值之和(MAE)。有時(shí),也稱(chēng)其為曼哈頓范數(shù),因?yàn)樗鼫y(cè)量了城市中的兩點(diǎn),沿著矩形的邊行走的距離。

  • 更一般的,包含n個(gè)元素的矢量v的?k范數(shù),定義成


    ?0只顯示了這個(gè)矢量的基數(shù)(即,元素的個(gè)數(shù)),?是矢量中最大的絕對(duì)值。

  • 范數(shù)的指數(shù)越高,就越關(guān)注大的值而忽略小的值。這就是為什么RMSE比MAE對(duì)異常值更敏感。但是當(dāng)異常值是指數(shù)分布的(類(lèi)似正態(tài)曲線),RMSE就會(huì)表現(xiàn)很好。

核實(shí)假設(shè)

最后,最好列出并核對(duì)迄今(你或其他人)作出的假設(shè)。這樣可以盡早發(fā)現(xiàn)嚴(yán)重的問(wèn)題。例如,你的系統(tǒng)輸出的分區(qū)房?jī)r(jià),會(huì)傳入到下游的機(jī)器學(xué)習(xí)系統(tǒng),我們假設(shè)這些價(jià)格確實(shí)會(huì)被當(dāng)做分區(qū)房?jī)r(jià)使用。但是如果下游系統(tǒng)實(shí)際上將價(jià)格轉(zhuǎn)化成了分類(lèi)(例如,便宜、中等、昂貴),然后使用這些分類(lèi),而不是使用價(jià)格。這樣的話,獲得準(zhǔn)確的價(jià)格就不那么重要了,你只需要得到合適的分類(lèi)。問(wèn)題相應(yīng)地就變成了一個(gè)分類(lèi)問(wèn)題,而不是回歸任務(wù)。你可不想在一個(gè)回歸系統(tǒng)上工作了數(shù)月,最后才發(fā)現(xiàn)真相。

幸運(yùn)的是,在與下游系統(tǒng)主管探討之后,你很確信他們需要的就是實(shí)際的價(jià)格,而不是分類(lèi)。很好!整裝待發(fā),可以開(kāi)始寫(xiě)代碼了。

獲取數(shù)據(jù)

開(kāi)始動(dòng)手。最后用Jupyter notebook完整地敲一遍示例代碼。完整的代碼位于https://github.com/ageron/handson-ml。

創(chuàng)建工作空間

首先,你需要安裝Python。可能已經(jīng)安裝過(guò)了,沒(méi)有的話,可以從官網(wǎng)下載https://www.python.org/。

接下來(lái),需要為你的機(jī)器學(xué)習(xí)代碼和數(shù)據(jù)集創(chuàng)建工作空間目錄。打開(kāi)一個(gè)終端,輸入以下命令(在提示符$之后):

$ export ML_PATH="$HOME/ml"      # 可以更改路徑
$ mkdir -p $ML_PATH

還需要一些Python模塊:Jupyter、NumPy、Pandas、Matplotlib和Scikit-Learn。如果所有這些模塊都已經(jīng)在Jupyter中運(yùn)行了,你可以直接跳到下一節(jié)“下載數(shù)據(jù)”。如果還沒(méi)安裝,有多種方法可以進(jìn)行安裝(包括它們的依賴(lài))。你可以使用系統(tǒng)的包管理系統(tǒng)(比如Ubuntu上的apt-get,或macOS上的MacPorts或HomeBrew),安裝一個(gè)Python科學(xué)計(jì)算環(huán)境比如Anaconda,使用Anaconda的包管理系統(tǒng),或者使用Python自己的包管理器pip,它是Python安裝包(自從2.7.9版本)自帶的??梢杂孟旅娴拿顧z測(cè)是否安裝pip:

$ pip3 --version
pip 9.0.1 from [...]/lib/python3.5/site-packages (python 3.5)

你需要保證pip是近期的版本,至少高于1.4,以保障二進(jìn)制模塊文件的安裝(也成為wheels)。要升級(jí)pip,可以使用下面的命令:

$ pip3 install --upgrade pip
Collecting pip
[...]
Successfully installed pip-9.0.1

創(chuàng)建獨(dú)立環(huán)境

如果你希望在一個(gè)獨(dú)立環(huán)境中工作(強(qiáng)烈推薦這么做,不同項(xiàng)目的庫(kù)的版本不會(huì)沖突),用下面的pip命令安裝virtualenv:

$ pip3 install --user --upgrade virtualenv
Collecting virtualenv
[...]
Successfully installed virtualenv

現(xiàn)在可以通過(guò)下面命令創(chuàng)建一個(gè)獨(dú)立的Python環(huán)境:

$ cd $ML_PATH
$ virtualenv env
Using base prefix '[...]'
New python executable in [...]/ml/env/bin/python3.5
Also creating executable in [...]/ml/env/bin/python
Installing setuptools, pip, wheel...done.

以后每次想要激活這個(gè)環(huán)境,只需打開(kāi)一個(gè)終端然后哦輸入:

$ cd $ML_PATH
$ source env/bin/activate

啟動(dòng)該環(huán)境時(shí),使用pip安裝的任何包都只安裝于這個(gè)獨(dú)立環(huán)境中,Python只會(huì)訪問(wèn)這些包(如果你希望Python能訪問(wèn)系統(tǒng)的包,創(chuàng)建環(huán)境時(shí)要使用包選項(xiàng)--system-site-)。更多信息,請(qǐng)查看virtualenv文檔。

現(xiàn)在,你可以使用pip命令安裝所有必需的模塊和它們的依賴(lài):

$ pip3 install --upgrade jupyter matplotlib numpy pandas scipy scikit-learn
Collecting jupyter
  Downloading jupyter-1.0.0-py2.py3-none-any.whl
Collecting matplotlib
  [...]

要檢查安裝,可以用下面的命令引入每個(gè)模塊:

$ python3 -c "import jupyter, matplotlib, numpy, pandas, scipy, sklearn"

這個(gè)命令不應(yīng)該有任何輸出和錯(cuò)誤?,F(xiàn)在你可以用下面的命令打開(kāi)Jupyter:

$ jupyter notebook
[I 15:24 NotebookApp] Serving notebooks from local directory: [...]/ml
[I 15:24 NotebookApp] 0 active kernels
[I 15:24 NotebookApp] The Jupyter Notebook is running at: http://localhost:8888/
[I 15:24 NotebookApp] Use Control-C to stop this server and shut down all
kernels (twice to skip confirmation).

Jupyter服務(wù)器現(xiàn)在運(yùn)行在終端上,監(jiān)聽(tīng)8888端口。你可以用瀏覽器打開(kāi)http://localhost:8888/,以訪問(wèn)這個(gè)服務(wù)器(服務(wù)器啟動(dòng)時(shí),通常就自動(dòng)打開(kāi)了)。你可以看到一個(gè)空的工作空間目錄(如果按照先前的virtualenv步驟,只包含env目錄)。

現(xiàn)在點(diǎn)擊按鈕New創(chuàng)建一個(gè)新的Python筆記本,選擇合適的Python版本(見(jiàn)圖2-3)。

圖2-3 Jupyter的工作空間

這一步做了三件事:首先,在工作空間中創(chuàng)建了一個(gè)新的notebook文件Untitled.ipynb;第二,它啟動(dòng)了一個(gè)Jupyter的Python內(nèi)核來(lái)運(yùn)行這個(gè)notebook;第三,在一個(gè)新欄中打開(kāi)這個(gè)notebook。接下來(lái),點(diǎn)擊Untitled,將這個(gè)notebook重命名為Housing(這會(huì)將ipynb文件自動(dòng)命名為Housing.ipynb)。

notebook包含一組代碼框。每個(gè)代碼框可以放入可執(zhí)行代碼或格式化文本?,F(xiàn)在,notebook只有一個(gè)空的代碼框,標(biāo)簽是“In [1]:”。在框中輸入print("Hello world!"),點(diǎn)擊運(yùn)行按鈕(見(jiàn)圖2-4)或按Shift+Enter。這會(huì)將當(dāng)前的代碼框發(fā)送到Python內(nèi)核,運(yùn)行之后會(huì)返回輸出。結(jié)果顯示在代碼框下方。由于抵達(dá)了notebook的底部,一個(gè)新的代碼框會(huì)被自動(dòng)創(chuàng)建出來(lái)。從Jupyter的Help菜單中的User Interface Tour可以學(xué)習(xí)Jupyter的基本操作。

圖2-4 在notebook中打印Hello world!

下載數(shù)據(jù)

一般情況下,數(shù)據(jù)是存儲(chǔ)于關(guān)系型數(shù)據(jù)庫(kù)(或其它常見(jiàn)數(shù)據(jù)庫(kù))中的多個(gè)表、文檔、文件。要訪問(wèn)數(shù)據(jù),你首先要有密碼和登錄權(quán)限,并要了解數(shù)據(jù)結(jié)構(gòu)。但是在這個(gè)項(xiàng)目中,這一切要簡(jiǎn)單些:只要下載一個(gè)壓縮文件,housing.tgz,它包含一個(gè)CSV文件housing.csv,含有所有數(shù)據(jù)。

你可以使用瀏覽器下載,運(yùn)行tar xzf housing.tgz解壓提取出csv文件,但是更好的辦法是寫(xiě)一個(gè)小函數(shù)來(lái)做這件事。如果數(shù)據(jù)變動(dòng)頻繁,這么做是非常好的,因?yàn)榭梢宰屇銓?xiě)一個(gè)小腳本隨時(shí)獲取最新的數(shù)據(jù)(或者創(chuàng)建一個(gè)定時(shí)任務(wù)來(lái)做)。如果你想在多臺(tái)機(jī)器上安裝數(shù)據(jù)集,獲取數(shù)據(jù)自動(dòng)化也是非常好的。

下面是獲取數(shù)據(jù)的函數(shù):

import os
import tarfile
from six.moves import urllib

DOWNLOAD_ROOT = "https://raw.githubusercontent.com/ageron/handson-ml/master/"
HOUSING_PATH = "datasets/housing"
HOUSING_URL = DOWNLOAD_ROOT + HOUSING_PATH + "/housing.tgz"

def fetch_housing_data(housing_url=HOUSING_URL, housing_path=HOUSING_PATH):
    if not os.path.isdir(housing_path):
        os.makedirs(housing_path)
    tgz_path = os.path.join(housing_path, "housing.tgz")
    urllib.request.urlretrieve(housing_url, tgz_path)
    housing_tgz = tarfile.open(tgz_path)
    housing_tgz.extractall(path=housing_path)
    housing_tgz.close()

現(xiàn)在,當(dāng)你調(diào)用fetch_housing_data(),就會(huì)在工作空間創(chuàng)建一個(gè)datasets/housing目錄,下載housing.tgz文件,提取出housing.csv。

然后使用Pandas加載數(shù)據(jù)。還是用一個(gè)小函數(shù)來(lái)加載數(shù)據(jù):

import pandas as pd

def load_housing_data(housing_path=HOUSING_PATH):
    csv_path = os.path.join(housing_path, "housing.csv")
    return pd.read_csv(csv_path)

這個(gè)函數(shù)會(huì)返回一個(gè)包含所有數(shù)據(jù)的Pandas DataFrame對(duì)象。

快速查看數(shù)據(jù)結(jié)構(gòu)

使用DataFrame的head()方法查看該數(shù)據(jù)集的頂部5行(見(jiàn)圖2-5)。

圖2-5 數(shù)據(jù)集的頂部五行

每一行都表示一個(gè)分區(qū)。共有10個(gè)屬性(截圖中可以看到6個(gè)):經(jīng)度、維度、房屋年齡中位數(shù)、總房間數(shù)、臥室數(shù)量、人口數(shù)、家庭數(shù)、收入中位數(shù)、房屋價(jià)值中位數(shù)、大海距離。

info()方法可以快速查看數(shù)據(jù)的描述,包括總行數(shù)、每個(gè)屬性的類(lèi)型和非空值的數(shù)量(見(jiàn)圖2-6)。

圖2-6 房屋信息

數(shù)據(jù)集中共有20640個(gè)實(shí)例,按照機(jī)器學(xué)習(xí)的標(biāo)準(zhǔn)這個(gè)數(shù)據(jù)量很小,但是非常適合入門(mén)??偡块g數(shù)只有20433個(gè)非空值,意味著207個(gè)分區(qū)缺少這個(gè)值。后面要對(duì)它進(jìn)行處理。

所有的屬性都是數(shù)值的,除了大海距離這項(xiàng)。它的類(lèi)型是對(duì)象,因此可以包含任意Python對(duì)象,但是因?yàn)槭菑腃SV文件加載的,所以必然是文本。當(dāng)查看頂部的五行時(shí),你可能注意到那一列的值是重復(fù)的,意味著它可能是一個(gè)分類(lèi)屬性??梢允褂胿alue_counts()方法查看都有什么類(lèi)型,每個(gè)類(lèi)都有多少分區(qū):

>>> housing["ocean_proximity"].value_counts()
<1H OCEAN     9136
INLAND        6551
NEAR OCEAN    2658
NEAR BAY      2290
ISLAND           5
Name: ocean_proximity, dtype: int64

再來(lái)看其它字段。describe()方法展示了數(shù)值屬性的概括(見(jiàn)圖2-7)。

圖2-7 每個(gè)數(shù)值屬性的概括

count、mean、min和max幾行的意思很明了。注意,空值被忽略了(所以,臥室總數(shù)是20433而不是20640)。std是標(biāo)準(zhǔn)差(揭示數(shù)值的分散度)。25%、50%、75%展示了對(duì)應(yīng)的分位數(shù):每個(gè)分位數(shù)指明小于這個(gè)值,且指定分組的百分比。例如,25%的分區(qū)的房屋年齡中位數(shù)小于18,而50%的小于29,75%的小于37。這些值通常稱(chēng)為25th分位數(shù)(或1st四分位數(shù)),中位數(shù),75th分位數(shù)(3rd四分位數(shù))。

另一種快速了解數(shù)據(jù)類(lèi)型的方法是畫(huà)出每個(gè)數(shù)值屬性的柱狀圖。柱狀圖(的縱軸)展示了特定范圍的實(shí)例的個(gè)數(shù)。你還可以一次給一個(gè)屬性畫(huà)圖,或?qū)ν暾麛?shù)據(jù)集調(diào)用hist()方法,后者會(huì)畫(huà)出每個(gè)數(shù)值屬性的柱狀圖(見(jiàn)圖2-8)。例如,你可以看到略微超過(guò)800個(gè)分區(qū)的median_house_value值差不多等于$500000。

%matplotlib inline   # only in a Jupyter notebook
import matplotlib.pyplot as plt
housing.hist(bins=50, figsize=(20,15))
plt.show()
圖2-8 每個(gè)數(shù)值屬性的柱狀圖

筆記:hist()方法依賴(lài)于Matplotlib,后者依賴(lài)于用戶(hù)指定的圖形后端以打印到屏幕上。因此在畫(huà)圖之前,你要指定Matplotlib要使用的后端。最簡(jiǎn)單的方法是使用Jupyter的魔術(shù)命令%matplotlib inline。它會(huì)告訴Jupyter設(shè)定好Matplotlib,以使用Jupyter自己的后端。繪圖就會(huì)在notebook中渲染了。注意在Jupyter中調(diào)用show()不是必要的,因?yàn)榇a框執(zhí)行后Jupyter會(huì)自動(dòng)展示圖像。

注意柱狀圖中的一些點(diǎn):

  1. 首先,收入中位數(shù)貌似不是美元(USD)。與數(shù)據(jù)采集團(tuán)隊(duì)交流之后,你被告知數(shù)據(jù)是經(jīng)過(guò)縮放調(diào)整的,過(guò)高收入中位數(shù)的會(huì)變?yōu)?5(實(shí)際為15.0001),過(guò)低的會(huì)變?yōu)?(實(shí)際為0.4999)。在機(jī)器學(xué)習(xí)中對(duì)數(shù)據(jù)進(jìn)行預(yù)處理很正常,不一定是問(wèn)題,但你要明白數(shù)據(jù)是如何計(jì)算出來(lái)的。

  2. 房屋年齡中位數(shù)和房屋價(jià)值中位數(shù)也被設(shè)了上線。后者可能是個(gè)嚴(yán)重的問(wèn)題,因?yàn)樗悄愕哪繕?biāo)屬性(你的標(biāo)簽)。你的機(jī)器學(xué)習(xí)算法可能學(xué)習(xí)到價(jià)格不會(huì)超出這個(gè)界限。你需要與下游團(tuán)隊(duì)核實(shí),這是否會(huì)成為問(wèn)題。如果他們告訴你他們需要明確的預(yù)測(cè)值,即價(jià)格可以超過(guò)500000美元,你則有兩個(gè)選項(xiàng):
    a. 對(duì)于設(shè)了上限的標(biāo)簽,重新收集合適的標(biāo)簽;
    b. 將這些分區(qū)從訓(xùn)練集移除(也從測(cè)試集移除,因?yàn)槿舴績(jī)r(jià)超出$500000,你的系統(tǒng)就會(huì)被差評(píng))。

  3. 這些屬性值有不同的量度。我們會(huì)在本章后面討論特征縮放。

  4. 最后,許多柱狀圖的尾巴很長(zhǎng):相較于左邊,它們?cè)谥形粩?shù)的右邊延伸過(guò)遠(yuǎn)。對(duì)于某些機(jī)器學(xué)習(xí)算法,這會(huì)使檢測(cè)規(guī)律變得更難些。我們會(huì)在后面嘗試轉(zhuǎn)換處理這些屬性,使其變?yōu)檎植肌?/p>

希望你現(xiàn)在對(duì)要處理的數(shù)據(jù)有一定了解了。

警告:稍等!再你進(jìn)一步查看數(shù)據(jù)之前,你需要?jiǎng)?chuàng)建一個(gè)測(cè)試集,放在一旁,再也不看。

創(chuàng)建測(cè)試集

在這個(gè)階段就分割數(shù)據(jù),聽(tīng)起來(lái)很奇怪。畢竟,你只是簡(jiǎn)單快速地查看了數(shù)據(jù)而已,你需要再仔細(xì)調(diào)查下數(shù)據(jù)以決定使用什么算法。這么想是對(duì)的,但是人類(lèi)的大腦是一個(gè)神奇的發(fā)現(xiàn)規(guī)律的系統(tǒng),這意味著大腦非常容易發(fā)生過(guò)擬合:如果你查看了測(cè)試集,就會(huì)不經(jīng)意地按照測(cè)試集中的規(guī)律來(lái)選擇某個(gè)特定的機(jī)器學(xué)習(xí)模型。再當(dāng)你使用測(cè)試集來(lái)評(píng)估誤差率時(shí),就會(huì)導(dǎo)致評(píng)估過(guò)于樂(lè)觀,而實(shí)際部署的系統(tǒng)表現(xiàn)就會(huì)差。這稱(chēng)為數(shù)據(jù)透視偏差。

理論上,創(chuàng)建測(cè)試集很簡(jiǎn)單:只要隨機(jī)挑選一些實(shí)例,一般是數(shù)據(jù)集的20%,放到一邊:

import numpy as np

def split_train_test(data, test_ratio):
    shuffled_indices = np.random.permutation(len(data))
    test_set_size = int(len(data) * test_ratio)
    test_indices = shuffled_indices[:test_set_size]
    train_indices = shuffled_indices[test_set_size:]
    return data.iloc[train_indices], data.iloc[test_indices]

然后可以像下面使用這個(gè)函數(shù):

>>> train_set, test_set = split_train_test(housing, 0.2)
>>> print(len(train_set), "train +", len(test_set), "test")
16512 train + 4128 test

這個(gè)方法可行,但是并不完美:如果再次運(yùn)行程序,就會(huì)產(chǎn)生一個(gè)不同的測(cè)試集!多次運(yùn)行之后,你(或你的機(jī)器學(xué)習(xí)算法)就會(huì)得到整個(gè)數(shù)據(jù)集,這是需要避免的。

解決的辦法之一是保存第一次運(yùn)行得到的測(cè)試集,并在隨后的過(guò)程加載。另一種方法是在調(diào)用np.random.permutation()之前,設(shè)置隨機(jī)數(shù)生成器的種子(比如np.random.seed(42)),以產(chǎn)生總是相同的混合指數(shù)(shuffled indices)。

但是如果獲取更新后的數(shù)據(jù)集,這兩個(gè)方法都會(huì)失效。一個(gè)通常的解決辦法是使用每個(gè)實(shí)例的識(shí)別碼,以判定是否這個(gè)實(shí)例是否應(yīng)該放入測(cè)試集(假設(shè)實(shí)例有單一且不變的識(shí)別碼)。例如,你可以每個(gè)實(shí)例識(shí)別碼的哈希值,只保留其最后一個(gè)字節(jié),如果值小于等于51(約為256的20%),就將其放入測(cè)試集。這樣可以保證在多次運(yùn)行中,測(cè)試集保持不變,即使更新了數(shù)據(jù)集。新的測(cè)試集會(huì)包含新實(shí)例中的20%,但不會(huì)有之前位于訓(xùn)練集的實(shí)例。下面是一種可用的方法:

import hashlib

def test_set_check(identifier, test_ratio, hash):
    return hash(np.int64(identifier)).digest()[-1] < 256 * test_ratio

def split_train_test_by_id(data, test_ratio, id_column, hash=hashlib.md5):
    ids = data[id_column]
    in_test_set = ids.apply(lambda id_: test_set_check(id_, test_ratio, hash))
    return data.loc[~in_test_set], data.loc[in_test_set]

不過(guò),房產(chǎn)數(shù)據(jù)集沒(méi)有識(shí)別碼這一列。最簡(jiǎn)單的方法是使用行索引作為ID:

housing_with_id = housing.reset_index()   # adds an `index` column
train_set, test_set = split_train_test_by_id(housing_with_id, 0.2, "index")

如果使用行索引作為唯一識(shí)別碼,你需要保證新數(shù)據(jù)放到現(xiàn)有數(shù)據(jù)的尾部,且沒(méi)有行被深處。如果做不到,則可以用最穩(wěn)定的特征來(lái)創(chuàng)建唯一識(shí)別碼。例如,一個(gè)區(qū)的維度和經(jīng)度在幾百萬(wàn)年之內(nèi)是不變的,所以可以將兩者結(jié)合成一個(gè)ID:

housing_with_id["id"] = housing["longitude"] * 1000 + housing["latitude"]
train_set, test_set = split_train_test_by_id(housing_with_id, 0.2, "id")

Scikit-Learn提供了一些函數(shù),可以用多種方式將數(shù)據(jù)集分割成多個(gè)子集。最簡(jiǎn)單的函數(shù)是train_test_split,它的作用和之前的函數(shù)split_train_test很像,并帶有其它一些功能。首先,它有一個(gè)random_state參數(shù),可以設(shè)定前面講過(guò)的隨機(jī)生成器種子;第二,你可以將種子傳遞到多個(gè)行數(shù)相同的數(shù)據(jù)集,可以在相同的索引上分割數(shù)據(jù)集(這個(gè)功能非常有用,比如你有另一個(gè)DataFrame作為標(biāo)簽):

from sklearn.model_selection import train_test_split

train_set, test_set = train_test_split(housing, test_size=0.2, random_state=42)

目前為止,我們采用的都是純隨機(jī)的取樣方法。當(dāng)你的數(shù)據(jù)集很大時(shí)(尤其是和屬性數(shù)相比),這通??尚校坏绻麛?shù)據(jù)集不大,就會(huì)有采樣偏差的風(fēng)險(xiǎn)。當(dāng)一個(gè)調(diào)查公司想要對(duì)1000個(gè)人進(jìn)行調(diào)查,它們不是在電話亭里隨機(jī)選1000個(gè)人出來(lái)。調(diào)查公司要保證這1000個(gè)人對(duì)人群整體有代表性。例如,美國(guó)人口的51.3%是女性,48.7%是男性。所以在美國(guó),嚴(yán)謹(jǐn)?shù)恼{(diào)查需要保證樣本也是這個(gè)比例:513名女性,487名男性。這稱(chēng)作分層采樣(stratified sampling):將人群分成均勻的子分組,稱(chēng)為分層,從每個(gè)分層取出合適數(shù)量的實(shí)例,以保證測(cè)試集對(duì)總?cè)藬?shù)有代表性。如果調(diào)查公司采用純隨機(jī)采樣,會(huì)有12%的概率導(dǎo)致采樣偏差:女性人數(shù)少于49%,或多余54%。不管發(fā)生那種情況,調(diào)查結(jié)果都會(huì)嚴(yán)重偏差。

假設(shè)專(zhuān)家告訴你,收入中位數(shù)是預(yù)測(cè)房?jī)r(jià)中位數(shù)非常重要的屬性。你可能想要保證測(cè)試集可以代表整體數(shù)據(jù)集中的多種收入分類(lèi)。因?yàn)槭杖胫形粩?shù)是一個(gè)連續(xù)的數(shù)值屬性,你首先需要?jiǎng)?chuàng)建一個(gè)收入分類(lèi)屬性。再仔細(xì)地看一下收入中位數(shù)的柱狀圖(圖2-9):

圖2-9 收入分類(lèi)的柱狀圖

大多數(shù)的收入中位數(shù)的值聚集在2-5(一萬(wàn)美元),但是一些收入中位數(shù)會(huì)超過(guò)6。數(shù)據(jù)集中的每個(gè)分層都要有足夠的實(shí)例位于你的數(shù)據(jù)中,這點(diǎn)很重要。否則,對(duì)分層重要性的評(píng)估就會(huì)有偏差。這意味著,你不能有過(guò)多的分層,且每個(gè)分層都要足夠大。后面的代碼通過(guò)將收入中位數(shù)除以1.5(以限制收入分類(lèi)的數(shù)量),創(chuàng)建了一個(gè)收入分類(lèi)屬性,用ceil對(duì)值舍入(以產(chǎn)生離散的分類(lèi)),然后將所有大于5的分類(lèi)歸入到分類(lèi)5:

housing["income_cat"] = np.ceil(housing["median_income"] / 1.5)
housing["income_cat"].where(housing["income_cat"] < 5, 5.0, inplace=True)

現(xiàn)在,就可以根據(jù)收入分類(lèi),進(jìn)行分層采樣。你可以使用Scikit-Learn的StratifiedShuffleSplit類(lèi):

from sklearn.model_selection import StratifiedShuffleSplit

split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)

for train_index, test_index in split.split(housing, housing["income_cat"]):
    strat_train_set = housing.loc[train_index]
    strat_test_set = housing.loc[test_index]

檢查下結(jié)果是否符合預(yù)期。你可以在完整的房產(chǎn)數(shù)據(jù)集中查看收入分類(lèi)比例:

>>> housing["income_cat"].value_counts() / len(housing)
3.0    0.350581
2.0    0.318847
4.0    0.176308
5.0    0.114438
1.0    0.039826
Name: income_cat, dtype: float64

使用相似的代碼,還可以測(cè)量測(cè)試集中收入分類(lèi)的比例。圖2-10對(duì)比了總數(shù)據(jù)集、分層采樣的測(cè)試集、純隨機(jī)采樣測(cè)試集的收入分類(lèi)比例。可以看到,分層采樣測(cè)試集的收入分類(lèi)比例與總數(shù)據(jù)集幾乎相同,而隨機(jī)采樣數(shù)據(jù)集偏差嚴(yán)重。

圖2-10 分層采樣和純隨機(jī)采樣的樣本偏差比較

現(xiàn)在,你需要?jiǎng)h除income_cat屬性,使數(shù)據(jù)回到初始狀態(tài):

for set in (strat_train_set, strat_test_set):
    set.drop(["income_cat"], axis=1, inplace=True)

我們用了大量時(shí)間來(lái)生成測(cè)試集的原因是:測(cè)試集通常被忽略,但實(shí)際是機(jī)器學(xué)習(xí)非常重要的一部分。還有,生成測(cè)試集過(guò)程中的許多思路對(duì)于后面的交叉驗(yàn)證討論是非常有幫助的。接下來(lái)進(jìn)入下一階段:數(shù)據(jù)探索。

數(shù)據(jù)探索和可視化、發(fā)現(xiàn)規(guī)律

目前為止,你只是快速查看了數(shù)據(jù),對(duì)要處理的數(shù)據(jù)有了整體了解。現(xiàn)在的目標(biāo)是更深的探索數(shù)據(jù)。

首先,保證你將測(cè)試集放在了一旁,只是研究訓(xùn)練集。另外,如果訓(xùn)練集非常大,你可能需要再采樣一個(gè)探索集,保證操作方便快速。在我們的案例中,數(shù)據(jù)集很小,所以可以在全集上直接工作。創(chuàng)建一個(gè)副本,以免損傷訓(xùn)練集:

housing = strat_train_set.copy()

地理數(shù)據(jù)可視化

因?yàn)榇嬖诘乩硇畔ⅲň暥群徒?jīng)度),創(chuàng)建一個(gè)所有分區(qū)的散點(diǎn)圖來(lái)數(shù)據(jù)可視化是一個(gè)不錯(cuò)的主意(圖2-11):

housing.plot(kind="scatter", x="longitude", y="latitude")
圖2-11 數(shù)據(jù)的地理信息散點(diǎn)圖

這張圖看起來(lái)很像加州,但是看不出什么特別的規(guī)律。將alpha設(shè)為0.1,可以更容易看出數(shù)據(jù)點(diǎn)的密度(圖2-12):

housing.plot(kind="scatter", x="longitude", y="latitude", alpha=0.1)
圖2-12 顯示高密度區(qū)域的散點(diǎn)圖

現(xiàn)在看起來(lái)好多了:可以非常清楚地看到高密度區(qū)域,灣區(qū)、洛杉磯和圣迭戈,以及中央谷,特別是從薩克拉門(mén)托到弗雷斯諾。

通常來(lái)講,人類(lèi)的大腦非常善于發(fā)現(xiàn)圖片中的規(guī)律,但是需要調(diào)整可視化參數(shù)使規(guī)律顯現(xiàn)出來(lái)。

現(xiàn)在來(lái)看房?jī)r(jià)(圖2-13)。每個(gè)圈的半徑表示分區(qū)的人口(選項(xiàng)s),顏色代表價(jià)格(選項(xiàng)c)。我們用預(yù)先定義的顏色圖(選項(xiàng)cmap)jet,它的范圍是從藍(lán)色(低價(jià))到紅色(高價(jià)):

housing.plot(kind="scatter", x="longitude", y="latitude", alpha=0.4,
    s=housing["population"]/100, label="population",
    c="median_house_value", cmap=plt.get_cmap("jet"), colorbar=True,
)
plt.legend()
圖2-13 加州房?jī)r(jià)

這張圖說(shuō)明房?jī)r(jià)和位置(比如,靠海)和人口密度聯(lián)系密切,這點(diǎn)你可能早就知道。可以使用聚類(lèi)算法來(lái)檢測(cè)主要的聚集,用一個(gè)新的特征值測(cè)量聚集中心的距離。海洋距離屬性也可能有用,盡管北加州海岸區(qū)域的房?jī)r(jià)并不高,所以這不是一個(gè)簡(jiǎn)單的規(guī)則。

查找關(guān)聯(lián)

因?yàn)閿?shù)據(jù)集并不是非常大,你可以很容易地使用corr()方法計(jì)算出每對(duì)屬性間的標(biāo)準(zhǔn)相關(guān)系數(shù)(也稱(chēng)作皮爾遜相關(guān)系數(shù)):

corr_matrix = housing.corr()

現(xiàn)在來(lái)看下每個(gè)屬性和房?jī)r(jià)中位數(shù)的關(guān)聯(lián)度:

>>> corr_matrix["median_house_value"].sort_values(ascending=False)
median_house_value    1.000000
median_income         0.687170
total_rooms           0.135231
housing_median_age    0.114220
households            0.064702
total_bedrooms        0.047865
population           -0.026699
longitude            -0.047279
latitude             -0.142826
Name: median_house_value, dtype: float64

相關(guān)系數(shù)的范圍是-1到1。當(dāng)接近1時(shí),意味強(qiáng)正相關(guān);例如,當(dāng)收入中位數(shù)增加時(shí),房?jī)r(jià)中位數(shù)也會(huì)增加。當(dāng)相關(guān)系數(shù)接近-1時(shí),意味強(qiáng)負(fù)相關(guān);你可以看到,緯度和房?jī)r(jià)中位數(shù)有輕微的負(fù)相關(guān)性(即,越往北,房?jī)r(jià)越可能降低)。最后,相關(guān)系數(shù)接近0,意味沒(méi)有線性相關(guān)性。圖2-14展示了相關(guān)系數(shù)在橫軸和縱軸之間的不同圖形。

圖2-14 不同數(shù)據(jù)集的標(biāo)準(zhǔn)相關(guān)系數(shù)(來(lái)源:Wikipedia; public domain image)

警告:相關(guān)系數(shù)只測(cè)量線性關(guān)系(如果x上升,y則上升或下降)。相關(guān)系數(shù)可能會(huì)完全忽略非線性關(guān)系(即,如果x接近0,則y值會(huì)變高)。在前面的計(jì)算結(jié)果中,底部的許多行的相關(guān)系數(shù)接近于0,盡管它們的軸并不獨(dú)立:這些就是非線性關(guān)系的例子。另外,第二行的相關(guān)系數(shù)等于1或-1;這和斜率沒(méi)有任何關(guān)系。例如,你的身高(單位是英寸)與身高(單位是英尺或納米)的相關(guān)系數(shù)就是1。

另一種檢測(cè)屬性間相關(guān)系數(shù)的方法是使用Pandas的scatter_matrix函數(shù),它能畫(huà)出每個(gè)數(shù)值屬性對(duì)每個(gè)其它數(shù)值屬性的圖。因?yàn)楝F(xiàn)在共有11個(gè)數(shù)值屬性,你可以得到112=121張圖,在一頁(yè)上畫(huà)不下,所以只關(guān)注幾個(gè)和房?jī)r(jià)中位數(shù)最有可能相關(guān)的屬性(圖2-15):

from pandas.tools.plotting import scatter_matrix

attributes = ["median_house_value", "median_income", "total_rooms",
              "housing_median_age"]
scatter_matrix(housing[attributes], figsize=(12, 8))
圖2-15 散點(diǎn)矩陣

如果pandas將每個(gè)變量對(duì)自己作圖,主對(duì)角線(左上到右下)都會(huì)是直線圖。所以Pandas展示的是每個(gè)屬性的柱狀圖(也可以是其它的,請(qǐng)參考Pandas文檔)。

最有希望用來(lái)預(yù)測(cè)房?jī)r(jià)中位數(shù)的屬性是收入中位數(shù),因此將這張圖放大(圖2-16):

housing.plot(kind="scatter", x="median_income",y="median_house_value",
             alpha=0.1)
圖2-16 收入中位數(shù)vs房?jī)r(jià)中位數(shù)

這張圖說(shuō)明了幾點(diǎn)。首先,相關(guān)性非常高;可以清晰地看到向上的趨勢(shì),并且數(shù)據(jù)點(diǎn)不是非常分散。第二,我們之前看到的最高價(jià),清晰地呈現(xiàn)為一條位于500000美元的水平線。這張圖也呈現(xiàn)了一些不是那么明顯的直線:一條位于450000美元的直線,一條位于350000美元的直線,一條在$280000的線,和一些更靠下的線。你可能希望去除對(duì)應(yīng)的分區(qū),以防止算法重復(fù)這些巧合。

屬性組合試驗(yàn)

希望前面的一節(jié)能教給你一些探索數(shù)據(jù)、發(fā)現(xiàn)規(guī)律的方法。你發(fā)現(xiàn)了一些數(shù)據(jù)的巧合,需要在給算法提供數(shù)據(jù)之前,將其去除。你還發(fā)現(xiàn)了一些屬性間有趣的關(guān)聯(lián),特別是目標(biāo)屬性。你還注意到一些屬性具有長(zhǎng)尾分布,因此你可能要將其進(jìn)行轉(zhuǎn)換(例如,計(jì)算其log對(duì)數(shù))。當(dāng)然,不同項(xiàng)目的處理方法各不相同,但大體思路是相似的。

給算法準(zhǔn)備數(shù)據(jù)之前,你需要做的最后一件事是嘗試多種屬性組合。例如,如果你不知道某個(gè)分區(qū)有多少戶(hù),該分區(qū)的總房間數(shù)就沒(méi)什么用。你真正需要的是每戶(hù)有幾個(gè)房間。相似的,總臥室數(shù)也不重要:你可能需要將其與房間數(shù)進(jìn)行比較。每戶(hù)的人口數(shù)也是一個(gè)有趣的屬性組合。讓我們來(lái)創(chuàng)建這些新的屬性:

housing["rooms_per_household"] = housing["total_rooms"]/housing["households"]
housing["bedrooms_per_room"] = housing["total_bedrooms"]/housing["total_rooms"]
housing["population_per_household"]=housing["population"]/housing["households"]

現(xiàn)在,再來(lái)看相關(guān)矩陣:

>>> corr_matrix = housing.corr()
>>> corr_matrix["median_house_value"].sort_values(ascending=False)
median_house_value          1.000000
median_income               0.687170
rooms_per_household         0.199343
total_rooms                 0.135231
housing_median_age          0.114220
households                  0.064702
total_bedrooms              0.047865
population_per_household   -0.021984
population                 -0.026699
longitude                  -0.047279
latitude                   -0.142826
bedrooms_per_room          -0.260070
Name: median_house_value, dtype: float64

看起來(lái)不錯(cuò)!與總房間數(shù)或臥室數(shù)相比,新的bedrooms_per_room屬性與房?jī)r(jià)中位數(shù)的關(guān)聯(lián)更強(qiáng)。顯然,臥室數(shù)/總房間數(shù)的比例越低,房?jī)r(jià)就越高。每戶(hù)的房間數(shù)也比分區(qū)的總房間數(shù)的更有信息,很明顯,房屋越大,房?jī)r(jià)就越高。

這一步的數(shù)據(jù)探索不必非常完備,此處的目的是有一個(gè)正確的開(kāi)始,快速發(fā)現(xiàn)規(guī)律,以得到一個(gè)合理的原型。但是這是一個(gè)交互過(guò)程:一旦你得到了一個(gè)原型,并運(yùn)行起來(lái),你就可以分析它的輸出,進(jìn)而發(fā)現(xiàn)更多的規(guī)律,然后再回到數(shù)據(jù)探索這步。

為機(jī)器學(xué)習(xí)算法準(zhǔn)備數(shù)據(jù)

現(xiàn)在來(lái)為機(jī)器學(xué)習(xí)算法準(zhǔn)備數(shù)據(jù)。不要手工來(lái)做,你需要寫(xiě)一些函數(shù),理由如下:

  • 函數(shù)可以讓你在任何數(shù)據(jù)集上(比如,你下一次獲取的是一個(gè)新的數(shù)據(jù)集)方便地進(jìn)行重復(fù)數(shù)據(jù)轉(zhuǎn)換。

  • 你能慢慢建立一個(gè)轉(zhuǎn)換函數(shù)庫(kù),可以在未來(lái)的項(xiàng)目中復(fù)用。

  • 在將數(shù)據(jù)傳給算法之前,你可以在實(shí)時(shí)系統(tǒng)中使用這些函數(shù)。

  • 這可以讓你方便地嘗試多種數(shù)據(jù)轉(zhuǎn)換,查看那些轉(zhuǎn)換方法結(jié)合起來(lái)效果最好。

但是,還是先回到清洗訓(xùn)練集(通過(guò)再次復(fù)制strat_train_set),將預(yù)測(cè)量和標(biāo)簽分開(kāi),因?yàn)槲覀儾幌雽?duì)預(yù)測(cè)量和目標(biāo)值應(yīng)用相同的轉(zhuǎn)換(注意drop()創(chuàng)建了一份數(shù)據(jù)的備份,而不影響strat_train_set):

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

(第一部分 機(jī)器學(xué)習(xí)基礎(chǔ))
第01章 機(jī)器學(xué)習(xí)概覽
第02章 一個(gè)完整的機(jī)器學(xué)習(xí)項(xiàng)目(上)
第02章 一個(gè)完整的機(jī)器學(xué)習(xí)項(xiàng)目(下)
第03章 分類(lèi)
第04章 訓(xùn)練模型
第05章 支持向量機(jī)
第06章 決策樹(shù)
第07章 集成學(xué)習(xí)和隨機(jī)森林
第08章 降維
(第二部分 神經(jīng)網(wǎng)絡(luò)和深度學(xué)習(xí))
第9章 啟動(dòng)和運(yùn)行TensorFlow
第10章 人工神經(jīng)網(wǎng)絡(luò)
第11章 訓(xùn)練深度神經(jīng)網(wǎng)絡(luò)(上)
第11章 訓(xùn)練深度神經(jīng)網(wǎng)絡(luò)(下)
第12章 設(shè)備和服務(wù)器上的分布式 TensorFlow
第13章 卷積神經(jīng)網(wǎng)絡(luò)
第14章 循環(huán)神經(jīng)網(wǎng)絡(luò)
第15章 自編碼器
第16章 強(qiáng)化學(xué)習(xí)(上)
第16章 強(qiáng)化學(xué)習(xí)(下)


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容