1. 程式人生 > >【機器學習】Udacity機器學習入門

【機器學習】Udacity機器學習入門

歡迎關注個人部落格:楓之羽

前言

   這部分內容側重於機器學習的應用以及如何使用sklearn和調優。該部分內容基於Udacity的機器學習入門課程,偏重實踐,有興趣的可以看看,也可以一起學習。

1、樸素貝葉斯

訓練分類器

from sklearn.naive_bayes import GaussianNB

clf = GaussianNB()  # 建立分類器
clf.fit(features_train, labels_train)  # 使用訓練特徵和標籤進行擬合
pred = clf.predict(features_test)  # 預測

評估分類器效果

準確性:正確分類的測試點數目除以測試點總數

兩種方法:

  • 根據定義計算準確性
  • 使用sklearn的accuracy_score()方法from sklearn.met
from sklearn.metrics import accuracy_score

print(accuracy_score(pred, labels_test))  # 引數normalize=Flase時方法返回的是正確個數,預設為True

先驗概率和後驗概率

先驗概率

P(C)=0.1,P(ℸC)=0.9

後驗概率

Posterior 應該寫為:

P(C, Pos) = P(C) • P(Pos|C)

P(ℸC, Pos) = P(ℸC)• P(Pos|ℸC)

樸素貝葉斯之所以“樸素”。

舉例:A,B兩個人在郵件中都喜歡使用love,deal,life這三個單詞,但是使用頻率不同。(這裡只是為了說明“樸素”一次,因此不給出詞頻)

然後給定love life,問是那個人說的概率比較大。

這個答案可以根據貝葉斯公式、先驗概率和後驗概率計算得到。

那麼它的樸素是因為什麼?  當然是沒有考慮單詞的順序啦。。在計算的時候是p1*p2*……*pn,沒有把順序考慮在內。

樸素貝葉斯實戰(迷你專案)

幾年前,J.K. 羅琳(憑藉《哈利波特》出名)試著做了件有趣的事。她以 Robert Galbraith 的化名寫了本名叫《The Cuckoo’s Calling》的書。儘管該書得到一些不錯的評論,但是大家都不太重視它,直到 Twitter 上一個匿名的知情人士說那是 J.K. Rowling 寫的。《倫敦週日泰晤士報》找來兩名專家對《杜鵑在呼喚》和 Rowling 的《偶發空缺》以及其他幾名作者的書進行了比較。

分析結果強有力地指出羅琳就是作者,《泰晤士報》直接詢問出版商情況是否屬實,而出版商也證實了這一說法,該書在此後一夜成名。

我們也將在此專案中做類似的事。我們有一組郵件,分別由同一家公司的兩個人撰寫其中半數的郵件。我們的目標是僅根據郵件正文區分每個人寫的郵件。在這個迷你專案一開始,我們將使用樸素貝葉斯,並在之後的專案中擴充套件至其他演算法。

我們會先給你一個字串列表。每個字串代表一封經過預處理的郵件的正文;然後,我們會提供程式碼,用來將資料集分解為訓練集和測試集(在下節課中,你將學習如何進行預處理和分解,但是現在請使用我們提供的程式碼)。

樸素貝葉斯特殊的一點在於,這種演算法非常適合文字分類。在處理文字時,常見的做法是將每個單詞看作一個特徵,這樣就會有大量的特徵。此演算法的相對簡單性和樸素貝葉斯獨立特徵的這一假設,使其能夠出色完成文字的分類。在這個迷你專案中,你將在計算機中下載並安裝 sklearn,然後使用樸素貝葉斯根據作者對郵件進行分類。

安裝Python,建議IDE使用Pycharm(個人喜好).然後安裝一些python包。

你只需操作一次,基礎程式碼包含所有迷你專案的初始程式碼。進入 tools/ 目錄,執行 startup.py。該程式首先檢查 python 模組,然後下載並解壓縮我們在後期將大量使用的大型資料集。下載和解壓縮需要一些時間,但是你無需等到全部完成再開始第一部分。

在 naive_bayes/nb_author_id.py 中建立和訓練樸素貝葉斯分類器,用其為測試集進行預測。準確率是多少?

0.9732650739476678 【核心程式碼附在下文】

no. of Chris training emails: 7936

no. of Sara training emails: 7884

traing time 1.17324280739

[0 0 1 ... 1 0 0]

0.9732650739476678

predict time 0.159196138382

在訓練期間,你可能會看到以下錯誤:“使用者警告:分數重複。結果可能取決於特徵排序,或者你對迴歸任務使用了分類分數。” 警告(“分數重複。結果可能取決於特徵排序。”)

