Apache Mahout 簡介 經過可伸縮、商業友好的機器學習來構建智能應用程序

在信息時代,公司和我的的成功愈來愈依賴於迅速有效地將大量數據轉化爲可操做的信息。不管是天天處理數以千計的我的電子郵件消息,仍是從海量博客文章中推測用戶的意圖,都須要使用一些工具來組織和加強數據。 這其中就蘊含着 機器學習領域以及本文章所介紹項目的前景:Apache Mahout(見 參考資料)。html

機器學習是人工智能的一個分支,它涉及經過一些技術來容許計算機根據以前的經驗改善其輸出。此領域與數據挖掘密切相關,而且常常須要使用各類技巧,包括統計學、機率論和模式識別等。雖然機器學習並非一個新興領域,但它的發展速度是毋庸置疑的。許多大型公司,包括 IBM®、Google、Amazon、Yahoo! 和 Facebook,都在本身的應用程序中實現了機器學習算法。此外,還有許多公司在本身的應用程序中應用了機器學習,以便學習用戶以及過去的經驗,從而得到收益。java

在簡要概述機器學習的概念以後,我將介紹 Apache Mahout 項目的特性、歷史和目標。而後,我將演示如何使用 Mahout 完成一些有趣的機器學習任務,這須要使用免費的 Wikipedia 數據集。程序員

機器學習 101

機器學習能夠應用於各類目的,從遊戲、欺詐檢測到股票市場分析。它用於構建相似於 Netflix 和 Amazon 所提供的系統,可根據用戶的購買歷史向他們推薦產品,或者用於構建可查找特定時間內的全部類似文章的系統。它還能夠用於根據類別(體育、經濟和戰爭等)對網頁自動進行分類,或者用於標記垃圾電子郵件。本文沒法徹底列出機器學習的全部應用。若是您但願更加深刻地探究該領域,我建議您參閱 參考資料算法

能夠採用一些機器學習方法來解決問題。我將重點討論其中最經常使用的兩個 —監管和 無監管學習 —由於它們是 Mahout 支持的主要功能。數據庫

監管學習的任務是學習帶標籤的訓練數據的功能,以便預測任何有效輸入的值。監管學習的常見例子包括將電子郵件消息分類爲垃圾郵件,根據類別標記網頁,以及識別手寫輸入。建立監管學習程序須要使用許多算法,最多見的包括神經網絡、Support Vector Machines (SVMs) 和 Naive Bayes 分類程序。apache

無監管學習的任務是發揮數據的意義,而無論數據的正確與否。它最常應用於將相似的輸入集成到邏輯分組中。它還能夠用於減小數據集中的維度數據,以便只專一於最有用的屬性,或者用於探明趨勢。無監管學習的常見方法包括 k-Means、分層集羣和自組織地圖。編程

在本文中,我將重點討論 Mahout 當前已實現的三個具體的機器學習任務。它們正好也是實際應用程序中至關常見的三個領域:網絡

  • 協做篩選
  • 集羣
  • 分類

在研究它們在 Mahout 中的實現以前,我將從概念的層面上更加深刻地討論這些任務。數據結構

協做篩選

協做篩選(CF) 是 Amazon 等公司極爲推崇的一項技巧,它使用評分、單擊和購買等用戶信息爲其餘站點用戶提供推薦產品。CF 一般用於推薦各類消費品,好比說書籍、音樂和電影。可是,它還在其餘應用程序中獲得了應用,主要用於幫助多個操做人員經過協做來縮小數據範圍。您可能已經在 Amazon 體驗了 CF 的應用,如 圖 1所示:併發

圖 1. Amazon 上的協做篩選示例
Amazon 上的協做篩選示例

CF 應用程序根據用戶和項目歷史向系統的當前用戶提供推薦。生成推薦的 4 種典型方法以下:

  • 基於用戶:經過查找類似的用戶來推薦項目。因爲用戶的動態特性,這一般難以定量。
  • 基於項目:計算項目之間的類似度並作出推薦。項目一般不會過多更改,所以這一般能夠離線完成。
  • Slope-One:很是快速簡單的基於項目的推薦方法,須要使用用戶的評分信息(而不只僅是布爾型的首選項)。
  • 基於模型:經過開發一個用戶及評分模型來提供推薦。

全部 CF 方法最終都須要計算用戶及其評分項目之間的類似度。能夠經過許多方法來計算類似度,而且大多數 CF 系統都容許您插入不一樣的指標,以便肯定最佳結果。

集羣

