天天看點

機器學習實用指南:這些基礎盲點請務必注意!

前幾天,紅色石頭在公衆号發文,給大家介紹了一本機器學習入門與實戰非常不錯的書籍《Hands-On Machine Learning with Scikit-Learn & TensorFlow》,文章連結如下: 2018 最好的機器學習實用指南書籍來了!

之前我說過會帶着大家一起來學習這本書,主要包括兩個方面來學習:

1. 建立 GitHub 項目,把本書各章節的重要知識點整理出來(不僅僅是翻譯)。目前才上傳了第一章内容。位址如下:

https://github.com/RedstoneWill/Hands-On-Machine-Learning-with-Sklearn-TensorFlow

2. 把本書各章節的一些知識點提煉出來,以筆記的形式釋出到微信公衆号上,友善大家檢視。

好了,言歸正傳!今天給大家整理出第一章前半部分内容:機器學習必須知道的基礎知識!

1. 什麼是機器學習?

機器學習是一門通過程式設計進而在資料中學習的科學技術,或者稱之為藝術。這裡有一個更一般的定義:

在不直接針對問題進行程式設計的情況下,賦予計算機學習能力的一個研究領域。 —— Arthur Samuel, 1959

另外一個更加工程化的定義:

對于某類任務T和性能度量P,如果計算機程式在T上以P衡量的性能随着經驗E而自我完善,那麼就稱這個計算機程式從經驗E學習。 —— Tom Mitchell, 1997

例如垃圾郵件過濾系統就是一個機器學習程式,可以用來區分垃圾郵件和非垃圾郵件。機器學習系統用來學習的樣本稱之為訓練樣本(training set),每個訓練樣本稱之為訓練執行個體(training instance)或樣本。在這個例子中,任務 T 就是要對新郵件進行區分,經驗 E 就是訓練資料,性能度量 P 需要定義,例如使用分類正确的郵件所占的比例。這種度量方式稱之為準确率(accuracy),經常應用在分類問題中。

2. 為什麼使用機器學習?

我們先來思考,使用傳統程式設計技術如何區分垃圾郵件和非垃圾郵件呢?(如下圖所示)

1.首先你應該考慮典型的垃圾郵件具有什麼特點。例如在郵件的主題中包含了“4U”、“信用卡”、“免費”等詞語。又或者是在郵件的發件人、郵件内容中有一些垃圾郵件常出現的特定的詞語等。

2.然後你就可以對這些情況編寫垃圾郵件檢測算法,若一定數量的詞彙檢測到了,則可以判定是垃圾郵件。

3.最後驗證程式,重複 1 和 2,直到檢測算法的準确率足夠高。

機器學習實用指南:這些基礎盲點請務必注意!

因為這個問題并不簡單,你按照上面思路編寫的程式可能很複雜、冗長,而且很難把控。

對比而言,同樣是垃圾郵件分類,機器學習可以自動從垃圾郵件和非垃圾郵件中檢測出哪些單詞是經常出現在垃圾郵件中的(如下圖所示),而不需要人為指出出現哪些單詞可能就是垃圾郵件。這樣使得問題更加簡化、容易掌控,而且分類的準确率更高。

機器學習實用指南:這些基礎盲點請務必注意!

而且,如果給你發垃圾郵件的人知道了他們的關鍵詞“4 U”被鎖定的話,他們可能會把這個關鍵詞替換成“For U”。如果使用傳統程式設計技術,就要針對“For U”重新編寫程式。那麼,垃圾郵件關鍵詞每次替換,都需要重新針對新的關鍵詞改寫程式,相當麻煩。

而機器學習則不用這麼麻煩,隻需将新的郵件樣本交給模型,機器會自動檢測出哪些單詞是可能出現在垃圾郵件中的。整個過程不需要人工排查和幹預(如下圖所示)。

機器學習實用指南:這些基礎盲點請務必注意!

機器學習強大的另一個原因是,某些問題非常複雜,傳統程式設計很難有較好的方案去解決。例如語音識别、圖像識别,使用傳統人工程式設計方式來解決效率低而且準确率不高。相比之下,最好的解決方法就是使用機器學習,給出足夠多的資料,讓機器自己去學習,得到較高的識别率。

