Apache Mahout 简介 通过可伸缩、商业友好的机器学习来构建智能应用程序
在信息時代,公司和個人的成功越來越依賴于迅速有效地將大量數據轉化為可操作的信息。無論是每天處理數以千計的個人電子郵件消息,還是從海量博客文章中推測用戶的意圖,都需要使用一些工具來組織和增強數據。 這其中就蘊含著?機器學習領域以及本文章所介紹項目的前景:Apache Mahout(見?參考資料)。
機器學習是人工智能的一個分支,它涉及通過一些技術來允許計算機根據之前的經驗改善其輸出。此領域與數據挖掘密切相關,并且經常需要使用各種技巧,包括統計學、概率論和模式識別等。雖然機器學習并不是一個新興領域,但它的發展速度是毋庸置疑的。許多大型公司,包括 IBM?、Google、Amazon、Yahoo! 和 Facebook,都在自己的應用程序中實現了機器學習算法。此外,還有許多公司在自己的應用程序中應用了機器學習,以便學習用戶以及過去的經驗,從而獲得收益。
在簡要概述機器學習的概念之后,我將介紹 Apache Mahout 項目的特性、歷史和目標。然后,我將演示如何使用 Mahout 完成一些有趣的機器學習任務,這需要使用免費的 Wikipedia 數據集。
機器學習 101
機器學習可以應用于各種目的,從游戲、欺詐檢測到股票市場分析。它用于構建類似于 Netflix 和 Amazon 所提供的系統,可根據用戶的購買歷史向他們推薦產品,或者用于構建可查找特定時間內的所有相似文章的系統。它還可以用于根據類別(體育、經濟和戰爭等)對網頁自動進行分類,或者用于標記垃圾電子郵件。本文無法完全列出機器學習的所有應用。如果您希望更加深入地探究該領域,我建議您參閱?參考資料。
可以采用一些機器學習方法來解決問題。我將重點討論其中最常用的兩個 —監管和?無監管學習 —因為它們是 Mahout 支持的主要功能。
監管學習的任務是學習帶標簽的訓練數據的功能,以便預測任何有效輸入的值。監管學習的常見例子包括將電子郵件消息分類為垃圾郵件,根據類別標記網頁,以及識別手寫輸入。創建監管學習程序需要使用許多算法,最常見的包括神經網絡、Support Vector Machines (SVMs) 和 Naive Bayes 分類程序。
無監管學習的任務是發揮數據的意義,而不管數據的正確與否。它最常應用于將類似的輸入集成到邏輯分組中。它還可以用于減少數據集中的維度數據,以便只專注于最有用的屬性,或者用于探明趨勢。無監管學習的常見方法包括 k-Means、分層集群和自組織地圖。
在本文中,我將重點討論 Mahout 當前已實現的三個具體的機器學習任務。它們正好也是實際應用程序中相當常見的三個領域:
- 協作篩選
- 集群
- 分類
在研究它們在 Mahout 中的實現之前,我將從概念的層面上更加深入地討論這些任務。
協作篩選
協作篩選(CF) 是 Amazon 等公司極為推崇的一項技巧,它使用評分、單擊和購買等用戶信息為其他站點用戶提供推薦產品。CF 通常用于推薦各種消費品,比如說書籍、音樂和電影。但是,它還在其他應用程序中得到了應用,主要用于幫助多個操作人員通過協作來縮小數據范圍。您可能已經在 Amazon 體驗了 CF 的應用,如?圖 1所示:
圖 1. 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 的入門相對比較簡單。首先,您需要安裝以下軟件:
- JDK 1.6 或更高版本
- Ant 1.7 或更高版本
- 如果要編譯 Mahout 源代碼,還需要安裝?Maven 2.0.9 或 2.0.10
您還需要本文的示例代碼(見?下載部分),其中包括一個 Mahout 副本及其依賴關系。依照以下步驟安裝示例代碼:
步驟 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和一個?Recommender。UserNeighborhood可以識別與相關用戶類似的用戶,并傳遞給?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 創建數據集群的步驟包括:
首先,集群算法要求數據必需采用適合處理的格式。在機器學習中,數據通常被表示為?矢量,有時也稱作?特征矢量。在集群中,矢量是表示數據的一組權重值。我將使用通過 Wikipedia 文檔生成的矢量來演示集群,但是也可以從其他地方獲取矢量,比如說傳感器數據或用戶資料。Mahout 隨帶了兩個?Vector表示:DenseVector和?SparseVector。根據所使用的數據,您需要選擇合適的實現,以便實現良好的性能。通常而言,基于文本的問題是很少的,因此應該使用?SparseVector來處理文本。另一方面,如果大多數矢量的大多數值都是非零的,則比較適合使用?DenseVector。如果您對此不確定,可以嘗試這兩種實現來處理數據的一個子集,然后確定哪種實現的運行速度更快。
通過 Wikipedia 內容生成矢量的方法如下(我已經完成了此工作):
運行這兩個步驟的結果是生成一個文件,該文件類似于與您從?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 中輸出的數據結構是?混合矩陣。混合矩陣可以描述各類別有多少正確分類的結果和錯誤分類的結果。
總的來說,生成分類結果的步驟如下:
運行所有這些命令(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 |
參考資料
學習
- 機器學習
- 機器學習:Wikipedia 頁面提供了一些有用的入門信息和優秀的參考資料,可幫助您了解關于機器學習(包含監管學習等方法)的更多信息。
- Programming Collective Intelligence(Toby Segaran,O'Reilly,2007 年):本書可以幫助您迅速掌握許多機器任務。
- Artificial Intelligence | Machine Learning:使用斯坦福大學教授 Andrew Ng 開發的這個類。
- Evaluation of clustering:了解關于評估集群的更多信息。另請參閱 Mahout 郵件列表上的?討論。
- Bayes Theorem:了解 Bayes Theorem 的運行原理。
- Lp空間:理解 Lp格式。
- Apache Mahout 和 Apache Lucene
- Mahout 項目主頁:搜索關于 Mahout 的所有內容。
- “Map-Reduce for Machine Learning on Multicore”:這篇文章將幫助您啟動 Mahout。
- “MapReduce: Simplified Data Processing on Large Clusters”(Google Research Publications):閱讀關于 Map-Reduce 初級文章。
- Taste:閱讀 Taste 文檔。
- Apache Lucene:了解關于 Lucene 的更多信息。
- Apache Lucene on developerWorks:通過這些文章探索 Lucene 的世界。
- Creating Vectors from Text:閱讀 Mahout Wiki 中的這個條目,了解如何將數據轉換為 Mahout 的?Vector類。
- Cluster Your Data:閱讀此 Mahout Wiki 頁面,了解關于如何實現數據集群的更多信息。
- Apache Hadoop:
- Apache Hadoop:了解關于 Hadoop 的更多信息。
- Hadoop 快速入門教程:了解如何運行 Hadoop Job。
- HBase:理解 Hadoop 數據庫。
- from:?https://www.ibm.com/developerworks/cn/java/j-mahout/
總結
以上是生活随笔為你收集整理的Apache Mahout 简介 通过可伸缩、商业友好的机器学习来构建智能应用程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 决策树算法介绍及应用
- 下一篇: 探索 Python、机器学习和 NLTK