對於大型數據集來講,不管它們是文本仍是數值,通常均可以將相似的項目自動組織,或 集羣,到一塊兒。舉例來講,對於全美國某天內的全部的報紙新聞,您可能但願將全部主題相同的文章自動歸類到一塊兒;而後,能夠選擇專一於特定的集羣和主題,而不須要閱讀大量無關內容。另外一個例子是:某臺機器上的傳感器會持續輸出內容,您可能但願對輸出進行分類,以便於分辨正常和有問題的操做,由於普通操做和異常操做會歸類到不一樣的集羣中。

與 CF 相似,集羣計算集合中各項目之間的類似度,但它的任務只是對類似的項目進行分組。在許多集羣實現中,集合中的項目都是做爲矢量表示在 n維度空間中的。經過矢量,開發人員可使用各類指標(好比說曼哈頓距離、歐氏距離或餘弦類似性)來計算兩個項目之間的距離。而後,經過將距離相近的項目歸類到一塊兒,能夠計算出實際集羣。

能夠經過許多方法來計算集羣,每種方法都有本身的利弊。一些方法從較小的集羣逐漸構建成較大的集羣,還有一些方法將單個大集羣分解爲愈來愈小的集羣。在發展成平凡集羣表示以前(全部項目都在一個集羣中,或者全部項目都在各自的集羣中),這兩種方法都會經過特定的標準退出處理。流行的方法包括 k-Means 和分層集羣。以下所示,Mahout 也隨帶了一些不一樣的集羣方法。

分類

分類(一般也稱爲 歸類)的目標是標記不可見的文檔,從而將它們歸類不一樣的分組中。機器學習中的許多分類方法都須要計算各類統計數據(經過指定標籤與文檔的特性相關),從而建立一個模型以便之後用於分類不可見的文檔。舉例來講,一種簡單的分類方法能夠跟蹤與標籤相關的詞,以及這些詞在某個標籤中的出現次數。而後,在對新文檔進行分類時,系統將在模型中查找文檔中的詞並計算機率,而後輸出最佳結果並經過一個分類來證實結果的正確性。

分類功能的特性能夠包括詞彙、詞彙權重(好比說根據頻率)和語音部件等。固然,這些特性確實有助於將文檔關聯到某個標籤並將它整合到算法中。

機器學習這個領域至關普遍和活躍。理論再多終究須要實踐。接下來,我將繼續討論 Mahout 及其用法。

 

Mahout 簡介

Apache Mahout 是 Apache Software Foundation (ASF) 開發的一個全新的開源項目,其主要目標是建立一些可伸縮的機器學習算法,供開發人員在 Apache 在許可下無償使用。該項目已經發展到了它的最二個年頭,目前只有一個公共發行版。Mahout 包含許多實現,包括集羣、分類、CP 和進化程序。此外,經過使用 Apache Hadoop 庫,Mahout 能夠有效地擴展到雲中(見 參考資料)。

Mahout 的歷史

背景知識

mahout的意思是大象的飼養者及驅趕者。Mahout 這個名稱來源於該項目(有時)使用 Apache Hadoop —其徽標上有一頭黃色的大象 —來實現可伸縮性和容錯性。

Mahout 項目是由 Apache Lucene(開源搜索)社區中對機器學習感興趣的一些成員發起的,他們但願創建一個可靠、文檔翔實、可伸縮的項目,在其中實現一些常見的用於集羣和分類的機器學習算法。該社區最初基於 Ng et al. 的文章 「Map-Reduce for Machine Learning on Multicore」(見 參考資料),但此後在發展中又併入了更多普遍的機器學習方法。Mahout 的目標還包括:

  • 創建一個用戶和貢獻者社區,使代碼沒必要依賴於特定貢獻者的參與或任何特定公司和大學的資金。
  • 專一於實際用例,這與高新技術研究及未經驗證的技巧相反。
  • 提供高質量文章和示例。

特性

雖然在開源領域中相對較爲年輕,但 Mahout 已經提供了大量功能,特別是在集羣和 CF 方面。Mahout 的主要特性包括:

Map-Reduce 簡介

Map-Reduce 是 Google 開發的一種分佈式編程 API,並在 Apache Hadoop 項目中獲得了實現。與分佈式文件系統相結合,它能夠爲程序員提供一個定義良好的用於描述計算任務的 API,從而幫助他們簡化並行化問題的任務。(有關更多信息,請參見 參考資料)。

  • Taste CF。Taste 是 Sean Owen 在 SourceForge 上發起的一個針對 CF 的開源項目,並在 2008 年被贈予 Mahout。
  • 一些支持 Map-Reduce 的集羣實現包括 k-Means、模糊 k-Means、Canopy、Dirichlet 和 Mean-Shift。
  • Distributed Naive Bayes 和 Complementary Naive Bayes 分類實現。
  • 針對進化編程的分佈式適用性功能。
  • Matrix 和矢量庫。
  • 上述算法的示例。