最後,機器學習還可以幫助人們去學習(如下圖所示)。為什麼這樣說呢?因為 ML 算法可以從資料中提取出有用和關鍵的資訊。例如垃圾郵件分類,經過好的訓練得到的 ML 模型能夠揭示出哪些單詞或者哪些單詞的組合是預測為垃圾郵件最重要的特征參考。機器得到的這些資訊可以幫助人們更好地揭示問題的本質,進而更好地解決問題。

将 ML 技術應用到大資料中,挖掘資料本身蘊含的規律和模式,這就是資料挖掘。

機器學習實用指南:這些基礎盲點請務必注意!

總結下來,機器學習的強大之處展現在以下幾個方面:

  • 傳統的程式設計方式解決問題通常需要人工調試、建立冗長規則,而機器學習算法可以極大地簡化代碼且性能更好。
  • 對于某些複雜問題,例如語音識别、圖像識别,傳統程式設計沒有一個較好的解決方案,而機器學習通常表現得很好。
  • 機器學習系統可以自适應新的資料,隻需采集新的資料,重新訓練 ML 模型即可。
  • 機器學習可以揭示複雜問題和大資料内在規律和特性。

3. 機器學習類型

機器學習類型可以按照不同的方式來劃分,具體表現在:

  • 是否需要人類的監督:監督式學習、非監督式學習、半監督式學習、強化學習
  • 是否可以線上上進行學習:線上學習、批量學習
  • 是否可以簡單地把新的資料集與已知資料集進行比較得出結果,還是從訓練集中檢測模式再建立預測模型:基于執行個體學習、基于模型學習。

當然以上這些劃分方式并不是各自獨立的,可以互相結合。例如一個垃圾郵件檢測系統,可以是線上的、基于神經網路模型的監督式學習。

接下來我們詳細看看這些機器學習類型。

3.1 監督式/非監督式學習

機器學習可以根據再訓練過程中受到的監督類型和程度進行劃分,類型包括:監督式學習、非監督式學習、半監督式學習、強化學習。

監督式學習

監督式學習,訓練集包含了樣本的輸出,即 label(如下圖所示)。

機器學習實用指南:這些基礎盲點請務必注意!

一個典型的監督式學習就是分類問題,例如垃圾郵件分類,通過對郵件内容包括它們對應的标簽(垃圾、非垃圾)進行訓練。最終得到的模型對新的郵件進行預測,判斷它是不是垃圾郵件。

另一個典型的監督式學習就是回歸問題(如下圖所示),例如汽車價格預測,通過對汽車特征(商标、車齡等)包括它們對應的價格進行訓練。最終得到的模型對新的汽車進行預測,得到它的價格。

機器學習實用指南:這些基礎盲點請務必注意!

值得注意的是,有些回歸算法也可以用于分類,反之亦然。例如邏輯回歸(Logistic Regression)常用于分類,然而它也可以輸出對應該類别的機率(例如得到垃圾郵件的機率是 20%)。

下面列舉一些最常見的監督式學習算法:

  • k-近鄰
  • 線性回歸
  • 邏輯回歸
  • 支援向量機
  • 決策樹和随機森林
  • 神經網路

非監督式學習

非監督式學習,顧名思義,訓練集是沒有輸出 label 的(如下圖所示)。

機器學習實用指南:這些基礎盲點請務必注意!

下面列舉一些最常見的非監督式學習算法:

  • 聚類

    — k-均值

    — 層次聚類分析(HCA)

    — 最大期望算法(EM)

  • 可視化和降維

    — 主成分分析(PCA)

    — 核 PCA

    — 局部線性嵌入(LLE)

    — t分布随機鄰居嵌入(t-SNE)

  • 關聯規則學習

    — Apriori

    — Eclat