郵件中兩個以上的單詞恰巧具有相同的使用模式時,會出現這一警告—對演算法而言,這表示兩個特徵是相同的。當重複特徵出現時,一些演算法實際上會中斷(數學上無法執行),或給出多個不同的答案(取決於特徵排序),然後 sklearn 發出警告。這種資訊能起到幫助作用,所以我們無需擔心。

核心程式碼

#!/usr/bin/python

""" 
    This is the code to accompany the Lesson 1 (Naive Bayes) mini-project. 

    Use a Naive Bayes Classifier to identify emails by their authors
    
    authors and labels:
    Sara has label 0
    Chris has label 1
"""
    
import sys
from time import time
sys.path.append("../tools/")
from email_preprocess import preprocess


### features_train and features_test are the features for the training
### and testing datasets, respectively
### labels_train and labels_test are the corresponding item labels
features_train, features_test, labels_train, labels_test = preprocess()



start_time = time()
#########################################################
### your code goes here ###
from sklearn.naive_bayes import GaussianNB

clf = GaussianNB()
clf.fit(features_train, labels_train)

fit_time = time()
print"traing time",fit_time - start_time

pred = clf.predict(features_test)
print (pred)

from sklearn.metrics import accuracy_score
print accuracy_score(pred, labels_test)

predict_time = time()
print "predict time",predict_time - fit_time
#########################################################

2、支援向量機

訓練分類器

from sklearn.svm import SVC

clf = SVC(kernel=”linear”)

clf.fit(features_train, labels_train)

pred = clf.predict(fetures_test)

核技巧

SVM引數

kernel:核,預設為’rbf’,還有linear,poly,sigmod,precomputed

gamma:預設為auto

C:平滑項,越大邊界越平滑得到更多正確的訓練點

SVM實戰(迷你專案)

這個專案依然是樸素貝葉斯中的專案,只是換成了支援向量機來實現了。

另外會介紹如何通過調整引數來優化提高準確率。

      在此迷你專案中,我們將解決與樸素貝葉斯迷你專案相同的電子郵件作者 ID 問題,不同的是我們將運用 SVM。我們的研究結果將闡明兩種演算法之間的一些實際差異。此專案還向我們提供比樸素貝葉斯更多的機會來使用引數,因此我們也將這樣做。

轉到 svm 目錄,查詢初始程式碼 (svm/svm_author_id.py)。

使用 sklearn SVC 分類器進行匯入、建立、訓練和預測。在建立分類器時使用線性核心(如果你忘記此步驟,你會發現分類器要花很長的時間來訓練)。

分類器的準確率是多少?

準確率:0.9840728100113766

no. of Chris training emails: 7936

no. of Sara training emails: 7884

traing time 197.081834078

[0 0 1 ... 1 0 0]

predict time 20.2912540436

0.9840728100113766

核心程式碼

svm_author_id.py

#!/usr/bin/python

""" 
    This is the code to accompany the Lesson 2 (SVM) mini-project.

    Use a SVM to identify emails from the Enron corpus by their authors:    
    Sara has label 0
    Chris has label 1
"""

import sys
from time import time

sys.path.append("../tools/")
from email_preprocess import preprocess

### features_train and features_test are the features for the training
### and testing datasets, respectively
### labels_train and labels_test are the corresponding item labels
features_train, features_test, labels_train, labels_test = preprocess()

start_time = time()
#########################################################
### your code goes here ###
from sklearn.svm import SVC

clf = SVC(kernel="linear")
clf.fit(features_train, labels_train)

fit_time = time()
print"traing time",fit_time - start_time

pred = clf.predict(features_test)
print(pred)
predict_time = time()
print "predict time",predict_time - fit_time

from sklearn.metrics import accuracy_score

accuracy = accuracy_score(pred, labels_test)

print(accuracy)
#########################################################

Naive_Bayes與SVM的比較

SVM在訓練和預測時相比Naive_Bayes慢很多。【你可以從執行結果中列印的時間看出來】

調參與優化

更小的資料集

加快演算法速度的一種方式是在一個較小的訓練資料集上訓練它。這樣做換來的是準確率幾乎肯定會下降。讓我們更具體地探討這個問題:在訓練分類器之前,立即加入以下兩行。 

features_train = features_train[:len(features_train)/100] 
labels_train = labels_train[:len(labels_train)/100] 


這兩行有效地將訓練資料集切割至原始大小的 1%,丟棄掉 99% 的訓練資料。你可以使其他所有程式碼保持不變。

現在的準確率是多少?

