參考鏈接: Python中的邏輯門
內容介紹
在如今這個處處以數據驅動的世界中,機器學習正變得越來越大眾化。它已經被廣泛地應用于不同領域,如搜索引擎、機器人、無人駕駛汽車等。本書首先通過實用的案例介紹機器學習的基礎知識,然后介紹一些稍微復雜的機器學習算法,例如支持向量機、極端隨機森林、隱馬爾可夫模型、條件隨機場、深度神經網絡,等等。
用最火的 Python 語言、通過各種各樣的機器學習算法來解決實際問題!
書中介紹的主要問題如下。
探索分類分析算法并將其應用于收入等級評估問題使用預測建模并將其應用到實際問題中了解如何使用無監督學習來執行市場細分探索數據可視化技術以多種方式與數據進行交互了解如何構建推薦引擎理解如何與文本數據交互并構建模型來分析它使用隱馬爾科夫模型來研究語音數據并識別語音
作者簡介
Prateek Joshi,人工智能專家,重點關注基于內容的分析和深度學習,曾在英偉達、微軟研究院、高通公司以及硅谷的幾家早期創業公司任職。
本書內容
譯者序
有一天,忽然想到自己整天面對著52個英文字母、9個數字、32個符號①和一個空格,經常加班沒有雙休日,好傻。時間不斷被各種噪聲碎片化,完全就是毛姆在《月亮和六便士》里寫的,“If you look on the ground in search of a sixpence, you don't look up, and so miss the moon”,整天低頭刷手機,卻不記得舉頭望明月。生活也愈發無序,感覺漸漸被掏空。薛定諤的《生命是什么》給我提了個醒,他在“以‘負熵’為生”(It Feeds On ‘negative Entropy’)一節指出:“要活著,唯一的辦法就是從環境里不斷地汲取負熵。”在介紹了熵的概念及其統計學意義之后,他緊接著在“從環境中引出‘有序’以維持組織”(Organization Maintained By Extracting ‘Order’From The Environment)一節進一步總結:“一個有機體使本身穩定在較高的有序水平上(等于熵的相當低的水平上)的辦法,就是從環境中不斷地吸取秩序。”這個秩序(負熵、klog(1/n))可以是食物,也可以是知識,按主流叫法就是“正能量”(有些所謂正能量卻碰巧是增加系統無序水平的正熵)。于是,我開始漸漸放棄那些讓人沮喪的老梗,遠離那些引發混亂的噪聲,重新讀書,試著翻譯,學會去愛。這幾年最大的收獲就是明白了“隔行如隔山”的道理,試著循序漸進,教學相長,做力所能及之事,讓編程變簡單。
一般人都不喜歡編程,更不喜歡動手編程(時間消耗:編寫 & 測試 40%、重構 40%、風格 & 文檔 20%),卻喜歡在心里、嘴上編程:“先這樣,再那樣,如果要 XX,就 YY,最后就可以 ZZ 了。”分分鐘就可以說完幾萬行代碼的項目,水還剩大半杯。一旦大期將近,即使要親自動手 Copy 代碼,也會覺得苦堪搬磚,鍵盤不是紅與黑、屏幕不能左右推、小狗總是鬧跑追,不斷在數不清的理由中增加自己的熵。偶爾看編程書的目的也很明確,就是為了快速上手,找到答案。當然也是在 Google、StackOverflow、GitHub 網站上找不到答案之后,無可奈何之舉。編程書把看著復雜的知識寫得更復雜,雖然大多篇幅不輸“飛雪連天射白鹿,笑書神俠倚碧鴛”等經典,且綱舉目張、圖文并茂,甚至有作者愛引經據典,卻極少有令人拍案的驚奇之處。為什么同樣是文以載道,編程書卻不能像武俠小說一樣簡單具體,反而顯得了無生趣,令人望而卻步?雖然編程的目的就是用計算機系統解決問題,但是大多數問題的知識都在其他領域中,許多作者在介紹編程技巧時,又試圖介紹一些并不熟悉的背景知識,顯得生澀難懂,且增加了書的厚度。
有時我們真正需要的,就是能快刀斬亂麻的代碼。(Talk is cheap, show me the code.)編程與研究數理化不同,沒有任何假設、原命題、思維實驗,并非科學;與舞劍、奏樂、炒菜相似,都是手藝,只要基礎扎實,便結果立判。編程技巧也可以像劍譜、樂譜、食譜一般立竿見影,這本《Python 機器學習經典實例》正是如此,直接上代碼,照著做就行,不用糾結為什么。
機器學習是交叉學科,應用廣泛,目前主流方法為統計機器學習。既然是以統計學為基礎,那么就不只是計算機與數學專業的私房菜了,機器學習在自然科學、農業科學、醫藥科學、工程與技術科學、人文與社會科學等多種學科中均可應用。如果你遇到了回歸、分類、預測、聚類、文本分析、語音識別、圖像處理等經典問題,需要快速用 Python 解決,那么這本菜譜適合你。即使你對機器學習方法還一知半解,也不妨一試。畢竟是 Python 的機器學習,還能難到哪兒去呢?目前十分流行的 Python 機器學習庫 scikit-learn 是全書主角之一,功能全面,接口友好,許多經典的數據集和機器學習案例都來自Kaggle②。若有時間追根溯源,請研究周志華教授的《機器學習》西瓜書,周教授啃著西瓜把機器學習調侃得淋漓盡致,詳細的參考文獻尤為珍貴。但是想當作菜譜看,拿來就用,還是需要費一番功夫;若看書不過癮,還有吳恩達(Andrew Ng)教授在Coursera上的機器學習公開課③,機器學習入門最佳視頻教程,吳教授用的工具是 Matlab 的免費開源版本 Octave,你也可以用 Python 版演示教學示例。
學而時習之,不亦樂乎。學習編程技巧,解決實際問題,是一件快樂的事情。希望這本 Python 機器學習經典案例,可以成為你的負熵,幫你輕松化解那些陳年老梗。如果再努努力,也許陸汝鈐院士在《機器學習》序言中提出的6個問題④,你也有答案了。
示例代碼:
"""打印ASCII字母表、數字、標點符號"""import stringfor item in [string.ascii_letters,? ? ? ? ? ? ?string.digits,? ? ? ? ? ? ?string.punctuation]:? ? print('{}\t{}'.format(len(item), item))
輸出結果:
52 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ10 012345678932 !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
①見文末Python示例代碼。
②Kaggle 是一個2010年成立的數據建模和數據分析競賽平臺,全球數據科學家、統計學家、機器學習工程師的聚集地,上面有豐富的數據集,經典的機器學習基礎教程,以及讓人流口水的競賽獎金,支持Python、R、Julia、SQLite,同時也支持 jupyter notebook 在線編程環境,2017年3月8日被谷歌收購。
③分免費版和付費版(購買結業證書),學習內容一樣。
?
④陸院士的6個問題分別是:1. 機器學習早期的符號機器學習,如何在統計機器學習主流中發展;2. 統計機器學習算法中并不現實的“獨立同分布”假設如何解決;3. 深度學習得益于硬件革命,是否會取代統計機器學習;4. 機器學習用的都是經典的概率統計、代數邏輯,而目前僅有倒向微分方程用于預測,微分幾何的流形用于降維,只是數學領域的一角,其他現代數學理論是否可以參與其中;5. 機器學習方法仍不夠嚴謹,例如目前流形學習直接將高維數據集假設成微分流形,需要進一步完善;6. 大數據與統計機器學習是如何互動的。
流形學習,Manifold learning,科普見此。
前言
在如今這個處處以數據驅動的世界中,機器學習正變得越來越大眾化。它已經被廣泛地應用于不同領域,如搜索引擎、機器人、無人駕駛汽車等。本書不僅可以幫你了解現實生活中機器學習的應用場景,而且通過有趣的菜譜式教程教你掌握處理具體問題的算法。
本書首先通過實用的案例介紹機器學習的基礎知識,然后介紹一些稍微復雜的機器學習算法,例如支持向量機、極端隨機森林、隱馬爾可夫模型、條件隨機場、深度神經網絡,等等。本書是為想用機器學習算法開發應用程序的 Python 程序員準備的。它不僅適合 Python 初學者(當然,熟悉 Python 編程方法將有助于體驗示例代碼),而且也適合想要掌握機器學習技術的 Python 老手。
通過本書,你不僅可以學會如何做出合理的決策,為自己選擇合適的算法類型,而且可以學會如何高效地實現算法以獲得最佳學習效果。如果你在圖像、文字、語音或其他形式的數據處理中遇到困難,書中處理這些數據的機器學習技術一定會對你有所幫助!
本書內容
第1章介紹各種回歸分析的監督學習技術。我們將學習如何分析共享自行車的使用模式,以及如何預測房價。
第2章介紹各種數據分類的監督學習技術。我們將學習如何評估收入層級,以及如何通過特征評估一輛二手汽車的質量。
第3章論述支持向量機的預測建模技術。我們將學習如何使用這些技術預測建筑物里事件發生的概率,以及體育場周邊道路的交通情況。
第4章闡述無監督學習算法,包括 K-means 聚類和均值漂移聚類。我們將學習如何將這些算法應用于股票市場數據和客戶細分。
第5章介紹推薦引擎的相關算法。我們將學習如何應用這些算法實現協同濾波和電影推薦。
第6章闡述與文本數據分析相關的技術,包括分詞、詞干提取、詞庫模型等。我們將學習如何使用這些技術進行文本情感分析和主題建模。
第7章介紹與語音數據分析相關的算法。我們將學習如何建立語音識別系統。
第8章介紹分析時間序列和有序數據的相關技術,包括隱馬爾可夫模型和條件隨機場。我們將學習如何將這些技術應用到文本序列分析和股市預測中。
第9章介紹圖像內容分析與物體識別方面的算法。我們將學習如何提取圖像特征,以及建立物體識別系統。
第10章介紹在圖像和視頻中檢測與識別面部的相關技術。我們將學習使用降維算法建立面部識別器。
第11章介紹建立深度神經網絡所需的算法。我們將學習如何使用神經網絡建立光學文字識別系統。
第12章介紹機器學習使用的數據可視化技術。我們將學習如何創建不同類型的圖形和圖表。
閱讀背景
Python 2.x 和 Python 3.x 的版本之爭尚未平息①。一方面,我們堅信世界會向更好的版本不斷進化,另一方面,許多開發者仍然喜歡使用 Python 2.x 的版本。目前許多操作系統仍然內置 Python 2.x。本書的重點是介紹 Python 機器學習,而非 Python 語言本身。另外,考慮到程序的兼容性,書中用到了一些尚未被遷移到 Python 3.x 版本的程序庫,因此,本書依然選擇 Python 2.x 的版本。我們會盡最大努力保持代碼兼容各種 Python 版本,因為這樣可以讓你輕松地理解代碼,并且很方便地將代碼應用到不同場景中。
讀者對象
本書是為想用機器學習算法開發應用程序的 Python 程序員準備的。它適合 Python 初學者閱讀,不過熟悉 Python 編程方法對體驗示例代碼大有裨益。
內容組織
在本書中,你會頻繁地看到下面這些標題(準備工作、詳細步驟、工作原理、更多內容、另請參閱)。
為了更好地呈現內容,本書采用以下組織形式。
準備工作
這部分首先介紹本節目標,然后介紹軟件配置方法以及所需的準備工作。
詳細步驟
這部分介紹具體的實踐步驟。
工作原理
這部分通常是對前一部分內容的詳細解釋。
更多內容
這部分會補充介紹一些信息,幫助你更好地理解前面的內容。
另請參閱
這部分提供一些參考資料。
排版約定
在本書中,你會發現一些不同的文本樣式。這里舉例說明它們的含義。
嵌入代碼、命令、選項、參數、函數、字段、屬性、語句等,用等寬的代碼字體顯示:“這里,我們將25%的數據用于測試,可以通過test_size參數進行設置。”
代碼塊用如下格式:
import numpy as npimport matplotlib.pyplot as pltimport utilities# Load input datainput_file = 'data_multivar.txt'X, y = utilities.load_data(input_file)
命令行輸入或輸出用如下格式:
$ python object_recognizer.py --input-image imagefile.jpg --model-fileerf.pkl --codebook-file codebook.pkl
新術語和重要文字將采用黑體字。你在屏幕上看到的內容,包括對話框或菜單里的文本,都將這樣顯示:“如果你將數組改為(0, 0.2, 0, 0, 0),那么 Strawberry 部分就會高亮顯示。”
讀者反饋
我們非常歡迎讀者的反饋。如果你對本書有些想法,有什么喜歡或是不喜歡的,請反饋給我們,這將有助于我們出版充分滿足讀者需求的圖書。
一般性反饋請發送電子郵件至 feedback@packtpub.com,并在郵件主題中注明書名。
如果你在某個領域有專長,并有意編寫一本書或是貢獻一份力量,請參考我們的作者指南。
客戶支持
你現在已經是引以為傲的 Packt 讀者了。為了能讓你的購買物超所值,我們還為你準備了以下內容。
下載示例代碼
你可以用你的賬戶從此處下載所有已購買 Packt 圖書的示例代碼文件。如果你是從其他途徑購買的本書,可以訪問此處并注冊,我們將通過電子郵件把文件發送給你。
可以通過以下步驟下載示例代碼文件:
(1) 用你的電子郵件和密碼登錄或注冊我們的網站;
(2) 將鼠標移到網站上方的客戶支持(SUPPORT)標簽;
(3) 單擊代碼下載與勘誤(Code Downloads & Errata)按鈕;
(4) 在搜索框(Search)中輸入書名;
(5) 選擇你要下載代碼文件的書;
(6) 從下拉菜單中選擇你的購書途徑;
(7) 單擊代碼下載(Code Download)按鈕。
你也可以通過單擊 Packt 網站上本書網頁上的代碼文件(Code Files)按鈕來下載示例代碼,該網頁可以通過在搜索框(Search)中輸入書名獲得。以上操作的前提是你已經登錄了 Packt 網站。
下載文件后,請確保用以下軟件的最新版來解壓文件:
WinRAR / 7-Zip for Windows ;Zipeg / iZip / UnRarX for Mac ;7-Zip / PeaZip for Linux 。
本書的代碼包也可以在 GitHub 上獲得。另外,我們在這里還有其他書的代碼包和視頻,請需要的讀者自行下載。
下載本書的彩色圖片
我們也為你提供了一份 PDF 文件,里面包含了書中的截屏和圖表等彩色圖片,彩色圖片能幫助你更好地理解輸出的變化。下載地址
勘誤
雖然我們已盡力確保本書內容正確,但出錯仍舊在所難免。如果你在書中發現錯誤,不管是文本還是代碼,希望能告知我們,我們將不勝感激。這樣做,你可以使其他讀者免受挫敗,也可以幫助我們改進本書的后續版本。如果你發現任何錯誤,請訪問這里,選擇本書,單擊勘誤表提交表單(Errata Submission Form)的鏈接,并輸入詳細說明。②勘誤一經核實,你提交的內容將被接受,此勘誤會上傳到本公司網站或添加到現有勘誤表。
訪問這里,在搜索框中輸入書名,可以在勘誤(Errata)部分查看已經提交的勘誤信息。
盜版
任何媒體都會面臨版權內容在互聯網上的盜版問題,Packt 也不例外。Packt 非常重視版權保護。如果你發現我們的作品在互聯網上被非法復制,不管以什么形式,都請立即為我們提供相關網址或網站名稱,以便我們尋求補救。
請把可疑盜版材料的鏈接發到 copyright@packtpub.com。
保護我們的作者,就是保護我們繼續為你帶來價值的能力,我們將不勝感激。
問題
如果你對本書內容存有疑問,不管是哪個方面的,都可以通過 questions@packtpub.com 聯系我們,我們會盡最大努力解決。
①2020年之前應該不會終結。——譯者注
?
②中文版勘誤可以到這里查看和提交。——編者注
第01章:監督學習(上)
?
?
?
? ?
? ? ?1.1 簡介1.2 數據預處理技術
? ? ? ?1.2.1 準備工作1.2.2 詳細步驟1.3 標記編碼方法
?
在這一章,我們將介紹以下主題:
數據預處理技術標記編碼方法創建線性回歸器(linear regressor)計算回歸準確性保存模型數據創建嶺回歸器(ridge regressor)創建多項式回歸器(polynomial regressor)估算房屋價格計算特征的相對重要性評估共享單車的需求分布
1.1 簡介
如果你熟悉機器學習的基礎知識,那么肯定知道什么是監督學習。監督學習是指在有標記的樣本(labeled samples)上建立機器學習的模型。例如,如果用尺寸、位置等不同參數建立一套模型來評估一棟房子的價格,那么首先需要創建一個數據庫,然后為參數打上標記。我們需要告訴算法,什么樣的參數(尺寸、位置)對應什么樣的價格。有了這些帶標記的數據,算法就可以學會如何根據輸入的參數計算房價了。
無監督學習與剛才說的恰好相反,它面對的是沒有標記的數據。假設需要把一些數據分成不同的組別,但是對分組的條件毫不知情,于是,無監督學習算法就會以最合理的方式將數據集分成確定數量的組別。我們將在后面章節介紹無監督學習。
建立書中的各種模型時,將使用許多 Python 程序包,像 NumPy、SciPy、scikit-learn、matplotlib 等。如果你使用 Windows 系統,推薦安裝兼容 SciPy 關聯程序包的 Python 發行版,這些 Python 發行版里已經集成了常用的程序包。如果你使用 Mac OS X 或者 Ubuntu 系統,安裝這些程序包就相當簡單了。下面列出來程序包安裝和使用文檔的鏈接:
NumPy:http://docs.scipy.org/doc/numpy-1.10.1/user/install.htmlSciPy:http://www.scipy.org/install.htmlscikit-learn:http://scikit-learn.org/stable/install.htmlmatplotlib:http://matplotlib.org/1.4.2/users/installing.html
現在,請確保你的計算機已經安裝了所有程序包。
1.2 數據預處理技術
在真實世界中,經常需要處理大量的原始數據,這些原始數據是機器學習算法無法理解的。為了讓機器學習算法理解原始數據,需要對數據進行預處理。
1.2.1 準備工作
來看看 Python 是如何對數據進行預處理的。首先,用你最喜歡的文本編輯器打開一個擴展名為.py 的文件,例如 preprocessor.py。然后在文件里加入下面兩行代碼:
import numpy as npfrom sklearn import preprocessing
我們只是加入了兩個必要的程序包。接下來創建一些樣本數據。向文件中添加下面這行代碼:
data = np.array([[3,? -1.5,? ? 2,? -5.4], [0,? ? 4,? ? -0.3,? 2.1], [1,? ? 3.3,-1.9, -4.3]])
現在就可以對數據進行預處理了。
1.2.2 詳細步驟
數據可以通過許多技術進行預處理,接下來將介紹一些最常用的預處理技術。
1.均值移除(Mean removal)
通常我們會把每個特征的平均值移除,以保證特征均值為0(即標準化處理)。這樣做可以消除特征彼此間的偏差(bias)。將下面幾行代碼加入之前打開的Python文件中:
? ? data_standardized = preprocessing.scale(data)? ? print "\nMean =", data_standardized.mean(axis=0)? ? print "Std deviation =", data_standardized.std(axis=0)
現在來運行代碼。打開命令行工具,然后輸入以下命令:
? ? $ python preprocessor.py命令行工具中將顯示以下結果:? ? Mean = [? 5.55111512e-17? -1.11022302e-16? -7.40148683e-17? -7.40148683e-17]? ? Std deviation = [ 1.? 1.? 1.? 1.]你會發現特征均值幾乎是`0`,而且標準差為`1`。
2.范圍縮放(Scaling)
數據點中每個特征的數值范圍可能變化很大,因此,有時將特征的數值范圍縮放到合理的大小是非常重要的。在 Python 文件中加入下面幾行代碼,然后運行程序:
? ? data_scaler = preprocessing.MinMaxScaler(feature_range=(0, 1))? ? data_scaled = data_scaler.fit_transform(data)? ? print "\nMin max scaled data =", data_scaled
范圍縮放之后,所有數據點的特征數值都位于指定的數值范圍內。輸出結果如下所示:
? ? Min max scaled data:? ? [[ 1.? ? ? ? ? ? 0.? ? ? ? ? ? 1.? ? ? ? ? ? 0.? ? ? ? ]? ? ?[ 0.? ? ? ? ? ? 1.? ? ? ? ? ? 0.41025641? ? 1.? ? ? ? ]? ? ?[ 0.33333333? ? 0.87272727? ? 0.? ? ? ? ? ? 0.14666667]]
3.歸一化(Normalization)
數據歸一化用于需要對特征向量的值進行調整時,以保證每個特征向量的值都縮放到相同的數值范圍。機器學習中最常用的歸一化形式就是將特征向量調整為 L1范數,使特征向量的數值之和為1。增加下面兩行代碼到前面的 Python 文件中:
? ? data_normalized = preprocessing.normalize(data, norm='l1')? ? print "\nL1 normalized data =", data_normalized
執行 Python 文件,就可以看到下面的結果:
? ? L1? ? normalized? ? data:? ? [[? ? 0.25210084? ? -0.12605042? ? 0.16806723? ? -0.45378151]? ? ?[? ? 0.? ? ? ? ? ? ?0.625? ? ? ? -0.046875? ? ? ?0.328125? ]? ? ?[? ? 0.0952381? ? ? 0.31428571? ?-0.18095238? ? -0.40952381]]
這個方法經常用于確保數據點沒有因為特征的基本性質而產生較大差異,即確保數據處于同一數量級,提高不同特征數據的可比性。
4.二值化(Binarization)
二值化用于將數值特征向量轉換為布爾類型向量。增加下面兩行代碼到前面的 Python 文件中:
? ? data_binarized = preprocessing.Binarizer(threshold=1.4).transform(data)? ? print "\nBinarized data =", data_binarized
再次執行 Python 文件,就可以看到下面的結果:
? ? Binarized data:? ? [[? ? 1.? ? 0.? ? 1.? ? 0.]? ? ?[? ? 0.? ? 1.? ? 0.? ? 1.]? ? ?[? ? 0.? ? 1.? ? 0.? ? 0.]]
如果事先已經對數據有了一定的了解,就會發現使用這個技術的好處了。
5.獨熱編碼
通常,需要處理的數值都是稀疏地、散亂地分布在空間中,然而,我們并不需要存儲這些大數值,這時就需要使用獨熱編碼(One-Hot Encoding)。可以把獨熱編碼看作是一種收緊(tighten)特征向量的工具。它把特征向量的每個特征與特征的非重復總數相對應,通過 one-of-k 的形式對每個值進行編碼。特征向量的每個特征值都按照這種方式編碼,這樣可以更加有效地表示空間。例如,我們需要處理4維向量空間,當給一個特性向量的第 n 個特征進行編碼時,編碼器會遍歷每個特征向量的第 n 個特征,然后進行非重復計數。如果非重復計數的值是 K ,那么就把這個特征轉換為只有一個值是1其他值都是0的 K 維向量。增加下面幾行代碼到前面的 Python 文件中:
? ? encoder = preprocessing.OneHotEncoder()? ? encoder.fit([[0, 2, 1, 12], [1, 3, 5, 3], [2, 3, 2, 12], [1, 2, 4, 3]])? ? encoded_vector = encoder.transform([[2, 3, 5, 3]]).toarray()? ? print "\nEncoded vector =", encoded_vector
結果如下所示:
? ? Encoded vector:? ? [[ 0.? 0.? 1.? 0.? 1.? 0.? 0.? 0.? 1.? 1.? 0.]]
在上面的示例中,觀察一下每個特征向量的第三個特征,分別是1、5、2、4這4個不重復的值,也就是說獨熱編碼向量的長度是4。如果你需要對5進行編碼,那么向量就是[0, 1, 0, 0]。向量中只有一個值是1。第二個元素是1,對應的值是5。
1.3 標記編碼方法
在監督學習中,經常需要處理各種各樣的標記。這些標記可能是數字,也可能是單詞。如果標記是數字,那么算法可以直接使用它們,但是,許多情況下,標記都需要以人們可理解的形式存在,因此,人們通常會用單詞標記訓練數據集。標記編碼就是要把單詞標記轉換成數值形式,讓算法懂得如何操作標記。接下來看看如何標記編碼。
詳細步驟
(1) 新建一個 Python 文件,然后導入 preprocessing 程序包:
from sklearn import preprocessing
(2) 這個程序包包含許多數據預處理需要的函數。定義一個標記編碼器(label encoder),代碼如下所示:
label_encoder = preprocessing.LabelEncoder()
(3) label_encoder對象知道如何理解單詞標記。接下來創建一些標記:
input_classes = ['audi', 'ford', 'audi', 'toyota', 'ford', 'bmw']
(4) 現在就可以為這些標記編碼了:
label_encoder.fit(input_classes)print "\nClass mapping:"for i, item in enumerate(label_encoder.classes_):? ? print item, '-->', i
(5) 運行代碼,命令行工具中顯示下面的結果:
Class mapping:audi --> 0bmw --> 1ford --> 2toyota --> 3
(6) 就像前面結果顯示的那樣,單詞被轉換成從0開始的索引值。現在,如果你遇到一組標記,就可以非常輕松地轉換它們了,如下所示:
labels = ['toyota', 'ford', 'audi']encoded_labels = label_encoder.transform(labels)print "\nLabels =", labelsprint "Encoded labels =", list(encoded_labels)
命令行工具中將顯示下面的結果:
Labels = ['toyota', 'ford', 'audi']Encoded labels = [3, 2, 0]
(7) 這種方式比純手工進行單詞與數字的編碼要簡單許多。還可以通過數字反轉回單詞的功能檢查結果的正確性:
encoded_labels = [2, 1, 0, 3, 1]decoded_labels = label_encoder.inverse_transform(encoded_labels)print "\nEncoded labels =", encoded_labelsprint "Decoded labels =", list(decoded_labels)
結果如下所示:
Encoded labels = [2, 1, 0, 3, 1]Decoded labels = ['ford', 'bmw', 'audi', 'toyota', 'bmw']
可以看到,映射結果是完全正確的。
第01章:監督學習(中)
?
?
?
? ?
? ? ?1.4 創建線性回歸器
? ? ? ?1.4.1 準備工作1.4.2 詳細步驟1.5 計算回歸準確性
? ? ? ?1.5.1 準備工作1.5.2 詳細步驟1.6 保存模型數據1.7 創建嶺回歸器
? ? ? ?1.7.1 準備工作1.7.2 詳細步驟
?
1.4 創建線性回歸器
回歸是估計輸入數據與連續值輸出數據之間關系的過程。數據通常是實數形式的,我們的目標是估計滿足輸入到輸出映射關系的基本函數。讓我們從一個簡單的示例開始。考慮下面的輸入與輸出映射關系:
1 → 2
3 → 6
4.3 → 8.6
7.1 → 14.2
如果要你估計輸入與輸出的關聯關系,你可以通過模式匹配輕松地找到結果。我們發現輸出結果一直是輸入數據的兩倍,因此輸入與輸出的轉換公式就是這樣:
f(x) = 2x
這是體現輸入值與輸出值關聯關系的一個簡單函數。但是,在真實世界中通常都不會這么簡單,輸入與輸出的映射關系函數并不是一眼就可以看出來的。
1.4.1 準備工作
線性回歸用輸入變量的線性組合來估計基本函數。前面的示例就是一種單輸入單輸出變量的線性回歸。
現在考慮如圖1-1所示的情況。
?
圖 1-1
線性回歸的目標是提取輸入變量與輸出變量的關聯線性模型,這就要求實際輸出與線性方程預測的輸出的殘差平方和(sum of squares of differences)最小化。這種方法被稱為普通最小二乘法(Ordinary Least Squares,OLS)。
你可能覺得用一條曲線對這些點進行擬合效果會更好,但是線性回歸不允許這樣做。線性回歸的主要優點就是方程簡單。如果你想用非線性回歸,可能會得到更準確的模型,但是擬合速度會慢很多。線性回歸模型就像前面那張圖里顯示的,用一條直線近似數據點的趨勢。接下來看看如何用 Python 建立線性回歸模型。
1.4.2 詳細步驟
假設你已經創建了數據文件 data_singlevar.txt,文件里用逗號分隔符分割字段,第一個字段是輸入值,第二個字段是與逗號前面的輸入值相對應的輸出值。你可以用這個文件作為輸入參數。
(1) 創建一個 Python 文件 regressor.py,然后在里面增加下面幾行代碼:
import sysimport numpy as npfilename = sys.argv[1]X = []y = []with open(filename, 'r') as f:? ? for line in f.readlines():? ? ? ? xt, yt = [float(i) for i in line.split(',')]? ? ? ? X.append(xt)? ? ? ? y.append(yt)
把輸入數據加載到變量X和y,其中X是數據,y是標記。在代碼的for循環體中,我們解析每行數據,用逗號分割字段。然后,把字段轉化為浮點數,并分別保存到變量X和y中。
(2) 建立機器學習模型時,需要用一種方法來驗證模型,檢查模型是否達到一定的滿意度(satisfactory level)。為了實現這個方法,把數據分成兩組:訓練數據集(training dataset)與測試數據集(testing dataset)。訓練數據集用來建立模型,測試數據集用來驗證模型對未知數據的學習效果。因此,先把數據分成訓練數據集與測試數據集:
num_training = int(0.8 * len(X))num_test = len(X) - num_training# 訓練數據X_train = np.array(X[:num_training]).reshape((num_training,1))y_train = np.array(y[:num_training])# 測試數據X_test = np.array(X[num_training:]).reshape((num_test,1))y_test = np.array(y[num_training:])
這里用80%的數據作為訓練數據集,其余20%的數據作為測試數據集。
(3) 現在已經準備好訓練模型。接下來創建一個回歸器對象,代碼如下所示:
from sklearn import linear_model# 創建線性回歸對象linear_regressor = linear_model.LinearRegression()# 用訓練數據集訓練模型linear_regressor.fit(X_train, y_train)
(4) 我們利用訓練數據集訓練了線性回歸器。向fit方法提供輸入數據即可訓練模型。用下面的代碼看看它如何擬合:
import matplotlib.pyplot as plty_train_pred = linear_regressor.predict(X_train)plt.figure()plt.scatter(X_train, y_train, color='green')plt.plot(X_train, y_train_pred, color='black', linewidth=4)plt.title('Training data')plt.show()
(5) 在命令行工具中執行如下命令:
$ python regressor.py data_singlevar.txt
就會看到如圖1-2所示的線性回歸。
?
圖 1-2
(6) 在前面的代碼中,我們用訓練的模型預測了訓練數據的輸出結果,但這并不能說明模型對未知的數據也適用,因為我們只是在訓練數據上運行模型。這只能體現模型對訓練數據的擬合效果。從圖1-2中可以看到,模型訓練的效果很好。
(7) 接下來用模型對測試數據集進行預測,然后畫出來看看,代碼如下所示:
y_test_pred = linear_regressor.predict(X_test)plt.scatter(X_test, y_test, color='green')plt.plot(X_test, y_test_pred, color='black', linewidth=4)plt.title('Test data')plt.show()
運行代碼,可以看到如圖1-3所示的線性回歸。
?
圖 1-3
1.5 計算回歸準確性
現在已經建立了回歸器,接下來最重要的就是如何評價回歸器的擬合效果。在模型評價的相關內容中,用誤差(error)表示實際值與模型預測值之間的差值。
1.5.1 準備工作
下面快速了解幾個衡量回歸器擬合效果的重要指標(metric)。回歸器可以用許多不同的指標進行衡量,部分指標如下所示。
平均絕對誤差(mean absolute error):這是給定數據集的所有數據點的絕對誤差平均值。均方誤差(mean squared error):這是給定數據集的所有數據點的誤差的平方的平均值。這是最流行的指標之一。中位數絕對誤差(median absolute error):這是給定數據集的所有數據點的誤差的中位數。這個指標的主要優點是可以消除異常值(outlier)的干擾。測試數據集中的單個壞點不會影響整個誤差指標,均值誤差指標會受到異常點的影響。解釋方差分(explained variance score):這個分數用于衡量我們的模型對數據集波動的解釋能力。如果得分1.0分,那么表明我們的模型是完美的。R方得分(R2 score):這個指標讀作“R方”,是指確定性相關系數,用于衡量模型對未知樣本預測的效果。最好的得分是1.0,值也可以是負數。
1.5.2 詳細步驟
scikit-learn 里面有一個模塊,提供了計算所有指標的功能。重新打開一個 Python 文件,然后輸入以下代碼:
import sklearn.metrics as smprint "Mean absolute error =", round(sm.mean_absolute_error(y_test, y_test_pred), 2)print "Mean squared error =", round(sm.mean_squared_error(y_test, y_ test_pred), 2)print "Median absolute error =", round(sm.median_absolute_error(y_ test, y_test_pred), 2)print "Explained variance score =", round(sm.explained_variance_ score(y_test, y_test_pred), 2)print "R2 score =", round(sm.r2_score(y_test, y_test_pred), 2)
每個指標都描述得面面俱到是非常乏味的,因此只選擇一兩個指標來評估我們的模型。通常的做法是盡量保證均方誤差最低,而且解釋方差分最高。
1.6 保存模型數據
模型訓練結束之后,如果能夠把模型保存成文件,那么下次再使用的時候,只要簡單地加載就可以了。
詳細步驟
用程序保存模型的具體操作步驟如下。
(1) 在 Python 文件 regressor.py 中加入以下代碼:
import cPickle as pickleoutput_model_file = 'saved_model.pkl'with open(output_model_file, 'w') as f:? ? pickle.dump(linear_regressor, f)
(2) 回歸模型會保存在 saved_model.pkl 文件中。下面看看如何加載并使用它,代碼如下所示:
with open(output_model_file, 'r') as f:? ? model_linregr = pickle.load(f)y_test_pred_new = model_linregr.predict(X_test)print "\nNew mean absolute error =", round(sm.mean_absolute_ error(y_test, y_test_pred_new), 2)
(3) 這里只是把回歸模型從 Pickle 文件加載到model_linregr變量中。你可以將打印結果與前面的結果進行對比,確認模型與之前的一樣。
1.7 創建嶺回歸器
線性回歸的主要問題是對異常值敏感。在真實世界的數據收集過程中,經常會遇到錯誤的度量結果。而線性回歸使用的普通最小二乘法,其目標是使平方誤差最小化。這時,由于異常值誤差的絕對值很大,因此會引起問題,從而破壞整個模型。
1.7.1 準備工作
先看圖1-4。
?
圖 1-4
右下角的兩個數據點明顯是異常值,但是這個模型需要擬合所有的數據點,因此導致整個模型都錯了。僅憑直覺觀察,我們就會覺得如圖1-5的擬合結果更好。
?
圖 1-5
普通最小二乘法在建模時會考慮每個數據點的影響,因此,最終模型就會像圖1-4顯示的直線那樣。顯然,我們發現這個模型不是最優的。為了避免這個問題,我們引入正則化項的系數作為閾值來消除異常值的影響。這個方法被稱為嶺回歸。
1.7.2 詳細步驟
接下來看看如何用 Python 建立嶺回歸器。
(1) 你可以從 data_multi_variable.txt 文件中加載數據。這個文件的每一行都包含多個數值。除了最后一個數值外,前面的所有數值構成輸入特征向量。
(2) 把下面的代碼加入 regressor.py 文件中。我們用一些參數初始化嶺回歸器:
ridge_regressor = linear_model.Ridge(alpha=0.01, fit_ intercept=True, max_iter=10000)
(3) alpha參數控制回歸器的復雜程度。當alpha趨于0時,嶺回歸器就是用普通最小二乘法的線性回歸器。因此,如果你希望模型對異常值不那么敏感,就需要設置一個較大的alpha值。這里把alpha值設置為0.01。
(4) 下面讓我們來訓練嶺回歸器。
ridge_regressor.fit(X_train, y_train)y_test_pred_ridge = ridge_regressor.predict(X_test)print "Mean absolute error =", round(sm.mean_absolute_error? ? (y_ test, y_test_pred_ridge), 2)print "Mean squared error =", round(sm.mean_squared_error? ? (y_test, y_test_pred_ridge), 2)print "Median absolute error =", round(sm.median_absolute_error? ? (y_ test, y_test_pred_ridge), 2)print "Explain variance score =", round(sm.explained_variance_ score? ? (y_test, y_test_pred_ridge), 2)print "R2 score =", round(sm.r2_score(y_test, y_test_pred_ridge), 2)
運行代碼檢查誤差指標。可以用同樣的數據建立一個線性回歸器,并與嶺回歸器的結果進行比較,看看把正則化引入回歸模型之后的效果如何。
第01章:監督學習(下)
?
?
?
? ?
? ? ?1.8 創建多項式回歸器
? ? ? ?1.8.1 準備工作1.8.2 詳細步驟1.9 估算房屋價格
? ? ? ?1.9.1 準備工作1.9.2 詳細步驟1.10 計算特征的相對重要性1.11 評估共享單車的需求分布
? ? ? ?1.11.1 準備工作1.11.2 詳細步驟1.11.3 更多內容
?
1.8 創建多項式回歸器
線性回歸模型有一個主要的局限性,那就是它只能把輸入數據擬合成直線,而多項式回歸模型通過擬合多項式方程來克服這類問題,從而提高模型的準確性。
1.8.1 準備工作
先看圖1-6。
?
圖 1-6
從圖1-6中可以看到,數據點本身的模式中帶有自然的曲線,而線性模型是不能捕捉到這一點的。再來看看多項式模型的效果,如圖1-7所示。
?
圖 1-7
圖1-7中的虛線表示線性回歸模型,實線表示多項式回歸模型。這個模型的曲率是由多項式的次數決定的。隨著模型曲率的增加,模型變得更準確。但是,增加曲率的同時也增加了模型的復雜性,因此擬合速度會變慢。當我們對模型的準確性的理想追求與計算能力限制的殘酷現實發生沖突時,就需要綜合考慮了。
1.8.2 詳細步驟
(1) 將下面的代碼加入 Python 文件 regressor.py 中:
from sklearn.preprocessing import PolynomialFeaturespolynomial = PolynomialFeatures(degree=3)
(2) 上一行將曲線的多項式的次數的初始值設置為3。下面用數據點來計算多項式的參數:
X_train_transformed = polynomial.fit_transform(X_train)
其中,X_train_transformed表示多項式形式的輸入,與線性回歸模型是一樣大的。
(3) 接下來用文件中的第一個數據點來檢查多項式模型是否能夠準確預測:
datapoint = [0.39,2.78,7.11]poly_datapoint = polynomial.fit_transform(datapoint)poly_linear_model = linear_model.LinearRegression()poly_linear_model.fit(X_train_transformed, y_train)print "\nLinear regression:", linear_regressor.predict(datapoint) [0]print "\nPolynomial regression:", poly_linear_model.predict(poly_datapoint)[0]
多項式回歸模型計算變量數據點的值恰好就是輸入數據文件中的第一行數據值。再用線性回歸模型測試一下,唯一的差別就是展示數據的形式。運行代碼,可以看到下面的結果:
Linear regression: -11.0587294983Polynomial regression: -10.9480782122
可以發現,多項式回歸模型的預測值更接近實際的輸出值。如果想要數據更接近實際輸出值,就需要增加多項式的次數。
(4) 將多項式的次數加到10看看結果:
polynomial = PolynomialFeatures(degree=10)
可以看到下面的結果:
Polynomial regression: -8.20472183853
現在,你可以發現預測值與實際的輸出值非常地接近。
1.9 估算房屋價格
是時候用所學的知識來解決真實世界的問題了。讓我們用這些原理來估算房屋價格。房屋估價是理解回歸分析最經典的案例之一,通常是一個不錯的切入點。它符合人們的直覺,而且與人們的生活息息相關,因此在用機器學習處理復雜事情之前,通過房屋估價可以更輕松地理解相關概念。我們將使用帶 AdaBoost 算法的決策樹回歸器(decision tree regressor)來解決這個問題。
1.9.1 準備工作
決策樹是一個樹狀模型,每個節點都做出一個決策,從而影響最終結果。葉子節點表示輸出數值,分支表示根據輸入特征做出的中間決策。AdaBoost 算法是指自適應增強(adaptive boosting)算法,這是一種利用其他系統增強模型準確性的技術。這種技術是將不同版本的算法結果進行組合,用加權匯總的方式獲得最終結果,被稱為弱學習器(weak learners)。AdaBoost 算法在每個階段獲取的信息都會反饋到模型中,這樣學習器就可以在后一階段重點訓練難以分類的樣本。這種學習方式可以增強系統的準確性。
首先使用 AdaBoost 算法對數據集進行回歸擬合,再計算誤差,然后根據誤差評估結果,用同樣的數據集重新擬合。可以把這些看作是回歸器的調優過程,直到達到預期的準確性。假設你擁有一個包含影響房價的各種參數的數據集,我們的目標就是估計這些參數與房價的關系,這樣就可以根據未知參數估計房價了。
1.9.2 詳細步驟
(1) 創建一個新的 Python 文件 housing.py,然后加入下面的代碼:
import numpy as npfrom sklearn.tree import DecisionTreeRegressorfrom sklearn.ensemble import AdaBoostRegressorfrom sklearn import datasetsfrom sklearn.metrics import mean_squared_error, explained_variance_scorefrom sklearn.utils import shuffleimport matplotlib.pyplot as plt
(2) 網上有一個標準房屋價格數據庫,人們經常用它來研究機器學習。你可以在這里下載數據。不過 scikit-learn 提供了數據接口,可以直接通過下面的代碼加載數據:
housing_data = datasets.load_boston()
每個數據點由影響房價的13個輸入參數構成。你可以用housing_data.data獲取輸入的數據,用housing_data.target獲取對應的房屋價格。
(3) 接下來把輸入數據與輸出結果分成不同的變量。我們可以通過shuffle函數把數據的順序打亂:
X, y = shuffle(housing_data.data, housing_data.target, random_ state=7)
(4) 參數random_state用來控制如何打亂數據,讓我們可以重新生成結果。接下來把數據分成訓練數據集和測試數據集,其中80%的數據用于訓練,剩余20%的數據用于測試:
num_training = int(0.8 * len(X))X_train, y_train = X[:num_training], y[:num_training]X_test, y_test = X[num_training:], y[num_training:]
(5) 現在已經可以擬合一個決策樹回歸模型了。選一個最大深度為4的決策樹,這樣可以限制決策樹不變成任意深度:
dt_regressor = DecisionTreeRegressor(max_depth=4)dt_regressor.fit(X_train, y_train)
(6) 再用帶 AdaBoost 算法的決策樹回歸模型進行擬合:
ab_regressor =AdaBoostRegressor(DecisionTreeRegressor(max_depth=4), n_estimators=400, random_state=7)ab_regressor.fit(X_train, y_train)
這樣可以幫助我們對比訓練效果,看看 AdaBoost 算法對決策樹回歸器的訓練效果有多大改善。
(7) 接下來評價決策樹回歸器的訓練效果:
y_pred_dt = dt_regressor.predict(X_test)mse = mean_squared_error(y_test, y_pred_dt)evs = explained_variance_score(y_test, y_pred_dt)print "\n#### Decision Tree performance ####"print "Mean squared error =", round(mse, 2)print "Explained variance score =", round(evs, 2)
(8) 現在評價一下 AdaBoost 算法改善的效果:
y_pred_ab = ab_regressor.predict(X_test)mse = mean_squared_error(y_test, y_pred_ab)evs = explained_variance_score(y_test, y_pred_ab)print "\n#### AdaBoost performance ####"print "Mean squared error =", round(mse, 2)print "Explained variance score =", round(evs, 2)
(9) 命令行工具顯示的輸出結果如下所示:
#### 決策樹學習效果 ####Mean squared error = 14.79Explained variance score = 0.82#### AdaBoost算法改善效果 ####Mean squared error = 7.54Explained variance score = 0.91
前面的結果表明,AdaBoost 算法可以讓誤差更小,且解釋方差分更接近1。
1.10 計算特征的相對重要性
所有特征都同等重要嗎?在這個案例中,我們用了13個特征,它們對模型都有貢獻。但是,有一個重要的問題出現了:如何判斷哪個特征更加重要?顯然,所有的特征對結果的貢獻是不一樣的。如果需要忽略一些特征,就需要知道哪些特征不太重要。scikit-learn 里面有這樣的功能。
詳細步驟
(1) 畫出特征的相對重要性,在 housing.py 文件中加入下面幾行代碼:
plot_feature_importances(dt_regressor.feature_importances_,? ? ? ? 'Decision Tree regressor', housing_data.feature_names)plot_feature_importances(ab_regressor.feature_importances_,? ? ? ? 'AdaBoost regressor', housing_data.feature_names)
回歸器對象有一個feature_importances_方法會告訴我們每個特征的相對重要性。
(2) 接下來需要定義plot_feature_importances來畫出條形圖:
def plot_feature_importances(feature_importances, title, feature_names):? ? # 將重要性值標準化? ? feature_importances = 100.0 * (feature_importances / max(feature_importances))? ? # 將得分從高到低排序? ? index_sorted = np.flipud(np.argsort(feature_importances))? ? # 讓X坐標軸上的標簽居中顯示? ? pos = np.arange(index_sorted.shape[0]) + 0.5? ? # 畫條形圖? ? plt.figure()? ? plt.bar(pos, feature_importances[index_sorted], align='center')? ? plt.xticks(pos, feature_names[index_sorted])? ? plt.ylabel('Relative Importance')? ? plt.title(title)? ? plt.show()
(3) 我們從feature_importances_方法里取值,然后把數值放大到0~100的范圍內。運行前面的代碼,可以看到兩張圖(不帶 AdaBoost 算法與帶 AdaBoost 算法兩種模型)。仔細觀察圖1-8和圖1-9,看看能從決策樹回歸器中獲得什么。
?
圖 1-8
(4) 從圖1-8可以發現,不帶 AdaBoost 算法的決策樹回歸器顯示的最重要特征是 RM。再看看帶 AdaBoost 算法的決策樹回歸器的特征重要性排序條形圖,如圖1-9所示。
?
圖 1-9
加入 AdaBoost 算法之后,房屋估價模型的最重要特征是 LSTAT。在現實生活中,如果對這個數據集建立不同的回歸器,就會發現最重要的特征是 LSTAT,這足以體現 AdaBoost 算法對決策樹回歸器訓練效果的改善。
1.11 評估共享單車的需求分布
本節將用一種新的回歸方法解決共享單車的需求分布問題。我們采用隨機森林回歸器(random forest regressor)估計輸出結果。隨機森林是一個決策樹集合,它基本上就是用一組由數據集的若干子集構建的決策樹構成,再用決策樹平均值改善整體學習效果。
1.11.1 準備工作
我們將使用 bike_day.csv 文件中的數據集獲取。這份數據集一共16列,前兩列是序列號與日期,分析的時候可以不用;最后三列數據是不同類型的輸出結果;最后一列是第十四列與第十五列的和,因此建立模型時可以不考慮第十四列與第十五列。
1.11.2 詳細步驟
接下來看看 Python 如何解決這個問題。如果你下載了本書源代碼,就可以看到 bike_sharing.py 文件里已經包含了完整代碼。這里將介紹若干重要的部分。
(1) 首先導入一些新的程序包,如下:
import csvfrom sklearn.ensemble import RandomForestRegressorfrom housing import plot_feature_importances
(2) 我們需要處理 CSV 文件,因此加入了 csv 程序包來讀取 CSV 文件。由于這是一個全新的數據集,因此需要自己定義一個數據集加載函數:
def load_dataset(filename):? ? file_reader = csv.reader(open(filename, 'rb'), delimiter=',')? ? X, y = [], []? ? for row in file_reader:? ? ? ? X.append(row[2:13])? ? ? ? y.append(row[-1])? ? # 提取特征名稱? ? feature_names = np.array(X[0])? ? # 將第一行特征名稱移除,僅保留數值? ? return np.array(X[1:]).astype(np.float32), np.array(y[1:]).astype(np.float32), feature_names
在這個函數中,我們從 CSV 文件讀取了所有數據。把數據顯示在圖形中時,特征名稱非常有用。把特征名稱數據從輸入數值中分離出來,并作為函數返回值。
(3) 讀取數據,并打亂數據順序,讓新數據與原來文件中數據排列的順序沒有關聯性:
X, y, feature_names = load_dataset(sys.argv[1])X, y = shuffle(X, y, random_state=7)
(4) 和之前的做法一樣,需要將數據分成訓練數據和測試數據。這一次,我們將90%的數據用于訓練,剩余10%的數據用于測試:
num_training = int(0.9 * len(X))X_train, y_train = X[:num_training], y[:num_training]X_test, y_test = X[num_training:], y[num_training:]
(5) 下面開始訓練回歸器:
rf_regressor = RandomForestRegressor(n_estimators=1000, max_depth=10, min_samples_split=1)rf_regressor.fit(X_train, y_train)
其中,參數n_estimators是指評估器(estimator)的數量,表示隨機森林需要使用的決策樹數量;參數max_depth是指每個決策樹的最大深度;參數min_samples_split是指決策樹分裂一個節點需要用到的最小數據樣本量。
(6) 評價隨機森林回歸器的訓練效果:
y_pred = rf_regressor.predict(X_test)mse = mean_squared_error(y_test, y_pred)evs = explained_variance_score(y_test, y_pred)print "\n#### Random Forest regressor performance ####"print "Mean squared error =", round(mse, 2)print "Explained variance score =", round(evs, 2)
(7) 由于已經有畫出特征重要性條形圖的函數plot_feature_importances了,接下來直接調用它:
plot_feature_importances(rf_regressor.feature_importances_, 'Random Forest regressor', feature_names)
執行代碼,可以看到如圖1-10所示的圖形。
?
圖 1-10
看來溫度(temp)是影響自行車租賃的最重要因素。
1.11.3 更多內容
把第十四列與第十五列數據加入數據集,看看結果有什么區別。在新的特征重要性條形圖中,除了這兩個特征外,其他特征都變成了0。這是由于輸出結果可以通過簡單地對第十四列與第十五列數據求和得出,因此算法不需要其他特征計算結果。在數據集加載函數load_dataset中,我們需要對for循環內的取值范圍稍作調整:
X.append(row[2:15])
現在再畫出特征重要性條形圖,可以看到如圖1-11所示的柱形圖。
?
圖 1-11
與預想的一樣,從圖中可以看出,只有這兩個特征是重要的,這確實也符合常理,因為最終結果僅僅是這兩個特征相加得到的。因此,這兩個變量與輸出結果有直接的關系,回歸器也就認為它不需要其他特征來預測結果了。在消除數據集冗余變量方面,這是非常有用的工具。
還有一份按小時統計的自行車共享數據 bike_hour.csv。我們需要用到第3~14列,因此先對數據集加載函數load_dataset做一點調整:
X.append(row[2:14])
運行代碼,可以看到回歸器的訓練結果如下:
#### 隨機森林學習效果 ####Mean squared error = 2619.87Explained variance score = 0.92
特征重要性條形圖如圖1-12所示。
?
圖 1-12
圖1-12中顯示,最重要的特征是一天中的不同時點(hr),這也完全符合人們的直覺;其次重要的是溫度,與我們之前分析的結果一致。
第02章:創建分類器(上)
?
?
?
? ?
? ? ?2.1 簡介2.2 建立簡單分類器
? ? ? ?2.2.1 詳細步驟2.2.2 更多內容2.3 建立邏輯回歸分類器
? ? ? ?詳細步驟2.4 建立樸素貝葉斯分類器
? ? ? ?詳細步驟
?
在這一章,我們將介紹以下主題:
建立簡單分類器(simple classifier)建立邏輯回歸分類器(logistic regression classifier)建立樸素貝葉斯分類器(Na?ve Bayes classifier)將數據集分割成訓練集和測試集用交叉驗證(cross-validation)檢驗模型準確性混淆矩陣(confusion matrix)可視化提取性能報告根據汽車特征評估質量生成驗證曲線(validation curves)生成學習曲線(learning curves)估算收入階層(income bracket)
2.1 簡介
在機器學習領域中,分類是指利用數據的特性將其分成若干類型的過程。分類與上一章介紹的回歸不同,回歸的輸出結果是實數。監督學習分類器就是用帶標記的訓練數據建立一個模型,然后對未知數據進行分類。
分類器可以是實現分類功能的任意算法,最簡單的分類器就是簡單的數學函數。在真實世界中,分類器可以是非常復雜的形式。在學習過程中,可以看到二元(binary)分類器,將數據分成兩類,也可以看到多元(multiclass)分類器,將數據分成兩個以上的類型。解決分類問題的數據手段都傾向于解決二元分類問題,可以通過不同的形式對其進行擴展,進而解決多元分類問題。
分類器準確性的估計是機器學習領域的重要內容。我們需要學會如何使用現有的數據獲取新的思路(機器學習模型),然后把模型應用到真實世界中。在這一章里,我們將看到許多類似的主題。
2.2 建立簡單分類器
本節學習如何用訓練數據建立一個簡單分類器。
2.2.1 詳細步驟
(1)使用 simple_classifier.py 文件作為參考。假設你已經和上一章一樣導入了numpy和matplotlib.pyplot程序包,那么需要創建一些樣本數據:
X = np.array([[3,1], [2,5], [1,8], [6,4], [5,2], [3,5], [4,7], [4,-1]])
(2) 為這些數據點分配一些標記:
y = [0, 1, 1, 0, 0, 1, 1, 0]
(3) 因為只有兩個類,所以y列表包含0和1。一般情況下,如果你有 N個類,那么y的取值范圍就是從0到 N-1。接下來按照類型標記把樣本數據分成兩類:
class_0 = np.array([X[i] for i in range(len(X)) if y[i]==0])class_1 = np.array([X[i] for i in range(len(X)) if y[i]==1])
(4) 為了對數據有個直觀的認識,把圖像畫出來,如下所示:
plt.figure()plt.scatter(class_0[:,0], class_0[:,1], color='black', marker='s')plt.scatter(class_1[:,0], class_1[:,1], color='black', marker='x')
這是一個散點圖(scatterplot),用方塊和叉表示兩類數據。在前面的代碼中,參數marker用來表示數據點的形狀。用方塊表示class_0的數據,用叉表示class_1的數據。運行代碼,可以看到如圖2-1所示的圖形。
(5) 在之前的兩行代碼中,只是用變量X與y之間的映射關系創建了兩個列表。如果要你直觀地展示數據點的不同類型,在兩類數據間畫一條分割線,那么怎么實現呢?你只要用直線方程在兩類數據之間畫一條直線就可以了。下面看看如何實現:
line_x = range(10)line_y = line_x
(6) 用數學公式 y = x 創建一條直線。代碼如下所示:
plt.figure()plt.scatter(class_0[:,0], class_0[:,1], color='black', marker='s')plt.scatter(class_1[:,0], class_1[:,1], color='black', marker='x')plt.plot(line_x, line_y, color='black', linewidth=3)plt.show()
?
圖 2-1
(7) 運行代碼,可以看到如圖2-2所示的圖形。
?
圖 2-2
2.2.2 更多內容
用以下規則建立了一個簡單的分類器:如果輸入點(a, b)的a大于或等于b,那么它屬于類型class_0;反之,它屬于class_1。如果對數據點逐個進行檢查,你會發現每個數都是這樣,這樣你就建立了一個可以識別未知數據的線性分類器(linear classifier)。之所以稱其為線性分類器,是因為分割線是一條直線。如果分割線是一條曲線,就是非線性分類器(nonlinear classifier)。
這樣簡單的分類器之所以可行,是因為數據點很少,可以直觀地判斷分割線。如果有幾千個數據點呢?如何對分類過程進行一般化處理(generalize)呢?下一節將介紹這一主題。
2.3 建立邏輯回歸分類器
雖然這里也出現了上一章介紹的回歸這個詞,但邏輯回歸其實是一種分類方法。給定一組數據點,需要建立一個可以在類之間繪制線性邊界的模型。邏輯回歸就可以對訓練數據派生的一組方程進行求解來提取邊界。
詳細步驟
(1) 下面看看用 Python 如何實現邏輯回歸。我們使用 logistic_regression.py 文件作為參考。假設已經導入了需要使用的程序包,接下來創建一些帶訓練標記的樣本數據:
import numpy as npfrom sklearn import linear_modelimport matplotlib.pyplot as pltX = np.array([[4, 7], [3.5, 8], [3.1, 6.2], [0.5, 1], [1, 2],[1.2, 1.9], [6, 2], [5.7, 1.5], [5.4, 2.2]])y = np.array([0, 0, 0, 1, 1, 1, 2, 2, 2])
這里假設一共有3個類。
(2) 初始化一個邏輯回歸分類器:
classifier = linear_model.LogisticRegression(solver='liblinear', C=100)
前面的函數有一些輸入參數需要設置,但是最重要的兩個參數是solver和C。參數solver用于設置求解系統方程的算法類型,參數C表示正則化強度,數值越小,表示正則化強度越高。
(3) 接下來訓練分類器:
classifier.fit(X, y)
(4) 畫出數據點和邊界:
plot_classifier(classifier, X, y)
需要定義如下畫圖函數:
def plot_classifier(classifier, X, y):? ? # 定義圖形的取值范圍? ? x_min, x_max = min(X[:, 0]) - 1.0, max(X[:, 0]) + 1.0? ? y_min, y_max = min(X[:, 1]) - 1.0, max(X[:, 1]) + 1.0
預測值表示我們在圖形中想要使用的數值范圍,通常是從最小值到最大值。我們增加了一些余量(buffer),例如上面代碼中的1.0。
(5) 為了畫出邊界,還需要利用一組網格(grid)數據求出方程的值,然后把邊界畫出來。下面繼續定義網格:
? ? # 設置網格數據的步長? ? step_size = 0.01? ? # 定義網格? ? x_values, y_values = np.meshgrid(np.arange(x_min, x_max, step_size), np.arange(y_min, y_max, step_size))
變量x_values和y_values包含求解方程數值的網格點。
(6) 計算出分類器對所有數據點的分類結果:
? ? # 計算分類器輸出結果? ? mesh_output = classifier.predict(np.c_[x_values.ravel(), y_values.ravel()])? ? # 數組維度變形? ? mesh_output = mesh_output.reshape(x_values.shape)
(7) 用彩色區域畫出各個類型的邊界:
? ? # 用彩圖畫出分類結果? ? plt.figure()? ? # 選擇配色方案? ? plt.pcolormesh(x_values, y_values, mesh_output, cmap=plt.cm.gray)
這基本算是一個三維畫圖器,既可以畫二維數據點,又可以用色彩清單(color scheme)表示不同區域的相關屬性。你可以在這里找到所有的色彩清單。
(8) 接下來再把訓練數據點畫在圖上:
? ? plt.scatter(X[:, 0], X[:, 1], c=y, s=80, edgecolors='black', linewidth=1, cmap=plt.cm.Paired)? ? # 設置圖形的取值范圍? ? plt.xlim(x_values.min(), x_values.max())? ? plt.ylim(y_values.min(), y_values.max())? ? # 設置X軸與Y軸? ? plt.xticks((np.arange(int(min(X[:, 0])-1), int(max(X[:, 0])+1), 1.0)))? ? plt.yticks((np.arange(int(min(X[:, 1])-1), int(max(X[:, 1])+1), 1.0)))? ? plt.show()
其中,plt.scatter把數據點畫在二維圖上。X[:, 0]表示0軸(X軸)的坐標值,X[:, 1]表示1軸(Y軸)的坐標值。c=y表示顏色的使用順序。用目標標記映射cmap的顏色表。我們肯定希望不同的標記使用不同的顏色,因此,用y作為映射。坐標軸的取值范圍由plt.xlim和plt.ylim確定。為了標記坐標軸的數值,需要使用plt.xticks和plt.yticks。在坐標軸上標出坐標值,就可以直觀地看出數據點的位置。在前面的代碼中,我們希望坐標軸的最大值與最小值之前的刻度是單位刻度,還希望這些刻度值是整數,因此用int()函數對最值取整。
(9) 運行代碼,就可以看到如圖2-3所示的輸出結果。
?
圖 2-3
(10) 下面看看參數C對模型的影響。參數C表示對分類錯誤(misclassification)的懲罰值(penalty)。如果把參數C設置為1.0,會得到如圖2-4所示的結果。
?
圖 2-4
(11) 如果把參數C設置為10000,會得到如圖2-5所示的結果。
?
圖 2-5
隨著參數C的不斷增大,分類錯誤的懲罰值越高。因此,各個類型的邊界更優。
2.4 建立樸素貝葉斯分類器
樸素貝葉斯分類器是用貝葉斯定理進行建模的監督學習分類器。下面看看如何建立一個樸素貝葉斯分類器。
詳細步驟
(1) 我們使用naive_bayes.py文件作為參考。首先導入兩個程序包:
from sklearn.naive_bayes import GaussianNBfrom logistic_regression import plot_classifier
(2) 下載的示例代碼中有一個data_multivar.txt文件,里面包含了將要使用的數據,每一行數據都是由逗號分隔符分割的數值。從文件中加載數據:
input_file = 'data_multivar.txt'X = []y = []with open(input_file, 'r') as f:? ? for line in f.readlines():? ? ? ? data = [float(x) for x in line.split(',')]? ? ? ? X.append(data[:-1])? ? ? ? y.append(data[-1])X = np.array(X)y = np.array(y)
我們已經把輸入數據和標記分別加載到變量X和y中了。
(3) 下面建立一個樸素貝葉斯分類器:
classifier_gaussiannb = GaussianNB()classifier_gaussiannb.fit(X, y)y_pred = classifier_gaussiannb.predict(X)
GaussianNB函數指定了正態分布樸素貝葉斯模型(Gaussian Naive Bayes model)。
(4) 接下來計算分類器的準確性:
accuracy = 100.0 * (y == y_pred).sum() / X.shape[0]print "Accuracy of the classifier =", round(accuracy, 2), "%"
(5) 畫出數據點和邊界:
plot_classifier(classifier_gaussiannb, X, y)
可以看到如圖2-6所示的圖形。
?
圖 2-6
從圖2-6中可以發現,這里的邊界沒有嚴格地區分所有數據點。在前面這個例子中,我們是對所有的數據進行訓練。機器學習的一條最佳實踐是用沒有重疊(nonoverlapping)的數據進行訓練和測試。理想情況下,需要一些尚未使用的數據進行測試,可以方便準確地評估模型在未知數據上的執行情況。scikit-learn 有一個方法可以非常好地解決這個問題,我們將在下一節介紹它。
第02章:創建分類器(中)
?
?
?
? ?
? ? ?2.5 將數據集分割成訓練集和測試集
? ? ? ?詳細步驟2.6 用交叉驗證檢驗模型準確性
? ? ? ?2.6.1 準備工作2.6.2 詳細步驟2.7 混淆矩陣可視化
? ? ? ?詳細步驟2.8 提取性能報告
? ? ? ?詳細步驟2.9 根據汽車特征評估質量
? ? ? ?2.9.1 準備工作2.9.2 詳細步驟
?
2.5 將數據集分割成訓練集和測試集
本節一起來看看如何將數據合理地分割成訓練數據集和測試數據集。
詳細步驟
(1) 增加下面的代碼片段到上一節的 Python 文件中:
from sklearn import cross_validationX_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.25, random_state=5)classifier_gaussiannb_new = GaussianNB()classifier_gaussiannb_new.fit(X_train, y_train)
這里,我們把參數test_size設置成0.25,表示分配了25%的數據給測試數據集。剩下75%的數據將用于訓練數據集。
(2) 用分類器對測試數據進行測試:
y_test_pred = classifier_gaussiannb_new.predict(X_test)
(3) 計算分類器的準確性:
accuracy = 100.0 * (y_test == y_test_pred).sum() / X_test.shape[0]print "Accuracy of the classifier =", round(accuracy, 2), "%"
(4) 畫出測試數據的數據點及其邊界:
plot_classifier(classifier_gaussiannb_new, X_test, y_test)
(5) 可以看到如圖2-7所示的圖形。
?
圖 2-7
2.6 用交叉驗證檢驗模型準確性
交叉驗證是機器學習的重要概念。在上一節中,我們把數據分成了訓練數據集和測試數據集。然而,為了能夠讓模型更加穩定,還需要用數據集的不同子集進行反復的驗證。如果只是對特定的子集進行微調,最終可能會過度擬合(overfitting)模型。過度擬合是指模型在已知數據集上擬合得超級好,但是一遇到未知數據就掛了。我們真正想要的,是讓機器學習模型能夠適用于未知數據。
2.6.1 準備工作
介紹如何實現交叉驗證之前,先討論一下性能指標。當處理機器學習模型時,通常關心3個指標:精度(precision)、召回率(recall)和F1得分(F1 score)。可以用參數評分標準(parameter scoring)獲得各項指標的得分。精度是指被分類器正確分類的樣本數量占分類器總分類樣本數量的百分比(分類器分類結果中,有一些樣本分錯了)。召回率是指被應正確分類的樣本數量占某分類總樣本數量的百分比(有一些樣本屬于某分類,但分類器卻沒有分出來)。
假設數據集有100個樣本,其中有82個樣本是我們感興趣的,現在想用分類器選出這82個樣本。最終,分類器選出了73個樣本,它認為都是我們感興趣的。在這73個樣本中,其實只有65個樣本是我們感興趣的,剩下的8個樣本我們不感興趣,是分類器分錯了。可以如下方法計算分類器的精度:
分類正確的樣本數量 = 65總分類樣本數量 = 73精度 = 65 / 73 = 89.04%
召回率的計算過程如下:
數據集中我們感興趣的樣本數量 = 82分類正確的樣本數量 = 65召回率 = 65 / 82 = 79.26%
一個給力的機器學習模型需要同時具備良好的精度和召回率。這兩個指標是二律背反的,一個指標達到100%,那么另一個指標就會非常差!我們需要保持兩個指標能夠同時處于合理高度。為了量化兩個指標的均衡性,引入了 F1得分指標,是精度和召回率的合成指標,實際上是精度和召回率的調和均值(harmonic mean):
F1 得分=2×精度×召回率 / (精度+召回率)
上面示例中 F1得分的計算過程如下:
F1 得分=2×0.89×0.79 / (0.89+0.79)=0.8370
2.6.2 詳細步驟
(1) 下面看看如何實現交叉驗證,并提取性能指標。首先計算精度:
num_validations = 5accuracy = cross_validation.cross_val_score(classifier_gaussiannb,? ? ? ? X, y,scoring='accuracy', cv=num_validations)print "Accuracy: " + str(round(100*accuracy.mean(), 2)) + "%"
(2) 用前面的方程分別計算精度、召回率和F1得分:
f1 = cross_validation.cross_val_score(classifier_gaussiannb,? ? ? ? X, y, scoring='f1_weighted', cv=num_validations)print "F1: " + str(round(100*f1.mean(), 2)) + "%"precision = cross_validation.cross_val_score(classifier_ gaussiannb,? ? ? ? X, y, scoring='precision_weighted', cv=num_validations)print "Precision: " + str(round(100*precision.mean(), 2)) + "%"recall = cross_validation.cross_val_score(classifier_gaussiannb,? ? ? ? X, y, scoring='recall_weighted', cv=num_validations)print "Recall: " + str(round(100*recall.mean(), 2)) + "%"
2.7 混淆矩陣可視化
混淆矩陣(confusion matrix)是理解分類模型性能的數據表,它有助于我們理解如何把測試數據分成不同的類。當想對算法進行調優時,就需要在對算法做出改變之前了解數據的錯誤分類情況。有些分類效果比其他分類效果更差,混淆矩陣可以幫助我們理解這些問題。先看看如圖2-8所示的混淆矩陣。
?
圖 2-8
在圖2-8中,我們可以看出不同類型的分類數據。理想情況下,我們希望矩陣非對角線元素都是0,這是最完美的分類結果。先看看class 0,一共52個樣本屬于class 0。如果對第一行數據求和,總數就是52。但是現在,只有45個樣本被正確地預測出來,分類器說另外4個樣本屬于class 1,還有3個樣本屬于class 2。用同樣的思路分析另外兩行數據,有意思的是,class 1里面有11個樣本被錯誤地預測成了class 0,占到了class 1總數的16%。這就是模型需要優化的切入點。
詳細步驟
(1) 我們用 confusion_matrix.py 文件作為參考。首先看看如何從數據中提取混淆矩陣:
from sklearn.metrics import confusion_matrixy_true = [1, 0, 0, 2, 1, 0, 3, 3, 3]y_pred = [1, 1, 0, 2, 1, 0, 1, 3, 3]confusion_mat = confusion_matrix(y_true, y_pred)plot_confusion_matrix(confusion_mat)
這里用了一些樣本數據,一共有4種類型,取值范圍是0~3,也列出了預測的標記類型。用confusion_matrix方法提取混淆矩陣,然后把它畫出來。
(2) 繼續定義混淆矩陣的畫圖函數:
# 顯示混淆矩陣def plot_confusion_matrix(confusion_mat):? ? plt.imshow(confusion_mat, interpolation='nearest', cmap=plt.cm.Paired)? ? plt.title('Confusion matrix')? ? plt.colorbar()? ? tick_marks = np.arange(4)? ? plt.xticks(tick_marks, tick_marks)? ? plt.yticks(tick_marks, tick_marks)? ? plt.ylabel('True label')? ? plt.xlabel('Predicted label')? ? plt.show()
這里用imshow函數畫混淆矩陣,其他函數都非常簡單,只使用相關函數設置了圖形的標題、顏色欄、刻度和標簽。參數tick_marks的取值范圍是0~3,因為數據集中有4個標記類型。np.arange函數會生成一個numpy數組。
(3) 運行代碼,可以看到如圖2-9所示的圖形。
?
圖 2-9
從圖2-9中可以看出,對角線的顏色很亮,我們希望它們越亮越好。黑色區域表示0。在非對角線的區域有一些灰色區域,表示分類錯誤的樣本量。例如,當樣本真實標記類型是0,而預測標記類型是1時,就像在第一行的第二格看到的那樣。事實上,所有的錯誤分類都屬于class-1,因為第二列有3個不為0的格子。這在圖2-9中顯示得一目了然。
2.8 提取性能報告
也可以直接用 scikit-learn 打印精度、召回率和 F1得分。接下來看看如何實現。
詳細步驟
(1) 在一個新的 Python 文件中加入下面的代碼:
from sklearn.metrics import classification_reporty_true = [1, 0, 0, 2, 1, 0, 3, 3, 3]y_pred = [1, 1, 0, 2, 1, 0, 1, 3, 3]target_names = ['Class-0', 'Class-1', 'Class-2', 'Class-3']print(classification_report(y_true, y_pred, target_names=target_names))
(2) 運行代碼,可以在命令行工具中看到如圖2-10所示的結果。
?
圖 2-10
不需要單獨計算各個指標,可以直接用這個函數從模型中提取所有統計值。
2.9 根據汽車特征評估質量
接下來看看如何用分類技術解決現實問題。我們將用一個包含汽車多種細節的數據集,例如車門數量、后備箱大小、維修成本等,來確定汽車的質量。分類的目的是把車輛的質量分成4種類型:不達標、達標、良好、優秀。
2.9.1 準備工作
你可以從這里下載數據集。
你需要把數據集中的每個值看成是字符串。考慮數據集中的6個屬性,其取值范圍是這樣的:
buying:取值范圍是vhigh、high、med、low;maint:取值范圍是vhigh、high、med、low;doors:取值范圍是2、3、4、5等;persons:取值范圍是2、4等;lug_boot:取值范圍是small、med、big;safety:取值范圍是low、med、high。
考慮到每一行都包含字符串屬性,需要假設所有特征都是字符串,并設置分類器。在上一章中,我們用隨機森林建立過回歸器,這里再用隨機森林建立分類器。
2.9.2 詳細步驟
(1) 參考 car.py 文件中的源代碼。首先導入兩個軟件包:
from sklearn import preprocessingfrom sklearn.ensemble import RandomForestClassifier
(2) 加載數據集:
input_file = 'path/to/dataset/car.data.txt'# 讀取數據X = []count = 0with open(input_file, 'r') as f:? ? for line in f.readlines():? ? ? ? data = line[:-1].split(',')? ? ? ? X.append(data)X = np.array(X)
每一行都包含由逗號分隔的單詞列表。因此,我們解析輸入文件,對每一行進行分割,然后將該列表附加到主數據。我們忽略每一行最后一個字符,因為那是一個換行符。由于 Python 程序包只能處理數值數據,所以需要把這些屬性轉換成程序包可以理解的形式。
(3) 在上一章中,我們介紹過標記編碼。下面可以用這個技術把字符串轉換成數值:
# 將字符串轉化為數值label_encoder = []X_encoded = np.empty(X.shape)for i,item in enumerate(X[0]):? ? label_encoder.append(preprocessing.LabelEncoder())? ? X_encoded[:, i] = label_encoder[-1].fit_transform(X[:, i])X = X_encoded[:, :-1].astype(int)y = X_encoded[:, -1].astype(int)
由于每個屬性可以取有限數量的數值,所以可以用標記編碼器將它們轉換成數字。我們需要為不同的屬性使用不同的標記編碼器,例如,lug_boot屬性可以取3個不同的值,需要建立一個懂得給這3個屬性編碼的標記編碼器。每一行的最后一個值是類,將它賦值給變量y。
(4) 接下來訓練分類器:
# 建立隨機森林分類器params = {'n_estimators': 200, 'max_depth': 8, 'random_state': 7}classifier = RandomForestClassifier(**params)classifier.fit(X, y)
你可以改變n_estimators和max_depth參數的值,觀察它們如何改變分類器的準確性。我們將用一個標準化的方法處理參數選擇問題。
(5) 下面進行交叉驗證:
# 交叉驗證from sklearn import cross_validationaccuracy = cross_validation.cross_val_score(classifier,? ? ? ? X, y, scoring='accuracy', cv=3)print "Accuracy of the classifier: " + str(round(100*accuracy. mean(), 2)) + "%"
一旦訓練好分類器,我們就需要知道它是如何執行的。我們用三折交叉驗證(three-fold cross-validation,把數據分3組,輪換著用其中兩組數據驗證分類器)來計算分類器的準確性。
(6) 建立分類器的主要目的就是要用它對孤立的和未知的數據進行分類。下面用分類器對一個單一數據點進行分類:
# 對單一數據示例進行編碼測試input_data = ['vhigh', 'vhigh', '2', '2', 'small', 'low']input_data_encoded = [-1] * len(input_data)for i,item in enumerate(input_data):? ? input_data_encoded[i] = int(label_encoder[i].transform(input_data[i]))input_data_encoded = np.array(input_data_encoded)
第一步是把數據轉換成數值類型。需要使用之前訓練分類器時使用的標記編碼器,因為我們需要保持數據編碼規則的前后一致。如果輸入數據點里出現了未知數據,標記編碼器就會出現異常,因為它不知道如何對這些數據進行編碼。例如,如果你把列表中的第一個值vhigh改成abcd,那么標記編碼器就不知道如何編碼了,因為它不知道怎么處理這個字符串。這就像是錯誤檢查,看看輸入數據點是否有效。
(7) 現在可以預測出數據點的輸出類型了:
# 預測并打印特定數據點的輸出output_class = classifier.predict(input_data_encoded)print "Output class:", label_encoder[-1].inverse_transform(output_class)[0]
我們用predict方法估計輸出類型。如果輸出被編碼的輸出標記,那么它對我們沒有任何意義。因此,用inverse_transform方法對標記進行解碼,將它轉換成原來的形式,然后打印輸出類。
第02章:創建分類器(下)
?
?
?
? ?
? ? ?2.10 生成驗證曲線
? ? ? ?詳細步驟2.11 生成學習曲線
? ? ? ?詳細步驟2.12 估算收入階層
? ? ? ?詳細步驟
?
2.10 生成驗證曲線
前面用隨機森林建立了分類器,但是并不知道如何定義參數。本節來處理兩個參數:n_estimators和max_depth參數。它們被稱為超參數(hyperparameters),分類器的性能是由它們決定的。當改變超參數時,如果可以看到分類器性能的變化情況,那就再好不過了。這就是驗證曲線的作用。這些曲線可以幫助理解每個超參數對訓練得分的影響。基本上,我們只對感興趣的超參數進行調整,其他參數可以保持不變。下面將通過可視化圖片演示超參數的變化對訓練得分的影響。
詳細步驟
(1) 打開上一節的 Python 文件,加入以下代碼:
# 驗證曲線from sklearn.learning_curve import validation_curveclassifier = RandomForestClassifier(max_depth=4, random_state=7)parameter_grid = np.linspace(25, 200, 8).astype(int)train_scores, validation_scores = validation_curve(classifier, X, y, "n_estimators", parameter_grid, cv=5)print "\n##### VALIDATION CURVES #####"print "\nParam: n_estimators\nTraining scores:\n", train_scoresprint "\nParam: n_estimators\nValidation scores:\n", validation_ scores
在這個示例中,我們通過固定max_depth參數的值來定義分類器。我們想觀察評估器數量對訓練得分的影響,于是用parameter_grid定義了搜索空間。評估器數量會在25~200之間每隔8個數迭代一次,獲得模型的訓練得分和驗證得分。
(2) 運行代碼,可以在命令行工具中看到如圖2-11所示的結果。
?
圖 2-11
(3) 把數據畫成圖形:
# 畫出曲線圖plt.figure()plt.plot(parameter_grid, 100*np.average(train_scores, axis=1), color='black')plt.title('Training curve')plt.xlabel('Number of estimators')plt.ylabel('Accuracy')plt.show()
(4) 得到的圖形如圖2-12所示。
?
圖 2-12
(5) 用類似的方法對max_depth參數進行驗證:
classifier = RandomForestClassifier(n_estimators=20, random_ state=7)parameter_grid = np.linspace(2, 10, 5).astype(int)train_scores, valid_scores = validation_curve(classifier, X, y, "max_depth",? ? ? ? parameter_grid, cv=5)print "\nParam: max_depth\nTraining scores:\n", train_scoresprint "\nParam: max_depth\nValidation scores:\n", validation_ scores
我們把n_estimators參數固定為20,看看max_depth參數變化對性能的影響。命令行工具的輸出結果如圖2-13所示。
(6) 把數據畫成圖形:
# 畫出曲線圖plt.figure()plt.plot(parameter_grid, 100*np.average(train_scores, axis=1), color='black')plt.title('Validation curve')plt.xlabel('Maximum depth of the tree')plt.ylabel('Accuracy')plt.show()
?
圖 2-13
(7) 運行代碼,可以看到如圖2-14所示的圖形。
?
圖 2-14
2.11 生成學習曲線
學習曲線可以幫助我們理解訓練數據集的大小對機器學習模型的影響。當遇到計算能力限制時,這一點非常有用。下面改變訓練數據集的大小,把學習曲線畫出來。
詳細步驟
(1) 打開上一節的 Python 文件,加入以下代碼:
# 學習曲線from sklearn.learning_curve import learning_curveclassifier = RandomForestClassifier(random_state=7)parameter_grid = np.array([200, 500, 800, 1100])train_sizes, train_scores, validation_scores = learning_ curve(classifier,? ? ? ? X, y, train_sizes=parameter_grid, cv=5)print "\n##### LEARNING CURVES #####"print "\nTraining scores:\n", train_scoresprint "\nValidation scores:\n", validation_scores
我們想分別用200、500、800、1100的訓練數據集的大小測試模型的性能指標。我們把learning_curve方法中的cv參數設置為5,就是用五折交叉驗證。
(2) 運行代碼,可以在命令行工具中看到如圖2-15所示的結果。
?
圖 2-15
(3) 把數據畫成圖形:
# 畫出曲線圖plt.figure()plt.plot(parameter_grid, 100*np.average(train_scores, axis=1), color='black')plt.title('Learning curve')plt.xlabel('Number of training samples')plt.ylabel('Accuracy')plt.show()
(4) 得到的圖形如圖2-16所示。
?
圖 2-16
雖然訓練數據集的規模越小,仿佛訓練準確性越高,但是它們很容易導致過度擬合。如果選擇較大規模的訓練數據集,就會消耗更多的資源。因此,訓練數據集的規模選擇也是一個需要結合計算能力進行綜合考慮的問題。
2.12 估算收入階層
本節將根據14個屬性建立分類器評估一個人的收入等級。可能的輸出類型是“高于50K”和“低于或等于50K”。這個數據集稍微有點復雜,里面的每個數據點都是數字和字符串的混合體。數值數據是有價值的,在這種情況下,不能用標記編碼器進行編碼。需要設計一套既可以處理數值數據,也可以處理非數值數據的系統。我們將用美國人口普查收入數據集中的數據。
詳細步驟
(1) 我們將用 income.py 文件作為參考,用樸素貝葉斯分類器解決問題。首先導入兩個軟件包:
from sklearn import preprocessingfrom sklearn.naive_bayes import GaussianNB
(2) 加載數據集:
input_file = 'path/to/adult.data.txt'# 讀取數據X = []y = []count_lessthan50k = 0count_morethan50k = 0num_images_threshold = 10000
(3) 我們將使用數據集中的20 000個數據點——每種類型10 000個,保證初始類型沒有偏差。在模型訓練時,如果你的大部分數據點都屬于一個類型,那么分類器就會傾向于這個類型。因此,最好使用每個類型數據點數量相等的數據進行訓練:
with open(input_file, 'r') as f:? ? for line in f.readlines():? ? ? ? if '?' in line:? ? ? ? ? ? continue? ? ? ? data = line[:-1].split(', ')? ? ? ? if data[-1] == '<=50K' and count_lessthan50k < num_images_threshold:? ? ? ? ? ? X.append(data)? ? ? ? ? ? count_lessthan50k = count_lessthan50k + 1? ? ? ? elif data[-1] == '>50K' and count_morethan50k < num_images_threshold:? ? ? ? ? ? X.append(data)? ? ? ? ? ? count_morethan50k = count_morethan50k + 1? ? ? ? if count_lessthan50k >= num_images_threshold and count_morethan50k >= num_images_threshold:? ? ? ? ? ? breakX = np.array(X)
同樣地,這也是一個帶逗號分隔符的文件。我們還是像之前那樣處理,把數據加載到變量X。
(4) 我們需要把字符串屬性轉換為數值數據,同時需要保留原有的數值數據:
# 將字符串轉換為數值數據label_encoder = []X_encoded = np.empty(X.shape)for i,item in enumerate(X[0]):? ? if item.isdigit():? ? ? ? X_encoded[:, i] = X[:, i]? ? else:? ? ? ? label_encoder.append(preprocessing.LabelEncoder())? ? ? ? X_encoded[:, i] = label_encoder[-1].fit_transform(X[:, i])X = X_encoded[:, :-1].astype(int)y = X_encoded[:, -1].astype(int)
isdigit()函數幫助我們判斷一個屬性是不是數值數據。我們把字符串數據轉換為數值數據,然后把所有的標記編碼器保存在一個列表中,便于在后面處理未知數據時使用。
(5) 訓練分類器:
# 建立分類器classifier_gaussiannb = GaussianNB()classifier_gaussiannb.fit(X, y)
(6) 把數據分割成訓練數據集和測試數據集,方便后面獲取性能指標:
# 交叉驗證from sklearn import cross_validationX_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.25, random_state=5)classifier_gaussiannb = GaussianNB()classifier_gaussiannb.fit(X_train, y_train)y_test_pred = classifier_gaussiannb.predict(X_test)
(7) 提取性能指標:
# 計算分類器的F1得分f1 = cross_validation.cross_val_score(classifier_gaussiannb,? ? ? ? X, y, scoring='f1_weighted', cv=5)print "F1 score: " + str(round(100*f1.mean(), 2)) + "%"
(8) 接下來看看如何為單一數據點分類。我們需要把數據點轉換成分類器可以理解的形式:
# 對單一數據示例進行編碼測試input_data = ['39', 'State-gov', '77516', 'Bachelors', '13', 'Never-married', 'Adm-clerical', 'Not-in-family', 'White', 'Male', '2174', '0', '40', 'United-States']count = 0input_data_encoded = [-1] * len(input_data)for i,item in enumerate(input_data):? ? if item.isdigit():? ? ? ? input_data_encoded[i] = int(input_data[i])? ? else:? ? ? ? input_data_encoded[i] = int(label_encoder[count].transform(input_data[i]))? ? ? ? count = count + 1input_data_encoded = np.array(input_data_encoded)
(9) 這樣就可以進行分類了:
# 預測并打印特定數據點的輸出結果output_class = classifier_gaussiannb.predict(input_data_encoded)print label_encoder[-1].inverse_transform(output_class)[0]
和之前的分類案例一樣,我們用predict方法獲取輸出類型,然后用inverse_transform對標記進行解碼,將它轉換成原來的形式,然后在命令行工具中打印出來。
?
第03章:預測建模(上)
?
?
第03章:預測建模(下)
?
?
第04章:無監督學習——聚類(上)
?
?
第04章:無監督學習——聚類(中)
?
?
第04章:無監督學習——聚類(下)
?
?
第05章:構建推薦引擎(上)
?
?
第05章:構建推薦引擎(中)
?
?
第05章:構建推薦引擎(下)
?
?
第06章:分析文本數據(上)
?
?
第06章:分析文本數據(中)
?
?
第06章:分析文本數據(下)
?
?
第07章:語音識別(上)
?
?
第07章:語音識別(下)
?
?
第08章:解剖時間序列和時序數據(上)
?
?
第08章:解剖時間序列和時序數據(下)
?
?
第09章:圖像內容分析(上)
?
?
第09章:圖像內容分析(下)
?
?
第10章:人臉識別(上)
?
?
第10章:人臉識別(中)
?
?
第10章:人臉識別(下)
?
?
第11章:深度神經網絡(上)
?
?
第11章:深度神經網絡(中)
?
?
第11章:深度神經網絡(下)
?
?
第12章:可視化數據(上)
?
?
第12章:可視化數據(下)
?
閱讀全文: http://gitbook.cn/gitchat/geekbook/5a3c787a902f0f2223e2526f