例如現在你掌握了你的部落格訪客資訊,想使用聚類算法對這些訪客進行分組(如下圖所示)。你不需要告訴算法每個訪客應該屬于哪一組,聚類算法會自己分析和判斷。比如訪客中有 40% 是男性,喜歡看漫畫書,通路部落格的時間經常是晚上;20% 是年輕的科幻迷,通路部落格的時間經常是周末,等等。如果你使用層次聚類分析,會對每個組劃分得更細。

機器學習實用指南:這些基礎盲點請務必注意!

可視化算法(visualizationv algorithm)也是非監督式學習的好例子。它能夠把高緯的複雜且沒有标簽的樣本資料在 2D 或 3D 空間中展示出來,便于作圖(如下圖所示)。這些算法盡可能儲存原始資料足夠多的結構資訊(例如可視化的時候避免原始輸入空間不同類别的樣本發生重疊)。這有助于我們了解不同類别之間的近似程度。

機器學習實用指南:這些基礎盲點請務必注意!

一個相關的算法叫做降維(dimensionality reduction)。目的是簡化資料但是不能損失太多資訊。常用的思路就是講相似特征合并成一個。例如汽車的裡程數和它的車齡關系較為密切,降維算法就是把這兩個特征合并成一個特征來表征汽車的磨損程度。這種做法就是特征提取。降維的好處是減少特征個數,讓算法運作更快,減小了計算成本和存儲空間成本。更重要的是,降維可以消除一些噪聲影響,提升算法性能。

還有一個非監督式學習的例子就是異常檢測(anomaly detection)。例如檢測不正常的信用卡交易來避免詐騙,捕獲人工制造缺陷,或者剔除資料集中的異常點以便傳替給後面的機器學習算法。異常檢測算法是使用正常資料集進行訓練的,得到的模型對新的樣本進行測試,判斷它是不是異常點(如見圖所示)。

機器學習實用指南:這些基礎盲點請務必注意!

最後一個非監督式學習的例子就是關聯規則學習(association rule learning),目标就是挖掘大量資料中不同屬性之前的聯系。例如,通過對超市使用者購買商品曆史記錄的分析,發現購買燒烤醬和洋芋薯片的使用者也傾向于購買牛排。是以,基于此分析,超市老闆就可以把這些使用者可能會一起買的商品放在相近的貨架上,友善使用者購買。

半監督式學習

半監督式學習,簡單地說就是訓練集大多數樣本沒有 label,隻有少量樣本有 label。例如一些照片托管服務,例如谷歌照片,就是一個例子。一旦你把所有家庭照片上傳到伺服器之後,雲端算法會自動識别出每個家庭成員出現在哪些照片中,例如 A 出現在照片 1、3、5、6 中, B 出現在照片 2、3、5、8 中,這是一個非監督式學習的過程(聚類)。現在你要做的就隻是告訴機器每個人的名字(相當于 label),即标注 A、B 等分别叫什麼名字(監督式)。然後,機器就可以根據你給的 label,把每張照片中的每個人都标注上名字,即 label。也就是說,通過标注少量的樣本,然後根據聚類算法,把所有樣本的 label 都自動加上了。

機器學習實用指南:這些基礎盲點請務必注意!

大多數半監督式學習都是監督式學習和非監督式學習相結合的。例如深度置信網絡(DBNs),其基礎構模組化型為受限玻爾茲曼機(RBMs)。RBMs 的訓練過程是非監督式學習,但是整個 DBNs 系統是使用監督式學習調優的。

強化學習

強化學習相對來說比較難一些。如下圖所示,假設一個學習系統 Agent 可以觀察環境,并做出相應的行為,然後得到相應的回報。正确的行為得到獎勵,錯誤的行為得到懲罰。Agent 必須自我學習最佳政策是什麼,來即時獲得最多的正回報,進而實作學習的目的。政策定義為 Agent 在一個給定情境中需要做出的即時行為。

機器學習實用指南:這些基礎盲點請務必注意!

