Python 中的實用數據挖掘

本文是 2014 年 12 月我在布拉格經濟大學作的名爲‘ Python 數據科學’講座的筆記。歡迎經過 @RadimRehurek 進行提問和評論。css

本次講座的目的是展現一些關於機器學習的高級概念。該筆記中用具體的代碼來作演示,你們能夠在本身的電腦上運行(須要安裝 IPython,以下所示)。html

本次講座的聽衆須要瞭解一些基礎的編程(不必定是 Python),並擁有一點基本的數據挖掘背景。本次講座不是機器學習專家的「高級演講」。python

這些代碼實例建立了一個有效的、可執行的原型系統:一個使用「spam」(垃圾信息)或「ham」(非垃圾信息)對英文手機短信(」短信類型「的英文)進行分類的 app。git

Python

整套代碼使用 Python 語言。 python 是一種在管線(pipeline)的全部環節(I/O、數據清洗重整和預處理、模型訓練和評估)都好用的通用語言。儘管 python 不是惟一選擇,但它靈活、易於開發,性能優越,這得益於它成熟的科學計算生態系統。Python 龐大的、開源生態系統同時避免了任何單一框架或庫的限制(以及相關的信息丟失)。github

IPython notebook,是 Python 的一個工具,它是一個以 HTML 形式呈現的交互環境,能夠經過它馬上看到結果。咱們也將重溫其它普遍用於數據科學領域的實用工具。
 