no. of Chris training emails: 7936

no. of Sara training emails: 7884

traing time 0.28026509285

[0 1 1 ... 1 0 1]

predict time 1.30546784401

0.8845278725824801

如果速度是一個主要考慮因素(對於許多實時機器學習應用而言確實如此),並且如果犧牲一些準確率可加快你的訓練/預測速度,則你可能會想這樣做。

在以下哪些應用中,你可以想象非常快速地執行的演算法尤其重要?

·  >預測電子郵件作者

·  標記信用卡欺詐,在欺詐發生之前阻止交易

·Siri 之類的語音識別

部署RBF核心

保留上一個測試題中的訓練集程式碼段,以便仍在 1% 的完整訓練集上進行訓練。將 SVM 的核心更改為“rbf”。

這個更復雜的核心給出的準確率是多少?

no. of Chris training emails: 7936

no. of Sara training emails: 7884

traing time 0.149940013885

[0 1 1 ... 1 1 1]

predict time 1.56838107109

0.6160409556313993

優化C引數

保持訓練集大小不變,並且保留上一個測試題中的 rbf 核心,但是嘗試多個 C 值(比如:10.0、100.、1000. 和 10000.)。

哪個給出的準確率最高?

C=10.0 0.6160409556313993

C=100 0.6160409556313993

C=1000 0.8213879408418657

C=10000 0.8924914675767918

優化C後的準確率

在你為 RBF 核心優化了 C 值後,你會獲得怎樣的準確率?該 C 值是否對應更簡單或者更復雜的決策邊界?

(如果你不確定複雜度,請回顧本節課有關“SVM C 引數”的視訊。你在該處發現的結果同樣適用於此處,不過,在簡單的散點圖中畫出決策邊界現在變得更加困難甚至不可能。)

優化後的RBF與現行SVM:準確率

你已經為 RBF 核心優化了 C,現在恢復為使用完整的訓練集。較大的訓練集往往能提高演算法的效能,所以(通過在大資料集上調整 C 和進行訓練)我們應得到相當優化的結果。

經過優化的 SVM 的準確率是多少?

no. of Chris training emails: 7936

no. of Sara training emails: 7884

traing time 133.572846889

[0 0 1 ... 1 0 0]

predict time 12.8665001392

0.9908987485779295

從SVM提取預測

你的 SVM(0 或 1,分別對應 Sara 和 Chris)將測試集中的元素 10 預測為哪一類?元素 26 ?還是元素 50 ?

(使用 RBF 核心、C=10000 和 1% 的訓練集。通常,使用完整的訓練集能獲得最好的結果,但是我們發現使用 1% 的完整訓練集不僅大幅加快計算過程,而且不會改變我們的結果,因此你在這裡可以隨意使用該快捷演算法。)

而且需要說明的是,我們這裡給出的資料點數字 (10, 26, 50) 假設使用的是零索引列表。因此,使用類似於 answer=predictions[100] 的表示式可找到元素 # 100 的正確答案。

print(clf.predict(features_test[10]))
print(clf.predict(features_test[26]))
print(clf.predict(features_test[20]))

輸出為1 ,0,1

預測有多少Chris的郵件

There are over 1700 test events--how many are predicted to be in the “Chris” (1) class? (Use the RBF kernel, C=10000., and the full training set.) 測試事件的數量超過 1700——其中多少預測在“Chris” (1) 類中?(使用 RBF 核心、C=10000. 以及完整的訓練集。)

print "no. of Chris predicting emails:", sum(clf.predict(features_test))
print "no. of Sara predicting emails:", len(clf.predict(features_test))-sum(clf.predict(features_test))redict

no. of Chris predicting emails: 877

no. of Sara predicting emails: 881

小結

希望 Sebastian 在說樸素貝葉斯非常適合文字時,更清楚地表達了他的意思。對於這一具體問題,樸素貝葉斯不僅更快,而且通常比 SVM 更出色。當然,SVM 更適合許多其他問題。你在第一次求解問題時就知道該嘗試哪個演算法,這是機器學習藝術和科學性的一個體現。除了選擇演算法外,視你嘗試的演算法而定,你還需要考慮相應的引數調整以及過擬合的可能性(特別是在你沒有大量訓練資料的情況下)。

我們通常建議你嘗試一些不同的演算法來求解每個問題。調整引數的工作量很大,但你現在只需要聽完這堂課,我們將向你介紹 GridCV,一種幾乎能自動查詢最優引數調整的優秀 sklearn 工具。

最近更新於2018.9.18,有問題或者建議請留言,謝謝~