Mahout 入門

Mahout 的入門相對比較簡單。首先,您須要安裝如下軟件:

您還須要本文的示例代碼(見 下載部分),其中包括一個 Mahout 副本及其依賴關係。依照如下步驟安裝示例代碼:

  1. 解壓縮 sample.zip
  2. cd apache-mahout-examples
  3. ant install

步驟 3 將下載必要的 Wikipedia 文件將編譯代碼。所使用的 Wikipedia 文件大約爲 2.5 GB,所以下載時間將由您的寬帶決定。

 

創建一個推薦引擎

Mahout 目前提供了一些工具,可用於經過 Taste 庫創建一個推薦引擎 —針對 CF 的快速且靈活的引擎。Taste 支持基於用戶和基於項目的推薦,而且提供了許多推薦選項,以及用於自定義的界面。Taste 包含 5 個主要組件,用於操做 用戶項目和 首選項

  • DataModel:用於存儲 用戶項目和 首選項
  • UserSimilarity:用於定義兩個用戶之間的類似度的界面
  • ItemSimilarity:用於定義兩個項目之間的類似度的界面
  • Recommender:用於提供推薦的界面
  • UserNeighborhood:用於計算類似用戶鄰近度的界面,其結果隨時可由 Recommender使用

藉助這些組件以及它們的實現,開發人員能夠構建複雜的推薦系統,提供基於實時或者離線的推薦。基於實時的推薦常常只能處理數千用戶,而離線推薦具備更好的適用性。Taste 甚至提供了一些可利用 Hadoop 離線計算推薦的工具。在許多狀況中,這種合適的方法能夠幫助您知足包含大量用戶、項目和首選項的大型系統的需求。

爲了演示如何構建一個簡單的推薦系統,我須要一些用戶、項目和評分。爲此,咱們會使用 cf.wikipedia.GenerateRatings中的代碼(包含在示例代碼的源代碼中)爲 Wikipedia 文檔(Taste 稱之爲 項目)隨機生成大量 用戶和 首選項,而後再手動補充一些關於特定話題(Abraham Lincoln)的評分,從而建立示例中的最終 recommendations.txt 文件。此方法的內涵是展現 CF 如何將對某特定話題感興趣的人導向相關話題的其餘文檔。此示例的數據來源於 990(標記爲從 0 到 989)個隨機用戶,他們隨機爲集合中的全部文章隨機分配了一些評分,以及 10 個用戶(標記爲從 990 到 999),他們對集合中包含 Abraham Lincoln關鍵字的 17 篇文章中的部分文章進行了評分。

注意虛構數據!

本文中的示例徹底使用的是虛構數據。我本身完成了全部評分,模擬了 10 個對 Abraham Lincoln 感興趣的實際用戶。雖然我相信數據內部的概念頗有趣,但數據自己以及所使用的值並不是如此。若是您但願得到實際數據,我建議您參閱 University of Minnesota 的 GroupLens 項目,以及 Taste 文檔(見 參考資料)。我選擇虛構數據的緣由是但願在全部示例中都使用單一數據集。

首先,我將演示如何爲在 recommendations.txt 文件中指定了分數的用戶建立推薦。這是 Taste 最爲常見的應用,所以首先須要載入包含推薦的數據,並將它存儲在一個 DataModel中。Taste 提供了一些不一樣的 DataModel實現,用於操做文件和數據庫。在本例中,爲簡便起見,我選擇使用 FileDataModel類,它對各行的格式要求爲:用戶 ID、項目 ID、首選項 —其中,用戶 ID 和項目 ID 都是字符串,而首選項能夠是雙精度型。創建了模型以後,我須要通知 Taste 應該如何經過聲明一個 UserSimilarity實現來比較用戶。根據所使用的UserSimilarity實現,您可能還須要通知 Taste 如何在未指定明確用戶設置的狀況下推斷首選項。清單 1 實現了以上代碼。(示例代碼 中的cf.wikipedia.WikipediaTasteUserDemo包含了完整的代碼清單)。

清單 1. 建立模型和定義用戶類似度
 //create the data model 
 FileDataModel dataModel = new FileDataModel(new File(recsFile)); 
 UserSimilarity userSimilarity = new PearsonCorrelationSimilarity(dataModel); 
 // Optional: 
 userSimilarity.setPreferenceInferrer(new AveragingPreferenceInferrer(dataModel));