想交互運行下面的例子(選讀)?
1. 安裝免費的 Anaconda Python 發行版,其中已經包含 Python 自己。
2. 安裝「天然語言處理」庫——TextBlob: 安裝包在這
3. 下載本文的源碼(網址: http://radimrehurek.com/data_science_python/data_science_python.ipynb 並運行: $ ipython notebook data_science_python.ipynb
4. 觀看 IPython notebook 基本用法教程  IPython tutorial video 
5. 運行下面的第一個代碼,若是執行過程沒有報錯,就能夠了。
 
端到端的例子:自動過濾垃圾信息
In [1]:
 

第一步:加載數據,瀏覽一下

 
讓咱們跳過真正的第一步(完善資料,瞭解咱們要作的是什麼,這在實踐過程當中是很是重要的),直接到  https://archive.ics.uci.edu/ml/datasets/SMS+Spam+Collection 下載 demo 裏須要用的 zip 文件,解壓到 data 子目錄下。你能看到一個大概 0.5MB 大小,名爲 SMSSpamCollection 的文件:

 

這份文件包含了 5000 多份 SMS 手機信息(查看 readme 文件以得到更多信息):
 
In [2]:
5574
 
文本集有時候也稱爲「語料庫」,咱們來打印 SMS 語料庫中的前 10 條信息:
In [3]:
 
咱們看到一個 TSV 文件(用製表符 tab 分隔),它的第一列是標記正常信息(ham)或「垃圾文件」(spam)的標籤,第二列是信息自己。
 
這個語料庫將做爲帶標籤的訓練集。經過使用這些標記了 ham/spam 例子,咱們將訓練一個自動分辨 ham/spam 的機器學習模型。而後,咱們能夠用訓練好的模型將任意未標記的信息標記爲 ham 或 spam。

learning model

 
咱們可使用 Python 的 Pandas 庫替咱們處理 TSV 文件(或 CSV 文件,或 Excel 文件):
 
In [4]:
 
 
咱們也可使用 pandas 輕鬆查看統計信息:
 
In [5]:
 out[5]:
   
message
label    
ham count 4827
unique 4518
top Sorry, I’ll call later
freq 30
spam count 747
unique 653
top Please call our customer service representativ…
freq 4
 
 
這些信息的長度是多少:
 
In [6]:
In [7]:
Out[7]:
download
In [8]:
Out[8]:
哪些是超長信息?
In [9]:
spam 信息與 ham 信息在長度上有區別嗎?
 
In [10]:
Out[10]:
  download (1)
太棒了,可是咱們怎麼能讓電腦本身識別文字信息?它能夠理解這些胡言亂語嗎?

 

第二步:數據預處理

這一節咱們將原始信息(字符序列)轉換爲向量(數字序列);

這裏的映射並不是一對一的,咱們要用詞袋模型(bag-of-words)把每一個不重複的詞用一個數字來表示。算法

與第一步的方法同樣,讓咱們寫一個將信息分割成單詞的函數:
In [11]:
這仍是原始文本的一部分:
 
In [12]:
Out[12]:
 
這是原始文本處理後的樣子:
 
In [13]:
Out[13]:
 
天然語言處理(NLP)的問題:
 
  1. 大寫字母是否攜帶信息?
  2. 單詞的不一樣形式(「goes」和「go」)是否攜帶信息?
  3. 嘆詞和限定詞是否攜帶信息?

換句話說,咱們想對文本進行更好的標準化。編程

咱們使用 textblob 獲取 part-of-speech (POS) 標籤:數組

In [14]:
Out[14]:
 
並將單詞標準化爲基本形式 ( lemmas):
In [15]:
Out[15]:

 

這樣就好多了。你也許還會想到更多的方法來改進預處理:解碼 HTML 實體(咱們上面看到的 &amp 和 &lt);過濾掉停用詞 (代詞等);添加更多特徵,好比全部字母大寫標識等等。

 

第三步:數據轉換爲向量

如今,咱們將每條消息(詞幹列表)轉換成機器學習模型能夠理解的向量。網絡

用詞袋模型完成這項工做須要三個步驟:app

1.  對每一個詞在每條信息中出現的次數進行計數(詞頻);
2. 對計數進行加權,這樣常常出現的單詞將會得到較低的權重(逆向文件頻率);
3. 將向量由原始文本長度歸一化到單位長度(L2 範式)。

每一個向量的維度等於 SMS 語料庫中包含的獨立詞的數量。

In [16]:
 

這裏咱們使用強大的 python 機器學習訓練庫 scikit-learn (sklearn),它包含大量的方法和選項。

咱們取一個信息並使用新的 bow_tramsformer 獲取向量形式的詞袋模型計數:

In [17]:
 
In [18]:
 
 

message 4 中有 9 個獨立詞,它們中的兩個出現了兩次,其他的只出現了一次。可用性檢測,哪些詞出現了兩次?

In [19]:
 
 

整個 SMS 語料庫的詞袋計數是一個龐大的稀疏矩陣:

In [20]:
 
 

最終,計數後,使用 scikit-learn 的 TFidfTransformer 實現的 TF-IDF 完成詞語加權和歸一化。

In [21]:
 
 

單詞 「u」 的 IDF(逆向文件頻率)是什麼?單詞「university」的 IDF 又是什麼?

In [22]:
 
 

將整個 bag-of-words 語料庫轉化爲 TF-IDF 語料庫。

In [23]:
 
 
有許多方法能夠對數據進行預處理和向量化。這兩個步驟也能夠稱爲「特徵工程」,它們一般是預測過程當中最耗時間和最無趣的部分,可是它們很是重要而且須要經驗。訣竅在於反覆評估:分析模型偏差,改進數據清洗和預處理方法,進行頭腦風暴討論新功能,評估等等。

第四步:訓練模型,檢測垃圾信息

咱們使用向量形式的信息來訓練 spam/ham 分類器。這部分很簡單,有不少實現訓練算法的庫文件。

這裏咱們使用 scikit-learn,首先選擇 Naive Bayes 分類器:

In [24]:
 
 

咱們來試着分類一個隨機信息:

In [25]:
 
 

太棒了!你也能夠用本身的文本試試。

有一個很天然的問題是:咱們能夠正確分辨多少信息?

In [26]:
 
In [27]:
 
In [28]:
Out[28]:
  download (2)
咱們能夠經過這個混淆矩陣計算精度(precision)和召回率(recall),或者它們的組合(調和平均值)F1:
In [29]:
 
 

有至關多的指標均可以用來評估模型性能,至於哪一個最合適是由任務決定的。好比,將「spam」錯誤預測爲「ham」的成本遠低於將「ham」錯誤預測爲「spam」的成本。

 

第五步:如何進行實驗?

在上述「評價」中,咱們犯了個大忌。爲了簡單的演示,咱們使用訓練數據進行了準確性評估。永遠不要評估你的訓練數據。這是錯誤的。

這樣的評估方法不能告訴咱們模型的實際預測能力,若是咱們記住訓練期間的每一個例子,訓練的準確率將很是接近 100%,可是咱們不能用它來分類任何新信息。

一個正確的作法是將數據分爲訓練集和測試集,在模型擬合和調參時只能使用訓練數據,不能以任何方式使用測試數據,經過這個方法確保模型沒有「做弊」,最終使用測試數據評價模型能夠表明模型真正的預測性能。

In [30]:
 
 
按照要求,測試數據佔整個數據集的 20%(總共 5574 條記錄中的 1115 條),其他的是訓練數據(5574 條中的 4459 條)。

讓咱們回顧整個流程,將全部步驟放入 scikit-learn 的 Pipeline 中:

In [31]:
 
實際當中一個常見的作法是將訓練集再次分割成更小的集合,例如,5 個大小相等的子集。而後咱們用 4 個子集訓練數據,用最後 1 個子集計算精度(稱之爲「驗證集」)。重複5次(每次使用不一樣的子集進行驗證),這樣能夠獲得模型的「穩定性「。若是模型使用不一樣子集的得分差別很是大,那麼極可能哪裏出錯了(壞數據或者不良的模型方差)。返回,分析錯誤,從新檢查輸入數據有效性,從新檢查數據清洗。

在這個例子裏,一切進展順利:

In [32]:
 
 

得分確實比訓練所有數據時差一點點( 5574 個訓練例子中,準確性 0.97),可是它們至關穩定:

In [33]:
 
 

咱們天然會問,如何改進這個模型?這個得分已經很高了,可是咱們一般如何改進模型呢?

Naive Bayes 是一個高誤差-低方差的分類器(簡單且穩定,不易過分擬合)。與其相反的例子是低誤差-高方差(容易過分擬合)的 k 最臨近(kNN)分類器和決策樹。Bagging(隨機森林)是一種經過訓練許多(高方差)模型和求均值來下降方差的方法。

 

換句話說:

  • 高誤差 = 分類器比較執拗。它有本身的想法,數據可以改變的空間有限。另外一方面,也沒有多少過分擬合的空間(左圖)。
  • 低誤差 = 分類器更聽話,但也更神經質。你們都知道,讓它作什麼就作什麼可能形成麻煩(右圖)。
In [34]:
In [35]:
 
Out[35]:
 
  download (3)
 
 
 (咱們對數據的 64% 進行了有效訓練:保留 20% 的數據做爲測試集,保留剩餘的 20% 作 5 折交叉驗證 = > 0.8*0.8*5574 = 3567個訓練數據。)

隨着性能的提高,訓練和交叉驗證都表現良好,咱們發現因爲數據量較少,這個模型難以足夠複雜/靈活地捕獲全部的細微差異。在這種特殊案例中,無論怎樣作精度都很高,這個問題看起來不是很明顯。

關於這一點,咱們有兩個選擇:

  1. 使用更多的訓練數據,增長模型的複雜性;
  2. 使用更復雜(更低誤差)的模型,從現有數據中獲取更多信息。

在過去的幾年裏,隨着收集大規模訓練數據愈來愈容易,機器愈來愈快。方法 1 變得愈來愈流行(更簡單的算法,更多的數據)。簡單的算法(如 Naive Bayes)也有更容易解釋的額外優點(相對一些更復雜的黑箱模型,如神經網絡)。

瞭解瞭如何正確地評估模型,咱們如今能夠開始研究參數對性能有哪些影響。

第六步:如何調整參數?

到目前爲止,咱們看到的只是冰山一角,還有許多其它參數須要調整。好比使用什麼算法進行訓練。

上面咱們已經使用了 Navie Bayes,可是 scikit-learn 支持許多分類器:支持向量機、最鄰近算法、決策樹、Ensamble 方法等…

 

咱們會問:IDF 加權對準確性有什麼影響?消耗額外成本進行詞形還原(與只用純文字相比)真的會有效果嗎?

讓咱們來看看:

In [37]:
In [38]:
 
 

(首先顯示最佳參數組合:在這個案例中是使用 idf=True 和 analyzer=split_into_lemmas 的參數組合)

快速合理性檢查

In [39]:
 
 

predict_proba 返回每類(ham,spam)的預測機率。在第一個例子中,消息被預測爲 ham 的機率 >99%,被預測爲 spam 的機率 <1%。若是進行選擇模型會認爲信息是 」ham「:

In [40]:
 
 

在訓練期間沒有用到的測試集的總體得分:

In [41]:
 
 
這是咱們使用詞形還原、TF-IDF 和 Navie Bayes 分類器的 ham 檢測 pipeline 得到的實際預測性能。

讓咱們嘗試另外一個分類器:支持向量機(SVM)。SVM 能夠很是迅速的獲得結果,它所須要的參數調整也不多(雖然比 Navie Bayes 稍多一點),在處理文本數據方面它是個好的起點。

In [42]:
In [43]:
 
 

所以,很明顯的,具備 C=1 的線性核函數是最好的參數組合。

再一次合理性檢查:

In [44]:
 
In [45]:
 
 

這是咱們使用 SVM 時能夠從 spam 郵件檢測流程中得到的實際預測性能。

第七步:生成預測器

通過基本分析和調優,真正的工做(工程)開始了。

生成預測器的最後一步是再次對整個數據集合進行訓練,以充分利用全部可用數據。固然,咱們將使用上面交叉驗證找到的最好的參數。這與咱們開始作的很是類似,但此次深刻了解它的行爲和穩定性。在不一樣的訓練/測試子集進行評價。

最終的預測器能夠序列化到磁盤,以便咱們下次想使用它時,能夠跳過全部訓練直接使用訓練好的模型:

In [46]:
 

加載的結果是一個與原始對象表現相同的對象:

In [47]:
 
 

生產執行的另外一個重要部分是性能。通過快速、迭代模型調整和參數搜索以後,性能良好的模型能夠被翻譯成不一樣的語言並優化。能夠犧牲幾個點的準確性換取一個更小、更快的模型嗎?是否值得優化內存使用狀況,或者使用 mmap 跨進程共享內存? 電動叉車

請注意,優化並不老是必要的,要從實際狀況出發。

還有一些須要考慮的問題,好比,生產流水線還須要考慮魯棒性(服務故障轉移、冗餘、負載平衡)、監測(包括異常自動報警)、HR 可替代性(避免關於工做如何完成的「知識孤島」、晦澀/鎖定的技術、調整結果的黑藝術)。如今,開源世界均可覺得全部這些領域提供可行的解決方法,因爲 OSI 批准的開源許可證,今天展現的全部工具均可以避免費用於商業用途。

 

其餘實用概念

數據稀疏性

在線學習,數據流

用於內存共享的 mmap,系統「冷啓動」負載時間

可擴展性、分佈式(集羣)處理

無監督學習

大多數數據沒有結構化。瞭解這些數據,其中沒有自帶的標籤(否則就成了監督學習!)。

咱們如何訓練沒有標籤的內容?這是什麼魔法?

分佈假設「在相似語境中出現的詞傾向於具備類似的含義」。上下文=句子,文檔,滑動窗口……

查看 google 關於無監督學習的 word2vec 在線演示。簡單的模型、大量數據(Google 新聞,1000 億詞,沒有標籤)。

下一步作什麼?

這個 notebook 的靜態版本(非交互版本)的 HTML,地址: http://radimrehurek.com/data_science_python (你可能已經在看了,但以防萬一)

交互式 notebook 源文件在 GitHub 上,
http://radimrehurek.com/data_science_python/data_science_python.ipynb(見上面的安裝說明)。

相關文章
相關標籤/搜索