上面這張圖生動形象地解釋了強化學習。機器人 Agent 面臨的狀況是發生火災,這時候,它必須進行決策,是選擇接近火源,還是接水救火?這由 Agent 自己決定。如果 Agent 直接接近火源,那麼就會得到懲罰(負回報)。通過這樣的訓練,讓 Agent 自己知道避免懲罰就必須遠離火源,而做出取水救火的政策。強化學習可以類比成訓練寵物的過程,比如我們要訓練狗狗坐下,但是狗狗無法直接聽懂我們的指令的。在訓練過程中,我們根據狗狗的行為做出相應的回報,如果它表現得好,我們就給他獎勵,如果它做跟指令完全無關的動作,我們就給它小小的懲罰。這樣不斷修正狗狗的動作,最終能讓它按照我們的指令來行動。

強化學習非常強大,我們熟悉的 AlphaGo 就是強化學習的典型代表。2016 年,AlphaGo 戰敗了世界圍棋冠軍李世石。它就是通過分析數百萬場圍棋比賽,從中學習到赢的政策,然後跟自己進行很多長比賽。經過這樣的訓練和學習,最終 AlphaGo 成為了一名圍棋頂尖高手。

3.2 批量學習和線上學習

機器學習類型另一種分類方式是根據是否可以對新添加的資料進行線上的即時學習。如果可以的話就叫線上學習(online learning),如果是離線的話就叫批量學習(batch learning)。

批量學習

批量學習不是即時學習,它是将所有的訓練資料一起訓練,這會花費很多時間和計算資源,是以一般隻能用離線的方式訓練。模型一旦訓練完成,就上線釋出,使用固定的模型工作,是以也常稱為離線學習(offline learning)。

這時候如果有新的資料産生,想要得到新的模型必須把新的資料和之前的資料結合起來,再次重新離線訓練機器學習模型,最後上線釋出。

批量學習比較簡單也是最常見的機器學習類型。但是,一次完整的訓練過程可能會花費很多時間,甚至幾天、一個星期都有可能。如果機器學習系統更新資料很頻繁,那麼使用這種離線方式訓練就比較麻煩,成本很大,需要不停地整合資料、離線訓練、釋出模型。這種情況下,批量學習并不是一個好方法。

而且,訓練整個資料集需要很多的計算資源(例如 CPU/GPU、記憶體、存儲、IO、網絡等)。特别是再資料量很大的情況下,其消耗的資源和成本是巨大的。這時候,一般不建議使用批量學習模型。

最後,如果你的系統需要能夠自主學習,且資源有限(例如手機 App),那麼攜帶大量資料、消耗大量資源,每天花費數小時來進行模型訓練是不太現實的。

線上學習

線上學習可以即時地重新訓練模型,當新的資料點或者小批量(mini-batches)資料傳給模型的時候,模型立即根據新資料重新訓練。整個過程快速而且成本低。這是一種線上學習的方式,如下圖所示。

機器學習實用指南:這些基礎盲點請務必注意!

線上學習對于那些持續接受資料(例如,股票價格)并且需要快速更新或自主學習的系統非常有用。如果你的計算資源有限,線上學習也是一個不錯的選擇:一旦線上學習系統了學習了新的資料執行個體,它就不再需要它們了,是以可以丢棄(除非您想要復原到以前的狀态并“重播”資料)。這樣可以節省大量的空間。

線上學習算法也可以應用于當資料集很大,機器記憶體不夠的時候進行模型訓練(稱為核外學習,out of core learning)。做法是把整個資料集切分成許多小批量(mini-batches)樣本,依次對每個小批量樣本進行訓練,重複進行,直到整個資料集完成訓練(如下圖所示)。值得注意的是,整個過程一般是離線進行的,是以線上學習這個名字可能有點讓人疑惑,你也可以稱之它為增量學習(incremental learning)。

機器學習實用指南:這些基礎盲點請務必注意!

線上學習一個很重要的參數就是基于資料改變更新算法的頻率,是隻要有新的資料進來就更新算法還是積累一定的資料改變之後再更新算法。這個參數被成為:學習率(learning rate)。如果設定很大的學習率,算法對會快速适應新資料,而忘記舊的資料(然而,垃圾郵件檢測系統中你可能并不想讓模型隻對新的垃圾郵件标記,而很快舍棄之前的标記方法)。相反,如果設定較小的學習率,系統就會具有較大的慣性。也就是說,學習的速度比較慢,但是對資料中可能存在的噪聲就不會特别敏感。系統的健壯性就會更強一些。