在 清單 1中,我使用了 PearsonCorrelationSimilarity,它用於度量兩個變量之間的關係,可是也可使用其餘 UserSimilarity度量。應該根據數據和測試類型來選擇類似度度量。對於此數據,我發現這種組合最爲合適,但仍然存在一些問題。有關如何選擇類似度度量的更多信息,請訪問 Mahout 網站(見 參考資料)。

爲了完成此示例,我須要構建一個 UserNeighborhood和一個 RecommenderUserNeighborhood能夠識別與相關用戶相似的用戶,並傳遞給 Recommender,後者將負責建立推薦項目排名表。清單 2 實現瞭如下想法:

清單 2. 生成推薦
 //Get a neighborhood of users 
 UserNeighborhood neighborhood = 
        new NearestNUserNeighborhood(neighborhoodSize, userSimilarity, dataModel); 
 //Create the recommender 
 Recommender recommender = 
        new GenericUserBasedRecommender(dataModel, neighborhood, userSimilarity); 
 User user = dataModel.getUser(userId); 
 System.out.println("-----"); 
 System.out.println("User: " + user); 
 //Print out the users own preferences first 
 TasteUtils.printPreferences(user, handler.map); 
 //Get the top 5 recommendations 
 List<RecommendedItem> recommendations = 
        recommender.recommend(userId, 5); 
 TasteUtils.printRecs(recommendations, handler.map);

您能夠在命令行中運行整個示例,方法是在包含示例的目錄中執行 ant user-demo。運行此命令將打印輸出虛構用戶 995 的首選項和推薦,該用戶只是 Lincoln 的愛好者之一。清單 3 顯示了運行 ant user-demo的輸出:

清單 3. 用戶推薦的輸出
 [echo] Getting similar items for user: 995 with a neighborhood of 5 
     [java] 09/08/20 08:13:51 INFO file.FileDataModel: Creating FileDataModel 
            for file src/main/resources/recommendations.txt 
     [java] 09/08/20 08:13:51 INFO file.FileDataModel: Reading file info... 
     [java] 09/08/20 08:13:51 INFO file.FileDataModel: Processed 100000 lines 
     [java] 09/08/20 08:13:51 INFO file.FileDataModel: Read lines: 111901 
     [java] Data Model: Users: 1000 Items: 2284 
     [java] ----- 
     [java] User: 995 
     [java] Title: August 21 Rating: 3.930000066757202 
     [java] Title: April Rating: 2.203000068664551 
     [java] Title: April 11 Rating: 4.230000019073486 
     [java] Title: Battle of Gettysburg Rating: 5.0 
     [java] Title: Abraham Lincoln Rating: 4.739999771118164 
     [java] Title: History of The Church of Jesus Christ of Latter-day Saints 
              Rating: 3.430000066757202 
     [java] Title: Boston Corbett Rating: 2.009999990463257 
     [java] Title: Atlanta, Georgia Rating: 4.429999828338623 
     [java] Recommendations: 
     [java] Doc Id: 50575 Title: April 10 Score: 4.98 
     [java] Doc Id: 134101348 Title: April 26 Score: 4.860541 
     [java] Doc Id: 133445748 Title: Folklore of the United States Score: 4.4308662 
     [java] Doc Id: 1193764 Title: Brigham Young Score: 4.404066 
     [java] Doc Id: 2417937 Title: Andrew Johnson Score: 4.24178

從清單 3 中能夠看到,系統推薦了一些信心級別不一樣的文章。事實上,這些項目的分數都是由其餘 Lincoln 愛好者指定的,而不是用戶 995 一人所爲。若是您但願查看其餘用戶的結構,只須要在命令行中傳遞 -Duser.id=USER-ID參數,其中 USER-ID是 0和 999之間的編號。您還能夠經過傳遞 -Dneighbor.size=X來更改鄰近空間,其中,X是一個大於 0 的整型值。事實上,將鄰近空間更改成 10能夠生成極爲不一樣的結果,這是由於阾近範圍內存在一個隨機用戶。要查看鄰近用戶以及共有的項目,能夠向命令行添加 -Dcommon=true

如今,若是您所輸入的編號剛好不在用戶範圍內,則會注意到示例生成了一個 NoSuchUserException。確實,應用程序須要處理新用戶進入系統的狀況。舉例來講,您能夠只顯示 10 篇最熱門的文章,一組隨機文章,或者一組 「不相關」 的文章 —或者,與其這樣,還不如不執行任何操做。

如前所述,基於用戶的方法常常不具備可伸縮性。在本例中,使用基於項目的方法是更好的選擇。幸運的是,Taste 能夠很是輕鬆地實現基於項目的方法。處理項目類似度的基本代碼並無很大差別,如清單 4 所示:

清單 4. 項目類似度示例(摘錄自 cf.wikipedia.WikipediaTasteItemItemDemo
 //create the data model 
 FileDataModel dataModel = new FileDataModel(new File(recsFile)); 
 //Create an ItemSimilarity 
 ItemSimilarity itemSimilarity = new LogLikelihoodSimilarity(dataModel); 
 //Create an Item Based Recommender 
 ItemBasedRecommender recommender = 
        new GenericItemBasedRecommender(dataModel, itemSimilarity); 
 //Get the recommendations 
 List<RecommendedItem> recommendations = 
        recommender.recommend(userId, 5); 
 TasteUtils.printRecs(recommendations, handler.map);

與 清單 1相同,我根據推薦文件建立了一個 DataModel,但此次並未實例化 UserSimilarity實例,而是使用LogLikelihoodSimilarity建立了一個 ItemSimilarity,它能夠幫助處理不常見的事件。而後,我將 ItemSimilarity提供給一個ItemBasedRecommender,最後請求推薦。完成了!您能夠經過 ant item-demo命令在示例中代碼運行它。固然,在此基礎上,您可讓系統支持離線執行這些計算,您還能夠探索其餘的 ItemSimilarity度量。注意,因爲本示例中的數據是隨機的,所推薦的內容可能並不符合用戶的指望。事實上,您應該確保在測試過程當中計算結果,並嘗試不一樣的類似度指標,由於許多經常使用指標在一些邊界狀況中會因爲數據不足而沒法提供合適的推薦。

咱們再來看新用戶的例子,當用戶導航到某個項目以後,缺乏用戶首選項時的操做就比較容易實現了。對於這種狀況,您能夠利用項目計算並向ItemBasedRecommender請求與至關項目最類似的項目。清單 5 展現了相關代碼:

清單 5. 類似項目演示(摘錄自 cf.wikipedia.WikipediaTasteItemRecDemo
 //create the data model 
 FileDataModel dataModel = new FileDataModel(new File(recsFile)); 
 //Create an ItemSimilarity 
 ItemSimilarity itemSimilarity = new LogLikelihoodSimilarity(dataModel); 
 //Create an Item Based Recommender 
 ItemBasedRecommender recommender = 
        new GenericItemBasedRecommender(dataModel, itemSimilarity); 
 //Get the recommendations for the Item 
 List<RecommendedItem> simItems 
        = recommender.mostSimilarItems(itemId, numRecs); 
 TasteUtils.printRecs(simItems, handler.map);

您能夠經過在命令中執行 ant sim-item-demo來運行 清單 5。它與 清單 4之間的惟一差別就是,清單 5並無請求推薦,而是請求輸出最類似的項目。

如今,您能夠繼續深刻探索 Taste。要了解更多信息,請閱讀 Taste 文檔和 mahout-user@lucene.apache.org 郵件列表(見 參考資料)。接下來,我將討論如何經過利用 Mahout 的集羣功能來查找類似文章。

 

使用 Mahout 實現集羣

Mahout 支持一些集羣算法實現(都是使用 Map-Reduce 編寫的),它們都有一組各自的目標和標準:

  • Canopy:一種快速集羣算法,一般用於爲其餘集羣算法建立初始種子。
  • k-Means(以及 模糊 k-Means):根據項目與以前迭代的質心(或中心)之間的距離將項目添加到 k 集羣中。
  • Mean-Shift:無需任何關於集羣數量的 推理知識的算法,它能夠生成任意形狀的集羣。
  • Dirichlet:藉助基於多種機率模型的集羣,它不須要提早執行特定的集羣視圖。

從實際的角度來講,名稱和實現並不如它們生成的結果重要。瞭解了這一點以後,我將展現 k-Means 的運行原理,而其他內容將由您本身去研究。請記住,要有效運行每一個算法,您須要知足它們各自的的需求。

簡單來講(詳細信息見下文),使用 Mahout 建立數據集羣的步驟包括:

  1. 準備輸入。若是建立文本集羣,您須要將文本轉換成數值表示。
  2. 使用 Mahout 中可用的 Hadoop 就緒的驅動程序運行所選集羣算法。
  3. 計算結果。
  4. 若是有必要,執行迭代。

首先,集羣算法要求數據必需採用適合處理的格式。在機器學習中,數據一般被表示爲 矢量,有時也稱做 特徵矢量。在集羣中,矢量是表示數據的一組權重值。我將使用經過 Wikipedia 文檔生成的矢量來演示集羣,可是也能夠從其餘地方獲取矢量,好比說傳感器數據或用戶資料。Mahout 隨帶了兩個 Vector表示:DenseVector和 SparseVector。根據所使用的數據,您須要選擇合適的實現,以便實現良好的性能。一般而言,基於文本的問題是不多的,所以應該使用 SparseVector來處理文本。另外一方面,若是大多數矢量的大多數值都是非零的,則比較適合使用 DenseVector。若是您對此不肯定,能夠嘗試這兩種實現來處理數據的一個子集,而後肯定哪一種實現的運行速度更快。

經過 Wikipedia 內容生成矢量的方法以下(我已經完成了此工做):

  1. 將內容索引編入 Lucene,確保存儲相關字段(用於生成矢量的字段)的 term 矢量。我不會討論這方面的詳細信息 —不在本文討論範圍以內 —但我會提供一些簡要提示以及 Lucene 上的一些參考資料。Lucene 提供了一個稱爲 EnWikiDocMaker的類(包含在 Lucene 的contrib/benchmark包中),該類能夠讀取 Wikipedia 文件塊中的內容並生成編入 Lucene 索引的文檔。
  2. 使用 org.apache.mahout.utils.vectors.lucene.Driver類(位於 Mahout 的 utils模塊中)經過 Lucene 索引建立矢量。此驅動程序提供了大量用於建立矢量的選項。Mahout wiki 頁面 「Creating Vectors from Text」 提供了更多信息(見 參考資料)。

運行這兩個步驟的結果是生成一個文件,該文件相似於與您從 Getting started with Mahout 入門部分下載的 n2.tar.gz 文件。須要說明一下,n2.tar.gz 文件中的矢量是經過由 ant install方法以前下載的 Wikipedia 「塊」 文件中的全部文件的索引建立的。矢量將被格式化爲 Euclidean 格式(或者 L2格式;請參見 參考資料)。在使用 Mahout 時,您可能但願嘗試採用不一樣的方法來建立矢量,以肯定哪一種方法的效果最好。

評估結果

能夠採用多種方法來評估集羣結果。許多人最開始都是使用手動檢查與隨機測試相結合的方法。可是,要實現使人知足的結果,一般都須要使用一些更加高級的計算技巧,好比說使用一些準則開發一個黃金標準。有關評估結果的更多信息,請參見 參考資料。在本例中,我使用手動檢查來判斷結果集羣是否有意義。若是要投入生產,則應該使用更加嚴格的流程。

建立了一組矢量以後,接下來須要運行 k-Means 集羣算法。Mahout 爲全部集羣算法都提供了驅動程序,包括 k-Means 算法,更合適的名稱應該是 KMeansDriver。能夠直接將驅動程序做爲單獨的程序使用,而不須要 Hadoop 的支持,好比說您能夠直接運行 ant k-means。有關 KMeansDriver可接受的參數的更多信息,請查看 build.xml 中的 Ant k-means 目標。完成此操做以後,您可使用 ant dump命令打印輸出結果。

成功在獨立模式中運行驅動程序以後,您能夠繼續使用 Hadoop 的分佈式模式。爲此,您須要 Mahout Job JAR,它位於示例代碼的 hadoop 目錄中。Job JAR 包能夠將全部代碼和依賴關係打包到一個 JAR 文件中,以便於加載到 Hadoop 中。您還須要下載 Hadoop 0.20,並依照 Hadoop 教程的指令,首先在準分佈式模式(也就是一個集羣)中運行,而後再採用徹底分佈式模式。有關更多信息,請參見 Hadoop 網站及資源,以及 IBM 雲計算資源(參見 參考資料)。

 

使用 Mahout 實現內容分類

Mahout 目前支持兩種根據貝氏統計來實現內容分類的方法。第一種方法是使用簡單的支持 Map-Reduce 的 Naive Bayes 分類器。Naive Bayes 分類器爲速度快和準確性高而著稱,但其關於數據的簡單(一般也是不正確的)假設是徹底獨立的。當各種的訓練示例的大小不平衡,或者數據的獨立性不符合要求時,Naive Bayes 分類器會出現故障。第二種方法是 Complementary Naive Bayes,它會嘗試糾正 Naive Bayes 方法中的一些問題,同時仍然可以維持簡單性和速度。但在本文中,我只會演示 Naive Bayes 方法,由於這能讓您看到整體問題和 Mahout 中的輸入。

簡單來說,Naive Bayes 分類器包括兩個流程:跟蹤特定文檔及類別相關的特徵(詞彙),而後使用此信息預測新的、未見過的內容的類別。第一個步驟稱做 訓練(training),它將經過查看已分類內容的示例來建立一個模型,而後跟蹤與特定內容相關的各個詞彙的機率。第二個步驟稱做 分類,它將使用在訓練階段中建立的模型以及新文檔的內容,並結合 Bayes Theorem 來預測傳入文檔的類別。所以,要運行 Mahout 的分類器,您首先須要訓練模式,而後再使用該模式對新內容進行分類。下一節將演示如何使用 Wikipedia 數據集來實現此目的。

運行 Naive Bayes 分類器

在運行訓練程序和分類器以前,您須要準備一些用於訓練和測試的文檔。您能夠經過運行 ant prepare-docs來準備一些 Wikipedia 文件(經過 install目標下載的文件)。這將使用 Mahout 示例中的 WikipediaDatasetCreatorDriver類來分開 Wikipedia 輸入文件。分開文檔的標準是它們的相似是否與某個感興趣的類別相匹配。感興趣的類別能夠是任何有效的 Wikipedia 類別(或者甚至某個 Wikipedia 類別的任何子字符串)。舉例來講,在本例中,我使用了兩個類別:科學(science)和歷史(history)。所以,包含單詞 science或 history的全部 Wikipedia 類別都將被添加到該類別中(不須要準確匹配)。此外,系統爲每一個文檔添加了標記並刪除了標點、Wikipedia 標記以及此任務不須要的其餘特徵。最終結果將存儲在一個特定的文件中(該文件名包含類別名),並採用每行一個文檔的格式,這是 Mahout 所需的輸入格式。一樣,運行ant prepare-test-docs代碼能夠完成相同的文檔測試工做。須要確保測試和訓練文件沒有重合,不然會形成結果不許確。從理論上說,使用訓練文檔進行測試應該能實現最的結果,但實際狀況可能並不是如此。

設置好訓練和測試集以後,接下來須要經過 ant train目標來運行 TrainClassifier類。這應該會經過 Mahout 和 Hadoop 生成大量日誌。完成後,ant test將嘗試使用在訓練時創建的模型對示例測試文檔進行分類。這種測試在 Mahout 中輸出的數據結構是 混合矩陣。混合矩陣能夠描述各種別有多少正確分類的結果和錯誤分類的結果。

總的來講,生成分類結果的步驟以下:

  1. ant prepare-docs
  2. ant prepare-test-docs
  3. ant train
  4. ant test

運行全部這些命令(Ant 目標 classifier-example將在一次調用中捕獲全部它們),這將生成如清單 6 所示的彙總和混合矩陣:

清單 6. 運行 Bayes 分類器對歷史和科學主題進行分類的結果
 [java] 09/07/22 18:10:45 INFO bayes.TestClassifier: history 
                                  95.458984375    3910/4096.0 
 [java] 09/07/22 18:10:46 INFO bayes.TestClassifier: science 
                                  15.554072096128172      233/1498.0 
 [java] 09/07/22 18:10:46 INFO bayes.TestClassifier: ================= 
 [java] Summary 
 [java] ------------------------------------------------------- 
 [java] Correctly Classified Instances          :       4143 
                                                    74.0615% 
 [java] Incorrectly Classified Instances        :       1451 
                                                    25.9385% 
 [java] Total Classified Instances              :       5594 
 [java] 
 [java] ======================================================= 
 [java] Confusion Matrix 
 [java] ------------------------------------------------------- 
 [java] a           b       <--Classified as 
 [java] 3910        186      |  4096        a     = history 
 [java] 1265        233      |  1498        b     = science 
 [java] Default Category: unknown: 2

中間過程的結果存儲在 base 目錄下的 wikipedia 目錄中。

獲取告終果以後,顯然還有一個問題:「我應該如何作?」彙總結果代表,正確率和錯誤率大概分別爲 75 % 和 25 %。這種結果看上去很是合理,特別是它比隨機猜想要好不少。但在仔細分析以後,我發現對歷史信息的預測(正確率大約爲 95 %)至關出色,而對科學信息的預測則至關糟糕(大約 15 %)。爲了查找其緣由,我查看了訓練的輸入文件,並發現與歷史相關的示例要比科學多不少(文件大小几乎差了一倍),這多是一個潛在的問題。

對於測試,您能夠向 ant test添加 -Dverbose=true選項,這會顯示關於各測試輸入的信息,以及它的標籤是否正確。仔細研究此輸出,您能夠查找文檔並分析它分類錯誤的緣由。我還能夠嘗試不一樣的輸入參數,或者使用更加科學數據來從新訓練模型,以肯定是否可以改善此結果。

在訓練模型時考慮使用特徵選擇也是很重要的。對於這些示例,我使用 Apache Lucene 中的 WikipediaTokenizer來標記初始文檔,可是我沒有盡力刪除可能標記錯誤的經常使用術語或垃圾術語。若是要將此分類器投入生產,那麼我會更加深刻地研究輸入和其餘設置,以彌補性能的每一個方面。

爲了肯定 Science 結果是不是個意外,我嘗試了一組不一樣的類別:共和(Republican)與民主(Democrat)。在本例中,我但願預測新文檔是否與 Republicans 或者 Democrats 相關。爲了幫助您獨立實現此功能,我在 src/test/resources 中建立了 repubs-dems.txt 文件。而後,經過如下操做完成分類步驟:

 ant classifier-example -Dcategories.file=./src/test/resources/repubs-dems.txt -Dcat.dir=rd

兩個 -D值僅僅指向類別文件以及 wikipedia 目錄中存儲中間結果的目錄。此結果概要和混合矩陣如清單 7 所示:

清單 7. 運行 Bayes 分別器查找 Republicans 和 Democrats 的結果
 [java] 09/07/23 17:06:38 INFO bayes.TestClassifier: -------------- 
 [java] 09/07/23 17:06:38 INFO bayes.TestClassifier: Testing: 
                                wikipedia/rd/prepared-test/democrats.txt 
 [java] 09/07/23 17:06:38 INFO bayes.TestClassifier: democrats      70.0 
                                                                    21/30.0 
 [java] 09/07/23 17:06:38 INFO bayes.TestClassifier: -------------- 
 [java] 09/07/23 17:06:38 INFO bayes.TestClassifier: Testing: 
                              wikipedia/rd/prepared-test/republicans.txt 
 [java] 09/07/23 17:06:38 INFO bayes.TestClassifier: republicans    81.3953488372093 
                                                                    35/43.0 
 [java] 09/07/23 17:06:38 INFO bayes.TestClassifier: 
 [java] Summary 
 [java] ------------------------------------------------------- 
 [java] Correctly Classified Instances          :         56           76.7123% 
 [java] Incorrectly Classified Instances        :         17           23.2877% 
 [java] Total Classified Instances              :         73 
 [java] 
 [java] ======================================================= 
 [java] Confusion Matrix 
 [java] ------------------------------------------------------- 
 [java] a           b       <--Classified as 
 [java] 21          9        |  30          a     = democrats 
 [java] 8           35       |  43          b     = republicans 
 [java] Default Category: unknown: 2

雖然最終結果在正確性方面差很少是相同的,但您能夠看到我在這兩個類別中進行選擇時採起更好的方式。查看包含輸入文檔的 wikipedia/rd/prepared 目錄,咱們發現兩個訓練文件在訓練示例方面更加平衡了。 此外,與 「歷史 / 科學」 結果相比,獲得了示例也少了不少,由於每一個文件都比歷史或科學訓練集小不少。總的來講,結果至少代表平衡性獲得了顯著改善。更大的訓練集可能會抵消 Republicans 和 Democrats 之間的差別,即使不行也能夠暗示某個分組堅持其在 Wikipedia 上的消息是較好的選擇 —可是,我選擇將這留給政治學者來決定。

如今,我已經展現瞭如何在獨立模式中執行分類,接下來須要將代碼添加到雲中,並在 Hadoop 集羣上運行。與集羣代碼相同,您須要 Mahout Job JAR。除此以外,我以前提到的全部算法都是支持 Map-Reduce 的,而且可以在 Hadoop 教程所述的 Job 提交流程中運行。

 

結束語

Apache Mahout 在一年多的時間中走過了漫長的道路,爲集羣、分類和 CF 提供了許多重要的功能,但它還存在很大的發展空間。日益強大起來的還有 Map-Reduce 的隨機決策實現,它提供了分類、關聯規則、用於識別文檔主題的 Latent Dirichlet Allocation 以及許多使用 HBase 和其餘輔助存儲選項的類別選項。除了這些新的實現以外,還能夠找到許多演示、文檔和 bug 修復包。

最後,就像實際驅象者(mahout)利用大象的力量同樣,Apache Mahout 也能夠幫助您利用小黃象 Apache Hadoop 的強大功能。下次在須要集羣、分類或推薦內容時,特別是規模很大時,必定要考慮使用 Apache Mahout。

致謝

特別感謝 Ted Dunning 和 Sean Owen 對本文的審閱和建議。

 

下載

描述 名字 大小
示例代碼 j-mahout.zip 90MB

參考資料

學習

相關文章
相關標籤/搜索