線上學習一個大的挑戰是隻要有壞資料輸入給系統,那麼系統的性能就會立刻逐漸下降。如果這是一個即時系統,使用者就會立刻注意到。例如,壞資料可能來自于機器人上的故障傳感器,可能是某人在搜尋引擎輸入垃圾資訊以提高搜尋排名。為了減少這種風險,您需要密切監視系統,如果檢測到系統性能下降,就立即關閉學習(或復原到上一個版本的系統)。您可能還需要監視輸入資料并對異常資料作出反應(例如,使用異常檢測算法)。

3.3 基于執行個體學習 vs 基于模型學習

機器學習還可以就根據它的歸納方法來劃分。大多數機器學習的任務是做出預測,這意味着給到大量的訓練樣本訓練模型,系統需要泛化到從未見過的樣本。模型在訓練集上有好的表現是個好事,但這還不夠;目标是模型在新的執行個體上的表現。

有兩種主要的歸納方法:基于執行個體學習和基于模型學習。

基于執行個體學習

或許最簡單的學習方式就是記憶學習。如果你用這種方式建立一個垃圾郵件過濾器,它隻會标記所有與已經由使用者标記的郵件相同的郵件。這不是最壞的解決方案,但肯定不是最好的。

不能僅僅是标記與已知郵件相同的郵件,你的垃圾郵件檢測程式還應該可以标記與已知郵件相似的郵件。這就需要計算兩封郵件的相似程度。一種最基本的相似度測量方式就是計算兩封郵件包含相同單詞的個數。如果新郵件與已知的一封垃圾郵件相同單詞個數較多,那麼系統就會判斷其也是垃圾郵件。

這種學習方法就叫做基于執行個體學習:系統把所有訓練集樣本都存儲下來,然後計算新的樣本與存儲的這些執行個體的相似度(如下圖所示)。

機器學習實用指南:這些基礎盲點請務必注意!
機器學習實用指南:這些基礎盲點請務必注意!
機器學習實用指南:這些基礎盲點請務必注意!
機器學習實用指南:這些基礎盲點請務必注意!

似乎能看到一點趨勢。盡管資料有些噪聲,但是生活滿意度多少與 GDP 呈現線性增長關系。是以,你可以令生活滿意度是人均 GDP 的線性函數。這一步稱為模型選擇:選擇一個生活滿意度的線性模型,該模型隻有一個屬性(attribute),即人均 GDP。

機器學習實用指南:這些基礎盲點請務必注意!

這個模型有兩個參數:θ0  和 θ1  ,通過調整這些參數,你可以讓你的模型表示任何線性函數,如下圖所示。

機器學習實用指南:這些基礎盲點請務必注意!

在使用你的模型之前,你需要确定參數值 θ0 和 θ1 讓模型表現最好。怎麼做呢?你需要制定一個性能評估方法。可以定義一個拟合函數測量模型有多好,也可以定義一個代價函數(loss function)來測量模型有多不好。對于線性回歸問題,人們一般使用代價函數來測量線性模型預測值與實際樣本值之間的距離,目标就是讓這個距離越小越好,最小化。 這就是線性回歸算法,根據訓練集,線性回歸算法能夠找到最合适的參數,使得線性模型能最好程度地拟合這些資料。這個過程稱為模型訓練。在上面這個例子中,使用線性回歸算法,得到的最佳參數為:θ0 =4.85,θ1 =4.91×10^−5 。 現在得到的線性模型拟合資料的效果就很好了,如下圖所示。

機器學習實用指南:這些基礎盲點請務必注意!

最後,你就可以使用這個模型進行預測了。例如,你想知道 Cyprus 人的生活滿意度,但是 OECD 并沒有提供這個資料。幸運的是,你可以使用剛剛訓練好的模型進行預測:你查到 Cyprus 人均 GDP 是 $22,587,然後根據模型的線性表達式,計算生活滿意度為:4.85 + 22,587 × 4.91 × 10^-5 = 5.964.85+22,587×4.91×10^−5 = 5.96。 下面這段代碼就是使用 Python 來導入資料集,預處理,建立可視化散點圖,然後訓練線性模型并作出預測。

# Code example
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import sklearn.linear_model
import os
datapath = os.path.join("datasets", "lifesat", "")
def prepare_country_stats(oecd_bli, gdp_per_capita):
   oecd_bli = oecd_bli[oecd_bli["INEQUALITY"]=="TOT"]
   oecd_bli = oecd_bli.pivot(index="Country", columns="Indicator", values="Value")
   gdp_per_capita.rename(columns={"2015": "GDP per capita"}, inplace=True)
   gdp_per_capita.set_index("Country", inplace=True)
   full_country_stats = pd.merge(left=oecd_bli, right=gdp_per_capita,
                                 left_index=True, right_index=True)
   full_country_stats.sort_values(by="GDP per capita", inplace=True)
   remove_indices = [0, 1, 6, 8, 33, 34, 35]
   keep_indices = list(set(range(36)) - set(remove_indices))
   return full_country_stats[["GDP per capita", 'Life satisfaction']].iloc[keep_indices]
# Load the data
oecd_bli = pd.read_csv(datapath + "oecd_bli_2015.csv", thousands=',')
gdp_per_capita = pd.read_csv(datapath + "gdp_per_capita.csv",thousands=',',delimiter='\t',
                            encoding='latin1', na_values="n/a")
# Prepare the data
country_stats = prepare_country_stats(oecd_bli, gdp_per_capita)
X = np.c_[country_stats["GDP per capita"]]
y = np.c_[country_stats["Life satisfaction"]]
# Visualize the data
country_stats.plot(kind='scatter', x="GDP per capita", y='Life satisfaction')
plt.show()
# Select a linear model
model = sklearn.linear_model.LinearRegression()
# Train the model
model.fit(X, y)
# Make a prediction for Cyprus
X_new = [[22587]]  # Cyprus' GDP per capita
print(model.predict(X_new)) # outputs [[ 5.96242338]]      
機器學習實用指南:這些基礎盲點請務必注意!
[[ 5.96242338]]

值得注意的是,如果我們使用的是基于執行個體的方法學習,我們發現與 Cyprus 人均 GDP 最接近的國家是 Slovenia(人均 GDP 為 $20,732)。因為 Slovenia 人的生活滿意度是 5.7,則可以說 Cyprus 的生活滿意度也是 5.7。如果我們選擇與 Cyprus GDP 最接近的 3 個國家,分别是 Portugal、Slovenia、Spain,GDP 分别是 5.1、5.7、6.5,則平均計算,得到 Cyprus 的人均 GDP 為 5.77。這兩個結果與我們使用基于模型學習的結果很相近。這種執行個體學習方法就叫做 k-近鄰算法。

對應到代碼中,如果使用 k-近鄰替代線下回歸,則隻要把下面這條語句:

clf = sklearn.linear_model.LinearRegression()      

替換成:

clf = sklearn.neighbors.KNeighborsRegressor(n_neighbors=3)      

就好了。

如果一切進展順利的話,這個模型就可以較好地預測了。如果效果不好,那你還需要使用更多的特征(例如就業率、健康程度、空氣品質等),獲得更好的訓練集,或者使用更強大的模型(例如多項式回歸)。

下面對基于模型學習作個總結:

  • 選取資料集
  • 選擇模型
  • 在訓練集上訓練模型(即使用學習算法找到最佳參數,讓代價函數最小化)
  • 最後,将模型應用到新的樣本中,進行預測,希望的得到較好的泛化能力

這就是建構一個典型的機器學習項目的過程。

到目前為止,我們已經介紹了很多内容:你知道了什麼是機器學習,為什麼機器學習是有用的,機器學習有哪些類型,以及建構機器學習系統的一般流程是什麼樣的。