mahout in action 中文翻譯html
1. 初識Mahoutjava
本章涵蓋如下內容:node
讀者可能從本書的標題中依然知曉,本書是一本使用的工具書,講解如何將mahout應用於業界。Mahout是Apache開源的機器學習庫。它實現的算法都被納入機器學習或者集體智慧的範疇,可是在這裏Mahout主要注重協同過濾/推薦引擎、聚類和分類。linux
Mahout是可伸縮的。Mahout致力於實現海量數據,單機沒法處理狀況下的機器學習工具。在目前階段,這種可伸縮性由java實現,有些部分基於Apache Hadoop這個分佈式計算框架實現。算法
Mahout是java庫。它不支持用戶接口,預裝好的服務器。以及安裝等功能。它是一個利於開發者使用的工具框架。數據庫
1.1 Mahout適合你嗎?apache
你也許想知道-Mahout是一個什麼工程,或者是一本什麼書?編程
若是你在找一本機器學習的教材,那本書就不適合了。本書沒有嘗試去全面解釋各類算法和展示技術的理論基礎和來源。閱讀本書能夠,但不保證,可以對機器學習技術,相似矩陣、向量等相關概念的熟悉。windows
若是你正在開發現代智能應用,那本書很適合。這本書提供了一種實踐非理論的處理方式,有完整的實例、解決方法指南。這本書在展現Mahout如何展現解決這些問題的時候,證實了一些被有經驗的開發者收集的獨特看法。數組
若是你是一我的工智能、機器學習以及相關領域的研究者,也適合用本書。你最大的挑戰就是將一個新算法代碼實現,Mahout提供了一個豐富的框架,模式集合以及測試、部署大規模新算法的現成模塊。這本書是一張快車票,讓你的機器學習算法運行在複雜的分佈式計算框架上。
若是你正在領導一個產品團隊或者初創公司想利用機器學習創造競爭優點,這本書也適合你。經過真實世界的例子,這本書能夠啓發你不少技術可能有多種實現方式的想法。它能夠幫助你充滿鬥志的技術團隊成員直接跳到很划算的實現能處理大量數據的應用,而在放在之前必須組織大量的技術資源才能夠實現。
最後,你可能想知道怎麼讀「Mahout」 – 這是一個經常使用的英式,它與「trout」押韻。這是一個北印度語的單詞,指的是驅使大象的人,爲了解釋這個詞,下面介紹一段關於它的歷史。Mahout項 目開始於2008年,做爲ApacheLucene的子項目,Apache Lucene項目是你們熟知的開源搜索引擎。Lucene提供了搜索、文本挖掘和信息檢索的高級實現。在計算機科學領域,這些概念和機器學習技術近似,像 聚類、分類。因此,Lucene貢獻者的一部分機器學習相關工做被剝離進入子項目。不久後,Mahout吸取進「Taste」開源協同過濾的項目。
自2010.4月起,Mahout成爲Apache的頂級項目。
Mahout的大量工做不僅是傳統的實現這些算法,也實現將這些算法,讓它們工做在hadoop之上。Hadoop的吉祥物是一頭大象,這也解釋了Mahout的工程名字。
圖1.Mahout以及相關項目 (見附件)
Mahout孵化了至關多的技術和算法,不少都是在開發和實驗階段。在工程的早期階段,有3個核心主題:協同過濾/推薦引擎、聚類和分類。這並非Mahout中全部內容,但倒是最顯著、成熟的主題(在本書寫做時),所以,這是本書的範圍。
若是你讀了以上內容,說明你已經對這3個系列的技術有潛在的興趣。可是爲以防萬一,請繼續閱讀下面的內容。
1.2 推薦系統引擎
推薦引擎是目前咱們使用的機器學習技術中最容易識別的。你可能已經見過相關的服務或網頁,基於歷史行爲推薦書、電影、文檔。他們嘗試推論出用戶偏好,並標記出用戶不知曉的、感興趣的item:
對於Amazon和示例其餘網站,經過這種聰明的交叉銷售,推薦系統確實有具體的經濟價值,同一家公司的報告指出推薦產品給用戶可以帶來8-12%的銷售增加。
http://www.practicalecommerce.com/articles/1942-10-Questions-on-Product-Recommendations
1.3 聚類
Clustering turns up in less apparent but equally well-known contexts.(首句該如何翻譯,哪位仁兄幫個忙?)
顧名思義,聚類技術嘗試去將大量的擁有相同類似度的事物彙集到不一樣的類中。聚類是在海量或者難於理解的數據集裏發現層次和順序,展示興趣模式,或使得數據集容易被理解。
1.4 分類
分類技術用於決定一個事物是否是屬於一種類型、類目,或者該事物是否是含有某些屬性。一樣地,分類無處不在,儘管更多的時候隱於幕後。
這些系統經過評估item的不少實例來學習,以推導出分類規則。這個日常的想法能夠找到不少應用:
分類有助於判斷一個新進入事物是否匹配先前發現的模式,也經常使用於分類行爲或者模式。分類也可用來檢測可疑的網絡活動或欺詐。也可用於根據用戶發信息斷定表示失望或者滿意。
1.5 擴展性
當有海量、高質量的數據輸入時,這些技術都可以達到最佳效果。在一些狀況下,這些技術不只要將海量數據做爲輸入,並且須要很快計算出結果。很快,這些因素使得可擴展性成爲一個很大的問題。
依據一些粗略估計,Picasa在3年前可能已經擁有5億張照片。這意味着天天須要分析數百萬圖片。分析一張圖片並非一個大問題,儘管須要重複數百萬次。可是,學習階段須要億萬圖片都提供相關信息 — 上了規模的計算,使用單機是不行的。
http://blogoscoped.com/archive/2007-03-12-n67.html
依據一個相似的分析,Google News大約天天有350萬新文章。儘管數量並非很大,考慮到這些文章必須和目前其餘文章同時聚類,爲了及時響應計算時間須要在幾分鐘內。
Netflix爲Netflix大獎發佈的子集中包含1億的打分。這只是適合競賽的數據,據推測,Netflix實際上擁有的和必須用於建立推薦系統的整個數據遠遠大於這個這個量級。
http://archive.ics.uci.edu/ml/machine-learning-databases/netflix/
這些技術很是有必要應用於輸入數據量很大的情形–由於很大,全部不適用於單機處理,甚至高配置的機器也不能夠。因此,任何人實現這些技術都不能迴避 可擴展性問題。這就是爲何Mahout將可擴展性做爲最高優先級,也是爲什麼本書關注可擴展性問題,別人所沒有涉獵的一種方式,用於有效處理海量數據。
複雜的機器學習技術,上規模的應用,直到目前爲止,只是一些大的、先進的技術公司在考慮。可是,今天計算能力已經比以前廉價,藉助像Hadoop這 樣的開源框架更方便。Mahout嘗試經過使用hadoop提供優質、開源實現,可以在這個規模上解決問題,解決這類困惑,而且將其送到全部技術組織的手 中。
1.5.1 MapReduce and Hadoop
Mahout的一些部分使用了Apachehadoop工程,hadoop是一個開源的、基於java的MapReduce(http://labs.google.com/papers/mapreduce.html ) 實現。MapReduce是一種分佈式計算框架,在Google內部使用。它是一種編程模式,開始聽起來感受很奇怪,或者太簡單了以致於很強大。MapReduce編程模式適用於輸入是key-value鍵值對集合的問題。「map」函數將這些鍵值對轉換爲中間鍵值對。「Reduce」函數經過某 種方式將同一個中間鍵的值合併到一塊兒併產出結果。實際上,不少問題能夠設計成MapReduce問題,或者他們的一個系列。而且這種模式很是易於並行化實 現:全部的處理過程都是獨立的,因此能夠劃分到不一樣機器上去。這裏再也不詳細敘述MapReduce,hadoop提供的教程(http://hadoop.apache.org/common/docs/current/mapred_tutorial.html )。
Hadoop實現了MapReduce模式,這是一個不小的壯舉,甚至讓MapReduce像聽起來那麼簡單。它管理輸入數據、中間鍵值對、輸 出數據的存儲。這些數據多是海量的,須要在多臺計算機上運行,而不僅是存儲在某一臺機器的本地。它管理不一樣機器之間的劃分、數據傳輸。它負責檢測、恢復單個機器失敗的狀況。理解了有不少工做在幕後進行可以幫助你準備使用Hadoop的相對複雜性。不僅是將它做爲類庫添加到你的工程中,它包含不少模塊,每個模塊都有若干類庫和獨立的服務器進程,可能運行在幾臺機器上。基於Hadoop的操做處理不簡單,但投入在可擴展的、分佈式實現可讓你在以後有很大的收穫:由於你的數據可能成倍的增加,這種可擴展的性質對你的應用來講是一種面向將來的方式。
稍後,本書將試着剪掉一些複雜性讓你很快熟悉hadoop,基於這一點,你能夠探索操做完整聚類的重點和細節,調整整個框架。由於這個須要大量計算能力的複雜框架變的愈來愈流行,因此一點都不奇怪,雲計算已經開始提供hadoop相關的支持。例如Amazon提供的Elastic MapReduce(http://aws.amazon.com/elasticmapreduce/ )是一種管理Hadoop集羣、提供計算能力、提供友好的接口的服務,可基於hadoop操做、監控大規模複雜任務。
1.6 安裝Mahout
你須要安裝不少工具,在你能「能夠在家裏玩」咱們後面章節提供的一些示例代碼以前。咱們假設你已經熟悉Java開發。
Mahout以及和它相關的框架都是基於Java的,所以是平臺無關的,你能夠在任何一臺安裝了JVM的機器上使用他。有時候,咱們須要給出許 多不一樣平臺的示例和介紹,特別地,命令行模式在windows腳本和FreeBSD tcsh腳本有一些不一樣。咱們使用命令行和與bash一塊兒的句法,是一種類Unix平臺的腳本。這是默認的在大部分Linux、 Mac OS X, 一些Unix變種和Cygwin(一種windows上的類Unix環境)。指望使用windows腳本的用戶極可能不方便。儘管如此,本書下面的介紹列 表對你來講應該能夠很容易的理解。
1.6.1 Java和IDE
你若是以前作過任何Java開發的工做,你的我的電腦上已經裝上Java了。注意Mahout須要使用Java6。若是有所疑慮,打開一個終端並鍵入java -version。若是報告不是以「1.6」開頭,你仍須要安裝Java6。
windows和Linux用戶能在 http://java.sun.com 找 到Java 6 JVM。蘋果公司爲Mac OS X 10.5 和 10.6提供Java 6 JVM。若是發現Java 6沒有被應用,在「/Applications/Utilities」打開「java perferences」。在這裏能夠選擇Java 6做爲默認選項。
大部分人能發如今IDE的幫助下,很是好編輯、編譯和運行這些示例;因此強烈推薦你使用IDE。Eclipse(http://www.eclipse.org)是很是經常使用、免費的一款JavaIDE,安裝配置Eclipse不在本書的講解範圍內,你能夠花點時間去熟悉它。NetBeans (http://netbeans.org/) 也是一款經常使用開源IDE。 IntelliJ IDEA (http://www.jetbrains.com/idea/index.html)是一款強大的、流行的IDE,它有一個免費的社區版本。
例如,IDEA能從現有的Mavan模型中直接建立一個新工程;在建立新工程的時候,經過指定Mahout源代碼的根目錄,它將用一種友好的組 織方式自動配置、展現整個工程。例如,丟掉整本書的源代碼 core/src/…,而後在IDE裏面運行,只須要一次點擊,依賴和編譯的細節都會自動搞定。這證實了使用IDE比人工編譯、運行容易不少。
1.6.2 安裝Maven
和其餘Apache工程同樣,Mahout的構建、發佈系統基於Maven(http://maven.apache.org)。Maven是一種命令行模式的管理代碼,打包發佈,生成文檔,發佈正式版本的工具。儘管它和Ant工具備一些相同之處,可是不一樣。Ant是一種靈活的、低級別的腳本語言,Maven是一種高級別的工具,其目標傾向於發佈管理。
由於Mahout使用maven,你應該先安裝maven。Mac OS X用戶會發現maven是默認安裝,若是沒有,安裝蘋果開發工具包。在命令行鍵入mvn –version。若是你能看到版本號,這個版本號最低2.2,那麼能夠繼續進行。不然,你須要安裝mavn的本地拷貝。
linux用戶能夠使用系統帶有的包管理系統能夠很是快的獲取最近的maven版本。另外,標準方式是下載二進制版本,將其解壓到/usr /local/maven,而後編輯bash配置文件~/.bashrc,添加一行exportPATH=/usr/local/maven/bin:$PATH。保證maven命令行一直有效。
若是你使用IDE,像Eclipse或者IntelliJ,他們已經集成了Maven。參考文檔它的文檔去了解如何將Maven整合。這將在IDE中使用Mahout變得簡單一些,由於IDE能夠根據那個Maven配置文件(pim.xml)配置、導入工程。
1.6.3 安裝Mahout
Mahout仍在開發過程當中,這本書寫的時候Mahout是0.4版本。能夠在這裏下載發佈版本和其餘介紹http://lucene.apache.org/mahout/releases.html 源文件能夠解壓到你電腦的任何地方。
由於Mahout的更新很頻繁,有規律的進行漏洞修復、功能改進,在實際使用過程當中,使用最新發布版本的軟件(或者使用svn上的最近的未發佈 代碼)可能對你的幫助更大,詳見http://lucene.apache.org/mahout/developer-resources.html)。將來的發行版本應該向後兼容本書的示例。
一旦你從svn或者發佈的歸檔文件中獲取了源代碼,在IDE中建立一個Mahout的新工程。這個對不一樣IDE是過程不一樣的,需根據如何完成建立的文檔細節區別對待。使用IDE的Maven整合用工程根目錄下的pom.xml導入Maven工程是很簡單的。
一旦配置完成,你能夠很容易的建立一個新的源代碼文件夾來管理下面章節提到的樣例代碼。隨着工程的配置完成,你應該能夠透明的編譯和運行代碼,不須要再作其餘工做。
1.6.4 安裝hadoop
本書後面的一些行爲,你須要在本機安裝hadoop。你不須要一個集羣去運行hadoop。配置hadoop不是很麻煩、繁瑣。不重複這個過 程,咱們直接指導你在hadoop官網行獲取hadoop 0.20.2版本的副本,http://hadoop.apache.org/common/releases.html,而後使用「僞分佈式」方式安裝 hadoop,詳見http://hadoop.apache.org/common/docs/current/quickstart.html。
1.7 總結
Mahout是一個年輕的、開源的、可擴展的,Apache的機器學習庫,本書是一本使用Mahout中的機器學習算法解決現實問題的使用指南。尤爲是,你能夠很快的探索推薦引擎、聚類、分類。若是你是一個機器學習領域的研究者,正在尋找一個實用指導、又或者你是這個領域的開發者,想從其餘從 業者處快速學習實用方法,本書是很是適合你的。
這些技術不只僅是路論:咱們已經注意到不少知名的推薦引擎、聚類、分類的樣例在現實世界中已經在應用:電子商務、郵件、視頻、圖片,更涉及大規模的機器學習算法。這些技術已經用來解決現實問題,甚至爲企業產生了價值 — 這些如今在Mahout中都是能夠觸及的。
咱們已經注意到不少時候這些技術時常伴隨着海量的數據 — 可擴展性是這個領域特別須要持續關注的。咱們首先來看一下MapReduce和hadoop,以及他們如何爲Mahout提供可擴展支持。
由於這是一本動手實踐的、實用書籍,咱們立刻開始使用Mahout。此刻,你應該已經安裝好了Mahout須要的工具而且立刻開始行動。由於這本書以實用爲主,因此將這些開幕詞收起來去見識一下Mahout的代碼吧。繼續讀下去。
第2章 推薦系統簡介
本章包含如下內容:
咱們天天都會對喜歡的、不喜歡的、甚至不關心的事情有不少觀點。這些事情每每發生的不知不覺。你在收音機上聽歌,由於它容易記住或者由於聽起來可怕而關注它 — 又或者根本不去關注它。一樣的事情有可能發生在T恤衫,色拉,髮型,滑雪勝地,面孔,電視節目。
儘管人們的愛好差別很大,但他們仍然遵循某種模式。人們傾向於喜歡一些事物,這些事物相似於他們本身喜歡的其餘事物。由於我喜歡培根-生菜-西 紅柿三明治,你可能猜到我可能也喜歡總彙三明治,相似於前者的帶有火雞肉的三明治。另外,人們傾向於喜歡興趣和他們類似的人所喜歡的事物。當一個朋友進入設計學校,發現幾乎周圍全部同窗都用一個蘋果電腦 — 不用吃驚,他已是一個終生的蘋果用戶。
這些模式能夠用來預測喜愛與否。若是將一個陌生人帶到你面前並問你,她是否喜歡指環王三部曲,你只能胡亂猜想了。可是,若是她告訴咱們她喜歡頭 兩部指環王,若是她不喜歡第3部,你會感到震驚。另外一種狀況,若是她說討厭指環或者問「什麼王?」,你能夠準確的猜想她對指環王不感興趣。
推薦系統是關於這些預測偏好模型的系統,而且使用他們爲你發現新的、趁心的事物。
2.1 推薦系統是什麼
你由於某種緣由從書架上拿起這本書。可能你看到它臨近其餘的你熟知的書,發現他們是有用的,想到書店是由於喜歡那些書的人也會喜歡這本書才把他們放到一塊兒。也可能你看到這本書在你同事的書架上,你和這個同事常常分享機器學習方面的知識,或者他直接將這本書推薦給你。
後面的章節探索了人們實現推薦系統的不少方法,發現新事物,固然有這些過程在Mahout軟件中是如何實現的。咱們已經提到一些策略:爲了發現你喜歡的items,你可能去尋找有相同興趣的人。另外一方面,你能夠由其餘人的明顯偏好計算出相似你喜歡的items的其餘items。這描述了兩大類推 薦系統算法:「user-based」和「item-based」推薦系統。
2.1.1 協同過濾 vs 基於內容的推薦
嚴格的講,上面章節提到例子是「協同過濾」 — 僅僅基於user和item關係的生產推薦系統。這些技術不須要item本身的屬性信息。在某種程度上,這是一個優勢,該推薦系統框架不須要關心「item」是書、主題公園、花、甚至人,由於他們的任何屬性都沒有做爲輸入數據。
有不少其餘的方法基於item的屬性,通常被稱之爲「基於內容」的推薦技術。例如,若是一個朋友推薦一本書給你,由於這是一本Manning出版的書,這個朋友喜歡其餘Manning的書,那麼你的這個朋友在作相似於基於內容推薦的事情。這種想法基於書籍的屬性:出版社。Mahout推薦框架沒 有直接實現這些技術,儘管它提供一些方法將item的屬性信息添加到計算中。基於這些,技術上稱前面的方法爲協同過濾框架。
這些技術沒有沒什麼問題;正相反,他們工做的很好。他們是特定領域的方法,可能很難有效地將他們整理到一個框架中。爲了創建一個基於內容的圖書 推薦系統,咱們須要決定書籍的哪些屬性對推薦系統是有意義的、做用多少程度 — 頁數、做者、出版社、顏色、字體。可是這些知識不能簡單的應用於別的領域;像圖書推薦的方法對披薩配料推薦是沒什麼幫助的。
基於這個緣由,Mahout沒有過多涉及這種類型的推薦。能夠將這些想法融入進來,但首要任務是Mahout提供些什麼。其中的一個樣例將在下 一個章節中講解,在那裏你將創建一個約會網站的推薦引擎。在介紹完Mahout基於協同過濾推薦的實現後,你有機會探索它和基於內容的推薦之間關係的細 節。
2.1.2 推薦系統成爲主流
如今,不少人已經看到了推薦系統在現實網站上的實現,像Amazon或者Netflix:基於瀏覽和交易歷史,頁面將產生一個認爲對你有吸引力 的商品列表。這類推薦引擎在上世紀九十年代已經出現,但直到如今它仍然是使用大型計算機的專門研究者的領域。由於這些技術已經變動加主流,對它們的需求在增長,開源實現的提供也是同樣。隨着理解的深刻和計算資源愈來愈廉價,推薦引擎變得愈來愈容易接近和普遍使用。
實際上,推薦技術不僅是爲用戶推薦DVD相似的東西。這種方法很是通用,能夠用來評估不少事物之間的關係的強弱。
在社區網絡中,一個推薦系統能夠爲用戶推薦用戶。
2.2 運行你的第一個推薦引擎
Mahout包含了一個推薦引擎 — 有不少類型,實際上都是源於傳統的user-based和item-based推薦系統。它還包含了基於「slope-one」技術的實現,一個新的、有 效的方法。你將會找到不少實驗性的、初步的的SVD(singular value decomposition)實現。下面的章節將從新看Mahout的內容。在這些章節中,你將看到數據展現、瀏覽可用的推薦算法,評價推薦系統的有效 性,針對特殊問題協調和定製推薦系統,最後看一下分佈式計算。
2.2.1 建立輸入數據
爲了探索Mahout中的推薦系統,最好從一個很小的示例入手。推薦系統的輸入是必要的 — 這些數據是推薦的基礎。由於很是熟悉的推薦系統引擎將item推薦給user,很容易的認爲偏好是user和item之間的聯繫 — 儘管前面提到了user和item能夠是任何事物。偏好包含了一個user ID和一個item ID,一般狀況下,一個數值表明了user對item偏好的強度。Mahout中ID都是數值,其實是整數。偏好值能夠是任何值,值越大表明這正向偏好 越大。例如,這些值多是1到5的打分,user將1給於他不喜歡的,5給他很喜歡的。
建立一個文本文件包含用戶數據,命名爲「1」到「5」,他們對四本書的偏好,簡單的稱之爲「101」到「104」。在現實狀況中,這些多是公 司數據庫中消費者ID和產品ID;Mahout並不須要user和item的ID必定爲數值類型。使用下面的格式,生成文件intro.csv。
1,101,5.0
1,102,3.0
1,103,2.5
2,101,2.0
2,102,2.5
2,103,5.0
2,104,2.0
3,101,2.5
3,104,4.0
3,105,4.5
3,107,5.0
4,101,5.0
4,103,3.0
4,104,4.5
4,106,4.0
5,101,4.0
5,102,3.0
5,103,2.0
5,104,4.0
5,105,3.5
5,106,4.0
通過一些學習以後,趨勢就顯現出來了。用戶1和用戶5具備相同的興趣。他們都喜歡101這本書,對102的喜歡弱一些,對103的喜歡更弱。同理,用戶1和4具備相同的興趣,他們都喜歡101和103,沒有信息顯示用戶4喜歡102。另外一方面,用戶1和用戶2的興趣好像正好相反,用戶1喜歡 101,但用戶2討厭101,用戶1喜歡103而用戶2正好相反。用戶1和3的交集不多,只有101這本書顯示了他們的興趣。看圖2.1可能顯現了 user和item之間的關係,多是正的也多是負的。
2.2.2 建立推薦系統
那麼你應該給用戶1推薦哪本書?不是101, 102或者103,由於用戶已經知道本身對他們感興趣,推薦系統須要發現新的事物。直覺告訴咱們,用戶四、5與用戶1相似,因此推薦一些用戶4和5喜歡的 書籍給用戶1多是不錯的。這樣使得10四、105和106成爲可能的推薦。總體上看,104是最有可能的一個推薦,這基於item 104的4.5和4.0的偏好打分。如今運行下面的代碼:
Listing 2.2 a simple user-based recommender program withmahout 代碼
A 加載數據文件
B 建立推薦系統引擎Createthe recommender engine
C 對user1, 推薦一個item
爲了簡潔,後面許多其餘章節的示例中,代碼列表將省略imports、類聲明、方法聲明,只是重複程序語句。爲展現很好的展現各個模塊之間的關係,請看圖2.2。並非Mahout中全部的推薦都是這樣的,但這幅圖能夠給你一個樣例的邏輯的初步印象。
接下來兩章,在更細節的討論這些模塊以前,咱們能夠總結一下每一個模塊所扮演的角色。DataModel存儲了全部的偏好信息,提供了對user 和item信息的訪問。UserSimiliarity提供了兩個用戶如何類似的概念,這可能基於不少可能的矩陣和計算之一。 UserNeighborhood定義了一個給定用戶的用戶組的概念。最終,一個推薦系統將這些模塊組合在一塊兒將items推薦給users和相關功能。
2.2.3 分析輸出
使用你細化的IDE編譯運行,運行程序的輸出應該是:RecommendedItem[item:104,value:4.257081]
請求一個推薦結果並獲得一個。推薦系統引擎將書104推薦給用戶1。甚至,這樣作是由於推薦系統引擎將用戶1對書104的偏好是4.3,這是全部推薦結果的最高打分。
這個結果並不算壞。107沒有出現,本應該也是能夠推薦的,但它只是和另外一個具備不一樣愛好的user相關聯。選104而不是106,由於104的打分高一些。還有,輸出結果包含了一個用戶1喜歡104的評估值 — 是介於用戶4和5所表示的介於4.0和4.5的一個值。
直接看數據正確的結果並不明顯,可是推薦系統引擎推薦了一個得體的結果。若是對從這個簡單程序給出的有用並不明顯的結果感到有一種愉快的刺痛,那麼機器學習的世界是適合你的。
小數據集、產生推薦結果是一件微不足道的事情。現實中,數據集很大,而且噪聲數據不少。例如,想象一個新聞網站推薦新聞給用戶。偏好從文章的點 擊中獲取。可是,這裏面的不少點擊都是僞造的 — 可能不少讀者點擊一篇文章但他不必定喜歡它,或者點錯了。可能不少點擊都是在未登陸的時候發生的,不能將其關聯到一個用戶。想象一下數據集有多大,多是每個月幾十億的點擊量。
要從數據集產生正確的推薦結果並快速計算出是一件不通常的事情。稍後咱們將展現工具Mahout如何解決這些問題。他將展現標準方法如何產生差的推薦結果或者佔用了大量的cpu和內存時間,如何配置Mahout以提高性能。
2.3 評價推薦系統
推薦系統引擎是一個工具,一種回答問題的手段,「對用戶來說什麼是最好的推薦?」,在研究回答的前先研究一下這個問題。一個好的推薦的準確含義是什麼?如何知道推薦系統是如何生成推薦的?下面的章節將探索推薦系統的評價,在尋找特定推薦系統時,這將是一個有用的工具。
最好的推薦系統是心理學的範疇,有人在你作事情以前知道確切的知道你尚未看過的、或者沒有任何現象說明你喜歡的一些item,以及你對這些item的喜歡程度。
大部分的推薦引擎經過給item評價打分來實現。因此,評價推薦引擎的一種方式是評價它的評估偏好值的質量 — 評價評估偏好和實際偏好的匹配度。
2.3.1 訓練集和打分
「真實偏好」並不充分,沒有人會知道你未來是否會喜歡一些新的item。推薦引擎能夠經過設置一部分真實數據做爲測試數據。這些測試數據偏好在訓練集中並不展現偏好值 — 要求推薦系統對這些缺乏偏好值的數據做出評估,並比較和實際值的差距。
對於推薦系統產生一系列打分是很簡單的。例如,計算評估值和實際值之間的平均距離,在這種方法下,分值越低越好。0.0表示很是好的評估 — 評估值和實際值根本沒有差距。
均方根(root-mean-square)也是一種方法,也是分值越低越好。
上面的表中展現了實際偏好度和評估偏好度集合的不一樣值,以及如何將它們轉化爲打分。均方根能比較重的處罰距離遠的,例如item2,這是基於某種考慮在內的。由於平均距離容易理解,接下來的示例將使用它做爲評估方法。
2.3.1 運行RecommenderEvaluator
下面是代碼示例:
大部分的操做發生在evaluate()這個方法中。內部,RecommenderEvaluator將數據劃分爲訓練集和測試集,建立一個新的訓練DataModel和推薦引擎測試,比價評估結果和實際結果。
注意,沒有將Recommender傳給方法,這是由於在其內部,將基於建立的訓練集的DataModel建立一個Recommender。因此調用者必須提供一個RecommenderBuilder對象用於從DataModel建立Recommender。
2.3.3 評估結果
程序打印出了評估結果:一個代表推薦系統表現如何的打分。在這種狀況下你能看到很簡單的1.0。儘管評價器內部有不少隨機方法去選擇測試數據,結果多是一致的由於RandomUtils.useTestSeed()的使用,每次選取的隨機數都同樣。這隻用於示例、單元測試來保證重複的結果。不要在真是數據上用它。
AverageAbsoluteDifferenceRecommenderEvaluator
基於AverageAbsoluteDifferenceRecommenderEvaluator實現,獲得的這個值是什麼含義?1.0意味着,平均意義上,推薦系統評估偏好和實際偏好的的距離是1.0.
1.0早1-5規模上並不大,可是咱們的數據太少。若是數據集被隨機劃分結果可能不同,所以訓練、測試數據集可能每次跑都不同。
這種技術能夠應用於任何Recommender和DataModel。使用均方根打分的實現類RMSRecommenderEvaluator
替代AverageAbsoluteDifferenceRecommenderEvaluator。
evaluate()的null參數是DataModelBuilder的實例,用於控制訓練DataModel是如何從訓練數據上創建的。正常狀況下默認就好,若是須要,能夠使用特別實現的DataModel。DataModelBuilder用於將DataModel注入評價過程當中。
參數1.0表示使用整個數據集的比例。這樣用於產生一個很快的、可能精度低一些的評價方式。例如,0.1可能意味着用數據集的10%,忽略其餘90%。這對於快速檢測到Recommender的細微變化是很是有用的。
2.4 評估準確率和召回率
借用更廣泛的見解,咱們接收經典的信息檢索矩陣去評價推薦系統:準確率和召回率。這些是用於搜索引擎的術語,經過query從衆多可能結果中返回最好結果集。
一個搜索引擎不該該在靠前的結果中返回不相關的搜索結果,即便他致力於獲得儘量多的相關結果。」準確率」是指在靠前的結果中相關結果所佔的比 例,固然這種相關是某種程度上咱們定義的相關。」precisionat 10″應該是從前10個結果中判斷獲得的準確率。「召回率」靠前的結果中相關結果佔的比例。看圖2.3能夠有一些直觀的概念。
這些術語也能夠應用到推薦系統中:準確率是靠前的推薦中好的推薦所佔的比例,召回率是指出如今靠前推薦中好的推薦佔整個好的推薦的比例。
2.4.1 運行RecommenderIRStatsEvaluator
Mahout提供了很是簡單的方式爲推薦系統計算結果。
2.5 評價GroupLen數據集
有了這些工具在手,咱們不只能夠考慮速度,還要考慮推薦系統的效率。儘管大量數據集的例子還在幾章之後,小數據集上評價性能已成爲可能。
2.5.1 抽取推薦系統輸入
GroupLens (http://grouplens.org/)是一個研究型的項目。提供了不少不一樣大小的數據集。每一個都是用戶對電影打分的真實數據。這是幾個大的真實可用數據集之一,更多的將會在本書後續探尋。從GroupLens網站上下載「100K data set」,http://www.grouplens.org/node/73.解壓下載文件,在解壓後後,有一個叫ua.base的文件。該件tab分割user IDs, itemIDs, ratings(偏好值)和其餘信息。
這個文件能使用嗎?Tabs, 不是逗號,分隔字段,在每行結尾還有一個額外的字段。答案是確定的。該文件能夠相似FileDataModel的讀取。回到前面列表2.3,試着用 ua.base的路徑代替小文件路徑。從新跑一遍數據。這時,評估可能須要幾分鐘,由於數據量是100k。
最後,你應該獲得一個大約0.9的值。這不算壞,儘管值幾乎分佈在1-5區間內,聽起來還不錯。可能特殊的推薦系統對這種類型的數據來說是不徹底的?
2.5.2 其餘推薦系統實驗
在這個數據集上測試「slope-one」 ,一個簡單的算法,在後面的章節中會講到。很容易替換RecommenderBuilder,使用org.apache.mahout.cf.taste.impl.recommender.slopeone.SlopeOneRecommeder, 像這樣:
運行評價方法。你應該發現它很快,獲得一個大約是0.748的值。正朝好的方向發展。
這並不能說明slope-one算法老是很快、很好。在給定數據集上,每個算法都有本身的特性和屬性,這些屬性很難去檢測出來。例如,slope-one算法運行時可以很快的計算推薦過程,可是它須要在計算前須要花費很大一部分時間構建內部數據結構。基於用戶的推薦引擎,可以在其餘數據集上擁有很快的計算速度和更高的準確度,咱們將在第四章探索各類算法的優勢。
2.6 總結
在這一章咱們介紹了推薦引擎的思想。咱們建立了一些簡單的Mahout Recommender的輸入,運行一個簡單計算,而後輸出結果。
而後,咱們花時間介紹了推薦引擎系統的數據結果的質量評價,由於接下來的章節會頻繁用到。這一章包含了評價推薦引擎的準確性,像傳統的準確性和召回率。最後,咱們嘗試去評價GroupLens的真實數據集,觀察如何將評價結果用於推薦引擎的性能提高上。
在咱們繼續詳細學推薦引擎以前,須要花一些時間去了解另外一個Mahout中推薦系統的基本概念:數據表示。接下來一章會着重講這一點。
這章主要講述:
。Mahout如何展示recommender data
。DataModel的實現及其用法
。沒有評分數據
Recommendations的質量主要是由數據的數量和質量決定的。「無用輸出,無用輸入」 在這裏是最真實的。一樣,推薦器算法都是集中數據,運行的性能主要受數據的數量和展示的影響。這一章介紹Mahout的一些關鍵class,和訪問推薦器相關的數據。
mahoutin action 3.1 Preference對象
一個推薦引擎的輸入數據是評分數據:它喜歡什麼以及多少。因此,Mahout recommenders的輸入數據是一組簡單的「userID」,「itemID」,和「評分數據」元組,固然,這是一個大的集合。評分數據有時候會被省略。
3.1.1Preference對象
Preference 是一個最基礎的概念,它表現一個單一的userID,itemID和一個評分數據。這個對象表現爲一個用戶對一個項目的打分。Preference是一個 接口,一般使用的實現類爲GenericPreference。例如:建立一條記錄,user(123),對item(456)的打分是3.0: newGenericPreference(123, 456, 3.0f)。
一組Preferences如何表現?若是你給出了一個合 理的答案,如Collection<Preference>或者 Preference[],大部分狀況下,在MahoutAPIs中不是這樣實現的。Collections和arrays對處理海量Preference對象是無效的。若是你在Java中從未研究過上面的對 象,你可能會感到困惑!
單個的GenericPreference包含20個字節的有用數據:一個8字節的user ID(Java long),8字節的item ID(long),4字節的分值(float)。這個對象的存在使GenericPreference包含的字節有驚人的增加:28個字節!這個變化依賴的是JVM的實現;這個數字是從蘋果Mac OS X 10.6的64位Java 6 VM 獲得的。因爲上面的對象和其餘線性問題,對這個對象來講,28個字節中包括8字節的參考值,另外20個字節的空格,在對象自身的表現內。因爲上面的現象,所以一個GenericPreference對象已經比它須要多消耗了140%的存儲。
爲何這麼作?在recommender算法中,都須要全部評分數據的集合,這些評分數據是與一個用戶或一個項目聯繫在一塊兒的。在這樣一個集合裏,user ID或者item ID與全部好像多餘的Preference對象將會是配套的。
3.1.2PreferenceArray和實現
進 入PreferenceArray,這個接口的實現表現爲一個具備相似與數組的API的分值的集合。例 如,GenericUserPreferenceArray表現爲一個用戶的全部打分.它在內部包括一個單一的user ID,一系列的item IDs,一系列的評分值。在一個用戶的全部打分中,須要佔用12個字節的內存(一個8字節的item ID和一個4字節的評分值)。把它與須要一個完整的Preference項目的大約48個字節相比較。這個4字節內存,包括對齊這個特殊的實現,
但它也提供了小的性能提高,更小的對象必須被垃圾回收器分配和檢查。比較圖3.1 and 3.2去理解這些保存是如何完成的。
圖3.1效率較低的評分值的表現,利用一系列的Preference對象。灰色的區域表明上面的對象。白色的區域是數據,它包括引用對象。
圖3.2利用GenericUserPreferenceArray更有效的表現
下面的代碼表現一個PreferenceArray的典型的構造和使用
列表3.1在一個PreferenceArray中設置評分值
Java代碼:
PreferenceArray user1Prefs = newGenericUserPreferenceArray(2);
user1Prefs.setUserID(0, 1L); //A
user1Prefs.setItemID(0, 101L);
user1Prefs.setValue(0, 2.0f); //B
user1Prefs.setItemID(1, 102L);
user1Prefs.setValue(1, 3.0f); //C
Preference pref = user1Prefs.get(1); //D
PreferenceArray user1Prefs = newGenericUserPreferenceArray(2);
user1Prefs.setUserID(0, 1L); //A
user1Prefs.setItemID(0, 101L);
user1Prefs.setValue(0, 2.0f); //B
user1Prefs.setItemID(1, 102L);
user1Prefs.setValue(1, 3.0f); //C
Preference pref = user1Prefs.get(1); //D
A 爲全部打分設置user ID
B User 1當前爲item 101的打分2.0
C User 1爲item 102的打分3.0
D Item 102的一個Preference實現
一樣這裏存在一個稱爲GenericItemPreferenceArray的實現,它內部的全部分值,與item關聯而不是與user關聯。它的目的和用法都是徹底相似的。
mahoutin action 3.2 加速彙集
很是高興的是,Mahout已經從新創造了「java數組對象」。這只是萬里長征的第一步。咱們說起到規模是重要的嗎?可能,你已經被說服,咱們將會面對處理巨大數量的數據,和不尋常響應。
這 個reduced的內存需求,由PreferenceArray和它的實現,帶來的複雜性是值得的。削減內存需求的百分之七十五不僅是節約一對M字節。在 一個合理的規模上,它節約了10分之一G內存。這多是在你現存的硬盤上是否裝配之間的不一樣。這是是否必須投資大量的RAM和可能的一個新的64-bit 系統之間的不一樣。那是一個小的,但真正節能的技術,很是重要。
3.2.1FastByIDMap 和 FastIDSet
當 你聽到Mahout recommenders大量的使用如map和set的典型的數據結構時將不會感到奇怪,可是不要使用如TreeSet和HashMap的普通的Java實現。相反,遍歷這個實現和API你將會找到FastByIDMap和FastIDSet。它們是像Map和set同樣的程序,可是是被明確的詳細說明,並只提供Mahout recommenders須要的程序。它們減小內存佔用而不是在性能上顯著的增長。
這裏沒有一個像java中的Collections。可是,它們在一個大範圍的環境內,爲有效的目的而精心設計。它們不能對將來的使用作出更多的假設。Mahout的須要對可獲得的用法有更加特殊,更強的假設。主要不一樣是:
。如同HashMap,FastByIDMap 是 hash-based。它使用線性探索而不是分離連接來處理hash collisions。這避免了一個額外的Map.Entry對象的每一個入口的須要;如咱們所討論的,Objects佔用了使人驚奇的內存數量。
。Keys和members在Mahout recommenders中老是長的基元,而在objects中則不是。使用長的keys節約內存並提升性能。
。Set的實現不是使用下面的一個Map來實現的。
。FastByIDMap能夠像一個cache同樣起做用,由於它有一個「maximum size」的概念;超過這個尺寸,當增長了新的entries時,infrequently-used entries將會被刪除。
存 儲的不一樣是有意義的:與HashSet 的84個字節相比,FastIDSet平均每一個member須要大約14個字節。與HashMap 的每一個入口的84個字節再次比較,FastByIDMap每一個入口占用28個字節。這顯示當一我的對用法作了更強的假設時,有意義的改善是可能的:主要在 內存需求上。考慮到爲recommender系統提供的討論中的數據量,這些習慣的實現不只僅證實了它本身。因此,這些類用在哪裏?
mahoutin action 3.3 內存中的DataModel
這 是個抽象概念,在Mahout中,recommender的輸入數據是DataModel。DataModel的實現爲各類推薦器算法須要的數據提供了有效的使用。例如,一個DataModel能夠在輸入數據中,提供一個包括全部userIDs的列表,或提供與一個item相關聯的全部分值,或者提供一個爲一系列item IDs打分的全部用戶的列表。咱們將會集中研究一些highlights;一個關於DataModel的API的更詳細的描述,能夠經過在線文檔中找到。
3.3.1GenericDataModel
這個咱們先來看一下,最簡單 的實現(在內存中實現),GenericDataModel。當你想用編程的方法,而不是基於一個現存的外部數據資源。例如一個文件或相關數據庫在內存中建立你的數據表現時,這是很是合適的。它只是以這種形式把分值看成輸入數據,這個形式就是一個FastByIDMap映射user IDs到有這些用戶的數據的PreferenceArrays上。
列表3.2 基於GenericDataModel,定義輸入數據
Java代碼
FastByIDMap<PreferenceArray> preferences =
new FastByIDMap<PreferenceArray>();
PreferenceArray prefsForUser1 = new GenericUserPreferenceArray(10);//A
prefsForUser1.setUserID(0, 1L);
prefsForUser1.setItemID(0, 101L); //B
prefsForUser1.setValue(0, 3.0f); //B
prefsForUser1.setItemID(1, 102L);
prefsForUser1.setValue(1, 4.5f);
… (8 more)
preferences.put(1L, prefsForUser1);// C
DataModel model = new GenericDataModel(preferences); //D
FastByIDMap<PreferenceArray> preferences =
new FastByIDMap<PreferenceArray>();
PreferenceArray prefsForUser1 = new GenericUserPreferenceArray(10); //A
prefsForUser1.setUserID(0, 1L);
prefsForUser1.setItemID(0, 101L); //B
prefsForUser1.setValue(0, 3.0f); //B
prefsForUser1.setItemID(1, 102L);
prefsForUser1.setValue(1, 4.5f);
… (8 more)
preferences.put(1L, prefsForUser1);// C
DataModel model = new GenericDataModel(preferences); //D
A爲user 1創建PreferenceArray
B添加第一個preference,在剛剛建立的10中
C把user 1的preference添加到輸入數據上
D建立DataModel
一 個GenericDataModel使用多少內存?儲存的分值的數目佔內存佔用的絕對優點。經過一些經驗揭示,每一preference佔用28個字節的Java heap space 。它包括全部的數據和其餘次要數據結構--如指數。若是你喜歡你也能夠嘗試一下;下載一個GenericDataModel,調用 System.gc() ,幾回後,比較Runtime.totalMemory()和Runtime.freeMemory()的結構。這是未加工過的,但應該能夠給出一個合理 的估計,這個估計就是數據佔有多少內存。
3.3.2 基於文件的數據
一般咱們不會直接地使用GenericDataModel,而是可能使用FileDataModel: FileDataModel從一個文件中讀取數據,並能夠在內存中儲存做爲結果的分值數據,從而轉化爲GenericDataModel。
幾 乎任何一個合理的文件都將會這麼作。咱們在第一節裏已經看到了一個這樣文件的例子,在這節裏,咱們創造了一個簡單的用逗號分割數據的文件,在這個文件裏, 每一行都包含一個數據:user ID,item ID,分值。使用Tab分割的文件也一樣這麼作。若是它們的名字各自以「.zip」 或「.gz」爲後綴,使用對應的zip和gzip解壓。在壓縮格式儲存這一數據是一個好想法,由於它是巨大的,而且被壓縮好的。
3.3.3Refreshable組件
有時推薦引擎中呈現偏好值爲空的記錄。它表明了用戶和項目是接洽關係的,然則並無發揮解析出接洽關係程度。舉了例子,一個消息網站按 照用戶已瀏覽內容爲用戶推薦消息。「已瀏覽」使一個用戶和一個項目產生了接洽關係,然而這是獨一能夠或許獲取的信息。通常網站也不會讓用戶去給文章作個排序,更不會讓用戶再作除了瀏覽以外的其餘什麼事了。因此咱們僅僅知道用戶和那些文章接洽關係了,而再也沒有其餘的內容了。
面對如許的景象,咱們別無選擇。這裏不會有偏好值。後續幾章將會依然供給處理懲罰如此景象的技巧和建議。然而有時咱們忽視掉偏好值也何嘗不是壞事,只要景象需要。
丟掉用戶和項目之間的接洽很輕易,或者說咱們能夠直接忽視偏好值就能夠辦到。好比,你寧肯推敲有沒有看過一個電影,也不願去給一個電影 打分。換句話說,咱們寧可把數據改成「用戶1和項目3有關係」,也不願意寫成「用戶1喜愛項目103的程度爲4.5」。下面是一個示意圖,來申明兩者之間 的差異:
圖3.4 帶偏好值的數據(左)與布爾偏好數據(有)的差異
用Mahout的說話,沒有不帶偏好值的記錄就是布爾偏好,由於一個接洽關係只有兩種值:要麼有接洽關係,要麼沒接洽關係。這不表明偏好只有兩個值:是和否,而是有三個:喜愛、不喜愛、不知道。
爲什麼有時會忽視偏好值?由於會有如許的景象,用戶喜愛或者不喜愛一個項目標程度相對一致,至少與那些和用戶沒有接洽關係的項目比擬。還 記得那個例子嗎?一個傢伙不喜愛拉赫瑪尼諾夫(Rachmaninoff),固然世上有不少曲子他沒有聽過(好比滅亡金屬音樂(Norwegiandeath metal))。如許咱們只得到了他與這個做家的一個接洽關係,剛巧他又喜愛另外一個做家布拉姆斯,而後他把拉赫瑪尼諾夫標爲1,把布拉姆斯標爲5,和其他 未知做家比擬,如許的偏好值是沒有什麼意義的,認爲兩者在某種程度上是對等的。因此咱們索性不要這個偏好值,僅僅是喜愛、不喜愛、不知道或者說未知的關係。
你可能會說這都是用戶的錯。莫非他就不克不及爲拉赫瑪尼諾夫打4分而爲滅亡金屬打1分。也允許以,但你仍是認了吧!由於事實上推薦所須 要輸入的數據是很難判定的。你或許還要提出否決,當然對於全部流派均可以如許去推理,然則當你要向他推薦古典做曲家時該根據哪些數據呢?沒錯,在某範疇中的好的解決計齊截般不會公開出來。
拋去偏好值能夠很大程度上化簡數據表達,固然也會提拔機能、佔用更少的內存。像看我以前懂得的,在Mahout中需要用4個字節的浮點 數去存儲偏好值,至少如果沒有偏好值也就意味着咱們每一條會罕用4個字節。在內存方面的測試中也確切均勻每筆記錄都削減了4個字節到24字節了。
這個測試用的是GenericDataModel的雙胞胎兄弟GenericBooleanPrefDataModel。它看上去是一個內存版的實現,然則它沒有偏好值。事實上,它僅僅用FastIDSets去存儲一個用戶和項目標接洽關係。例如,只爲每一個用戶存儲和他接洽關係的全部項目ID,這裏不會再呈現偏好值。
由於GenericBooleanPrefDataModel也是DataModel對象,因此它徹底能夠直接庖代 GenericDataModel。一些數據模型的辦法在這種實現下會變得快速高效,好比:getItemIDsForUser(),由於該辦法在它裏面取項目ID是現成的。某些辦法也會變慢,好比:getPreferencesFromUser(),由於它的實現沒有應用 PreferenceArrays,而且必須實現如下該辦法。
你可能會好奇getPreferenceValue()在這裏能夠返回什麼?由於這裏不是沒有偏好值嗎?你調用該辦法並不會拋出 UnsupportedOperationException的異常,它會恆定的返回一個子虛值1.0。這一點值得重視,每一個組件都邑依附於一個偏好值, 它們必須從DataModel對象中獲取一個。這些捏造而且固定的值也會產生一些奧妙的題目。
讓咱們在文章最後來調查一下GroupLens例子的成果。下面是應用了GenericBooleanPrefDataModel的代碼片斷:
清單 3.7 用布爾偏好值建立和評估一個推薦器
DataModel model = newGenericBooleanPrefDataModel(
GenericBooleanPrefDataModel.toDataMap(
new FileDataModel(newFile("ua.base")))); A
RecommenderEvaluator evaluator =
newAverageAbsoluteDifferenceRecommenderEvaluator();
RecommenderBuilder recommenderBuilder = newRecommenderBuilder() {
public Recommender buildRecommender(DataModel model)
throws TasteException {
UserSimilarity similarity = newPearsonCorrelationSimilarity(model);
UserNeighborhood neighborhood =
new NearestNUserNeighborhood(10, similarity,model);
return
new GenericUserBasedRecommender(model, neighborhood,similarity);
}
};
DataModelBuilder modelBuilder = newDataModelBuilder() {
public DataModel buildDataModel(
FastByIDMap<PreferenceArray>trainingData) {
return new GenericBooleanPrefDataModel(
GenericBooleanPrefDataModel.toDataMap(trainingData)); B
}
};
double score = evaluator.evaluate(
recommenderBuilder,modelBuilder, model, 0.9, 1.0);
System.out.println(score);
A 基於雷同的數據,應用GenericBooleanPrefDataModel
B 建樹一個GenericBooleanPrefDataModel
這裏的轉折是DataModelBuilder。它能夠使評估法度爲練習數據機關DataModel對象,而不是去機關一個 GenericDataModel對象。GenericBooleanPrefDataModel用一種稍微不合的體式格式去獲取數據——用一些 FastIDSets而不是PreferenceArrays。而且它還供給了一個很便利的辦法toDataMap()用來對兩者進行轉換。在進入下一末 節時,測驗測驗運行一下這個法度,他將不會很成功的履行完畢。
你會發明在PearsonCorrelationSimilarity的機關辦法中拋出了 IllegalArgumentException。剛開端你可能感受很不成思議,GenericBooleanPrefDataModel莫非不也是 DataModel對象嗎?它與GenericDataModel的獨一差異不就是沒有偏好值嗎?
這個相似度懷抱對象EuclideanDistanceSimilarity拒絕在沒有偏好值的景象下工做,由於如許產生的成果是無心義的。皮爾森相干係數(Pearson correlation)在兩個數據集數據徹底反覆、同樣時就是沒有意義的。在這裏DataModel的偏好值所有爲1.0,那麼策畫出來的歐幾里得間隔 只能在一個點空間(1.0, 1.0, …, 1.0)中進行,如許是毫無心義的,由於全部的相似度都是0。
大致上講,不是全部的實現均可以在一路很好的匹配在一路,甚至都實現自一個接口的對象也不成能徹底匹配。爲懂得決這個當前題目,咱們須 要調換掉這個策畫相似度的類。LogLikelihoodSimilarity就是一個好的選擇,由於它不需要偏好值,咱們將即速評論辯論它。在法度頂用 它調換PearsonCorrelationSimilarity,這個成果就變成了0.0。很不錯吧!這意味着它的成果正確了,不過這真的很好嗎?
不幸的是,全部的偏好值都是1固然會致使全部的偏好相差爲0了。這個測試自己沒有什麼意義,由於它將永遠都是0。
然而,查準-召回評估仍是依然有效的,讓咱們來試一下吧:
清單3.8 應用布爾數據評估查準率和召回率
DataModel model = newGenericBooleanPrefDataModel(
new FileDataModel(newFile("ua.base")));
RecommenderIRStatsEvaluator evaluator =
new GenericRecommenderIRStatsEvaluator();
RecommenderBuilder recommenderBuilder = newRecommenderBuilder() {
@Override
public Recommender buildRecommender(DataModel model) {
UserSimilarity similarity = newLogLikelihoodSimilarity(model);
UserNeighborhood neighborhood =
new NearestNUserNeighborhood(10, similarity,model);
return newGenericBooleanPrefUserBasedRecommender( model, neighborhood, similarity);
}
};
DataModelBuilder modelBuilder = newDataModelBuilder() {
@Override
public DataModel buildDataModel(FastByIDMap<PreferenceArray> trainingData) {
return new GenericBooleanPrefDataModel(
GenericBooleanPrefDataModel.toDataMap(trainingData));
}
};
IRStatistics stats = evaluator.evaluate(
recommenderBuilder,modelBuilder, model, null, 10,
GenericRecommenderIRStatsEvaluator.CHOOSE_THRESHOLD, 1.0);
System.out.println(stats.getPrecision());
System.out.println(stats.getRecall());
評估成果爲查準率和召回率均爲15.5%,這個成果並不睬想。這意味着推薦成果中6個只有1個是好的推薦,6個好的推薦中只推薦出了1個。
這引出了第三個題目,偏好值依然埋伏於GenericUserBasedRecommender對象之中。由於推薦成果遵照偏好值排序,而偏好值盡是1.0,因此如許的次序是徹底隨機的。因此咱們引出GenericBooleanPrefUserBasedRecommender(是的,正如它名字同樣,它能夠辦到)。它能夠在推薦成果中產生一個頗有意義的排序。它爲每一個項目接洽關係於其餘相似的用戶加權重,用戶越相似,那麼權重也會 越高。它沒有供給一個加權均勻數。調換以後在運行代碼,成果可能在18%,好了一點,但沒有好太多。這種成果預示着推薦體系對於這些數據不是非常有效,我 們的目標不是要去批改它,僅僅是去看如安在Mahout中有效的安排如許帶有「布爾偏好」的數據。
其餘DataModel對象的布爾變種也是有的。FileDataModel在記錄中沒有偏好值的景象下內部會主動的應用一個 GenericBooleanPrefDataModel的對象。相似的,MySQLBooleanPrefDataModel適實用在數據庫中無偏好值的景象。它與以前的對象徹底相似,而且它的實現能夠充沛的哄騙數據庫供給的某些捷徑來提拔自身的機能。
最後,你如果好奇布爾型和非布爾型是否是能夠混在一路處理懲罰,答案是否認的。在這種景象下,咱們更偏向於遵照存在偏好值的景象去向理 懲罰,由於畢竟成果有些偏好值是存在的。那些沒有偏好值的記錄可能或者應當能夠經由過程某些手段揣摩出它的偏好值,甚至咱們能夠吧均勻偏好值填進去當作一個佔位符。
這一章咱們看到了數據在Mahout的推薦器中如何去表達、浮現。這裏包含了Preference對象,酷似湊集實現的特別數組PreferenceArray以及FastByIDMap。這些特定定製的對象很大程度上削減了內存的消費。
再看看DataModel,它是推薦器輸入數據的一種抽象封裝。在FileDataModel讀取完本地文件以後,GenericDataModel在內存中存儲這些數據。JDBCDataModel用來接見數據庫的數據,而且咱們還在MySQL上特意進行了測試。
最後咱們評論辯論了在無偏好值的景象下,這些模型該如何的變動。通常上述這些對象都邑用到,固然存儲上會稍微少一些。咱們列舉了一些標 準對象與該類數據不匹配的例子,如PearsonCorrelationSimilarity。最後經由過程檢查題目的緣由地點而解決了題目,目標是爲了 構建一個基於布爾偏好數據的推薦器。
本章概述:
分析維基百科上的一個大數據集
利用Hadoop和分佈式計算產生推薦結果
僞分佈式上存在的非分佈式推薦
本書着眼於持續增加的數據集,從10條到100,000再到1千萬再到1.7千萬。不過這依然是中等大小的推薦系統所處理的 數據。本章依然放手一搏,處理了來自維基百科語料庫中的1.3億條數據,這些數據主要是以文章對文章的鏈接形式存在的。在這些數據集中,文章既充當了用 戶,也充當了項目。這也顯示了Mahout在特定情形下十分靈活的應用。
爲知足演示目的,1.3億的數據仍是可管理的。可是對於單機處理推薦過程仍是有一些困難的。這就須要使用一種新的推薦算法,經過Mahout基於的Mapreduce範式與Hadoop來實現分佈式計算。
咱們首先要檢測一下維基百科的數據來認識一下它對於分佈式推薦計算意味着什麼。你將會學習到如何在分佈式的環境下設計一個推 薦器,由於這與非分佈式的推薦計算有很大的不一樣。你也將看到Mahout如何把以前的算法設計翻譯成基於MapReduce和Hadoop的實現。最後, 你將運行一個完整的基於Hadoop的推薦Job程序。
咱們從分析維基的數據開始,可是很快咱們會發現因爲問題規模而引發的問題。咱們將很快退後幾步去深刻了解下分佈式計算是如何執行的。
維基是一個由用戶編寫和維護的在線百科全書。據報道,在2010年它已經包含320萬篇英文文章了。維基文章提取的開源項目(http://download.freebase.com/wex/)估計全部維基文章大概有42GB。基於互聯網,維基文章能夠相互連接。這些連接表明了某種興趣。能夠作個比方,一篇文章像是用戶同樣「喜歡」另外一篇文章做爲其偏好的項目。
幸運的是咱們無需下載上述項目所提取的文章也不須要去分析出它們之間的連接。研究人員Henry Haselgrove已經在http://users.on.net/~henry/home/wikipedia.htm上發表了他所完成的提取信息。另外,還有一些深刻的提取,例如文章的討論頁、圖片等等。這些數據採用數字ID而不是文章的標題,這樣很是有好處,由於Mahout自己就是使用數字ID的。
在往下繼續以前,先下載並解壓links-simple-sorted.zip,其中包含5,706,070篇文檔對 3,773,865篇不一樣文檔的130,160,392個連接。主要說明的是,這些數據中沒有偏好值或者排名等級,這裏只有文章與文章之間的關聯關係。也 就是說,這屬於一種「布爾偏好」。文章A連接了文章B,不能表明B對A也有連接。在這裏,用戶和項目是同樣多的,因此不管是基於用戶的算法仍是基於項目的算法無好壞之分。若是使用一個涉及類似度度量的算法而且不依賴於偏好值,那麼LogLikelihoodSimilarity會比較合適。
直覺上這些數據具備什麼意義?而且咱們指望得到什麼樣的推薦結果?一條從A到B的連接表示了B向A提供了一些相關參照信息。一個基於這些信息的推薦信息將會一些和A指向相同或類似的文章。這些推薦出來的文章被解釋成它們沒有被A指向卻應該被A指向。推薦系統將揭示一些對A感興 趣或者會偶然關聯上的一些文章。
在處理這樣大的數據時,一個非分佈式的推薦引擎可能就搞不定了。單單這些數據就要消耗JVM堆空間2GB大小,再加上 Mahout程序所需空間,可能須要2.5GB。這已經超過了某些32位的機器的堆空間大小。也就是說,你須要一臺64位的機器,今兒不換明兒也得換。再 因爲推薦算法固有的時間複雜度,推薦系統須要超過一秒的時間去完成推薦任務,這對於現代Web實時應用來講已是很是慢了。
若是咱們有足夠多的硬盤,那麼咱們能夠搭建這樣一個平臺。可是總有一天,隨着數據的日益增多,到了十億或者更多,所需的堆空 間也達到了上限32GB呢?對了,也許有人會開始琢磨如何對數據降噪去減小數據的量,提升數據的精度。可是這並不能從根本上回避數據增加所帶來的問題。
若是你的系統在處理數據規模上有限制的話,那麼只能說你Out了。計算資源能夠無限的增長;那麼咱們要解決的問題是若是把這些計算資源整合在一塊兒去協同的完成任務。你的收益和製做一個超級計算機(計算能力的提高)所需的成本是不成比例的,因此咱們應該想辦法利用多個普通機器的 計算資源。對於那些單點無任何聯繫的機器,堆在一塊兒只能是浪費電源,最有效利用他們的方式就是聯合它們去爲推薦系統效力。
這些維基數據的大小表明了一個基於Mahout的實時推薦系統所處理數據的上限。——這其實已經超過現代的標準了。對於這樣的數據規模,咱們須要一個新的方法。
根據上面說明的緣由,咱們不得以才使用多個普通機器與代替一個高性能機器。一個公司或學術組織可能擁有不少未充分利用的普通 機器,這樣這些機器額外的空閒資源就能夠用來作推薦任務。另外有一些計算資源也能夠經過雲計算的提供商哪裏獲得,好比亞馬遜EC2服務 (http://aws.amazon.com)。
圖 6.1 分佈式能夠將一個數據規模很大的問題化簡成不少小規模數據的問題,從而分配給較小的服務器上去計算。
分佈式處理一個推薦問題從根本上改變了推薦引擎。到目前爲止咱們所見到的全部推薦算法都是一個具備一個偏好返回值的函數。爲 了給一篇文章推薦一個新的鏈接,咱們須要去遍歷全部的文章-文章的鏈接;由於推薦過程須要全部的這些數據。然而,如此大量的數據,咱們要遍歷所有或者大部 分不可能一次性完成。咱們以前所介紹的方法已經變得再也不適用了,至少對於目前的問題形式。接下來分佈式推薦引擎將爲你我點亮一展明燈。
須要指出的是,分佈式處理一個問題不能提搞計算的效率,相反,它相對於單機處理要消耗更多的資源。好比,在不少機器以前傳輸 數據須要消耗網絡帶寬。這種計算每每要被結構化,包括中間結果的排序,它會佔用一些時間去進行序列化、存儲以及反序列化等過程。並且這些是很是佔用內存和消耗電能的。
須要注意的是,這樣的計算須要在線下執行,由於即便計算不多的數據也是秒級別的,而不是毫秒級別的。這樣它就不能對用戶的請求作出實時響應。通常地,這樣的計算和存儲會按期的進行,而後在運行時返回給用戶。
然而,這種作法能夠爲推薦系統在處理大規模數據時提供一種途徑,這是單機處理方案沒法具有的。由於分佈式計算能夠從不少機器 上利用計算資源,把那些未使用、零散的計算資源整合在一塊兒,從而在計算能力上超越專用計算機。最後,分佈式計算能夠使用更少的時間完成任務,雖然它須要更多對原料處理的過程和時間。通常而言,對於同一個問題,分佈式要比單機的計算多消耗一倍的CPU資源。若是咱們用10CPU,那麼速度將會是單機處理的5 倍,並且對於機器的利用率也大大提升了。
對於如此規模的數據,咱們但願使用分佈式處理的方法。首先,咱們會對基於項目的算法的分佈式變異版本進行描述。它在某種程度上和之前非分佈式的版本很類似。固然它看起來是徹底不一樣的,由於之前的算法不曾被翻譯到分佈式的世界。接下來咱們要用Hadoop來跑一跑。
這個算法由一些簡單的矩陣操做都成,它易於解釋而且容易實現。若是你上次接觸矩陣是好幾年前了,不要擔憂,最棘手的操做只有矩陣乘法(若是您連矩陣乘法都不知道,拜託,那還搞啥數據挖掘...)。這裏保證沒有什麼行列式、行分解、特徵值等等。
回憶一下,基於項目的推薦,咱們依賴於ItemSimilarity的實現。它能夠提供兩個項目間的類似程度。試想一下,咱們會把計算完的類似度存放在一個很大的方陣裏面,行和列和項目一一對應。每一行(或者每一列)表明了一個特定的項目與其餘項目的類似度的一個向量。事實上 它是個對稱方陣。由於X與Y的類似度就是Y與X的類似度。
對與這個算法,咱們須要一個叫作「協同矩陣(co-occurrence matrix)」的東西。咱們用兩個不一樣項目同時 被喜歡的次數(協同因子)來代替以前類似度,這樣能夠構造出一個協同矩陣。好比,9個用戶同時對X,Y感興趣,那麼他們的協同因子就是9,若是X,Y沒有 同時被任何用戶喜歡那麼協同因子就是0,對於項目對本身的協同因子咱們不考慮,或者說咱們不去計算它。
協同因子很像類似度;兩個項目同時出現能夠描述這兩個項目的類似程度。因此,正如咱們以前所看到的,協同矩陣扮演了ItemSimilarity所須要的數據的角色。
表 6.1 樣本集中的協同矩陣。第一行和第一列分別是項目序號。
生成矩陣的過程就是簡單的計數,這個矩陣和偏好值無關。一會咱們會對這些值進行計算。表6.1 表示了咱們通篇用到的一個小樣例數據集所產生的協同矩陣。像上面所說,它是個對稱方陣。有7個項目,矩陣有7行7列,對角線上的值將不會被使用,爲了矩陣顯示完整,咱們暫且把數據寫 在上面。
下一步就是咱們把先前的推薦方法轉化爲一個基於矩陣的分佈式模型,咱們須要把用戶對項目的偏好看做是一個向量。這一步你已經作到了。當咱們使用歐幾里德距離來度量用戶類似度時,只需把用戶當作是空間裏的點,而類似度就是點之間的距離。
一樣的,在模型中,用戶的偏好就是一個n維的向量,每一個維度表明一個項目。偏好值就是向量的每一個份量。0表明用戶對該項目無偏好。這個向量是稀疏的,不少份量都是0,由於實際中的用戶僅對不多的項目有偏好。
例如,在上面的小樣本數據集中,用戶3的向量就是[2.0, 0.0, 0.0, 4.0, 4.5, 0.0, 5.0]。爲了完成推薦,每一個用戶都須要這樣一個向量。
爲了給用戶3產生推薦結果,只須要用矩陣去乘以他的用戶向量,如6.2表中所示。
花一些時間回憶一下矩陣乘法把,若是須要來這裏看看:(http://en.wikipedia.org/wiki/Matrix_multiplication )。協同矩陣和用戶向量的乘積是一個向量,維度個數等於項目的個數。這個向量就是咱們要的推薦結果。份量的值越大說明該項目的推薦排名越靠前。
表6.2 協同矩陣與用戶3向量(U3)的乘積,最後用R來表示結果。
表6.2 展現了協同矩陣與U3的乘法運算過程,以及獲得最終的推薦結果R。對於用斜體表示分數的項目10一、10四、 105還有107,咱們徹底忽略他們的結果,由於咱們事先知道用戶3對這些項目產生了偏好。剩下的結果中,103的分數是最高的,用黑體表示,那麼103 就應該排在推薦結果中的首位。其餘按照分數往下排便可。
讓咱們停下來理解一下上面產生的結果,爲什麼R中值較高的項目是較好的推薦呢?R中的沒個份量是估計出來的偏好值,可是爲什麼這個值就能夠來表徵用戶對該項目的偏好呢?
回顧一下上面的計算過程,好比,R的第三個份量來自於矩陣的第三行與用戶向量的點積。拿上面的數據就是:
4(2.0) + 3(0.0) + 4(0.0) + 3(4.0) + 1(4.5) + 2(0.0) + 0(5.0) = 24.5
矩陣的第三行包含了項目103與其餘項目的協同因子。直覺告訴咱們,若是103和該用戶所偏好的其餘項目比較類似,那麼用戶 極可能會對103也有偏好。這個公式就是項目的協同因子與用戶偏好乘積之和。若是103和該用戶所偏好的不少項目同時出現時,那麼103的分數就會越高。 相應的項目偏好越大也會對分數有所貢獻。這就是爲什麼R能夠做爲預測結果。
須要說明的是,R不能表明用戶對該物品的偏好值,由於他們對於偏好值來講太大了。咱們能夠經過歸一化來將這些值變位符合要求的偏好值。若是你願意的話,能夠本身對結果處理一下。可是對於咱們的目標來講,歸一化是不必的,由於咱們關心的只是這些項目的得分排序,而不是具體的 值。
這是個頗有意思的事情,可是用戶大規模處理的算法到底是什麼樣子的呢?
算法的每一個單元在任什麼時候候都僅僅包含了數據的一個子集。例如,在建立用戶向量時,每一個計算單元都只爲一個特定的用戶去計算。 計算協同矩陣時,計算單元僅爲一個項目去計算它的協同因子向量。產生推薦結果時,計算單元只是用矩陣的一個行或者一列去乘以用戶向量。另外,一些計算單元能夠立足於收集這些相關數據。好比,用戶向量的建立,它所需的每一個偏好值能夠各自單獨去計算,而後收集。
MapReduce範式專門爲此而生。
本章包括
1 實戰操做了解聚類
2.瞭解類似性概念
3 使用mahout運行一個簡單的聚類實例
4.用於聚類的各類不一樣的距離測算方法
做爲人類,咱們傾向於與志同道合的人合做—「鳥的羽毛彙集在一塊兒。咱們可以發現重複的模式經過聯繫在咱們的記憶中的咱們看到的、聽到的、問道的、嚐到的東 西。 例如,相比較鹽 ,糖可以是咱們更多地想起蜜。因此咱們把糖和蜜的味道結合起來叫他們甜蜜。甚至咱們不知道甜蜜的味道,可是知道他跟世界上全部的含糖的東西是類似的,是同一類的。咱們還知道它與鹽是不一樣類的東西。無心中,咱們不一樣的味道使用了聚類。把糖和鹽作了聚類,每一個組有數百個項目。
在天然界中,咱們觀察不一樣類型的羣體。認爲猿與猴是同一種靈長類動物。全部的猴子 都有一些性狀如短高度,長尾巴,和一個扁平的鼻子。相反,猿類有較大的尺寸,長長的手臂,和更大的頭。猿看起來不一樣於猴子,但都喜歡香焦。因此咱們能夠認爲猿和猴子做爲兩個不一樣的組,或做爲一個單一的愛香蕉的靈長類動物羣。咱們考慮一個集羣徹底取決於咱們選擇的項目之間的類似性測量的特色(在這種狀況下, 靈長類動物)。
在這一章中,從mahout學習的聚類的例子中,咱們將會知道聚類是什麼,如何有數據概念聯繫起來。讓咱們從基礎開始吧!
7.1 聚類的基礎
聚類的過程是怎麼樣的呢?假如你能夠去有成千上萬的書籍的圖書館。在圖書館內 ,圖書是雜亂無章的。要找到想讀的書必須橫掃全部的書籍,一本一本的才能特定的書。這不只是繁瑣和緩慢,並且很是枯燥。
按照標題的字母順序排序會對讀者經過標題尋找有很大的幫助,若是大多數人只是簡單地瀏覽一下,只是找一個大概的主題的書籍呢?這樣經過按照書籍的主題進行分類要比按照標題的字母順序更有用。可是如何進行分組呢?剛剛接手這份工做,你也不會知道全部的書籍是什麼的?是衝浪的、浪漫的,或你沒有遇到過的課 題。
經過按主題把書籍分類,你不得不把全部書放在同一線上,一本一本的開始閱讀。當你遇到一本書的內容是相似之前的一本書,你就返回去把它們放在在一塊兒。當你完成,你從數千上萬的書中獲取到你要的主題的一堆書。
幹得好!這是你的第一個聚類的經驗。若是一百個主題組太多了,你就得從頭開始和重複剛纔的過程得到書堆,直到你的主題,從另外一個堆是徹底不一樣的。
聚類是全部關於組織項目從一個給定集合成一組相似的項目。在某些方面,這些集羣能夠被認爲是做爲項目類似集,可是與其餘集羣項目不一樣的。
聚類集合包含三項
● 算法 ———–這是用來組書籍的方法
●類似性和差別性的概念——-一個在前面討論的,依賴於這本書是否屬於已經存在的堆,仍是應 該另組新一堆的判斷。
●終止條件———圖書館的例子中,當達到這些書不能堆積起來了,或這些堆已經至關不一樣的,這就是終止
在這個簡單的例子中,圈出來的顯然是基於距離三個集羣,表明了聚類的結果。圓是一個在聚類方面是一個很好的方法。因爲羣組經過中心點和半徑來定義的,圓的中心被叫爲羣重心,或者羣平均(平均值),羣重心的座標是類簇中的全部點的x,y軸的平均值
項目的類似性測量
圖7.1x-y平面圖的點,圓圈表明了聚類,在平面團中的點歸類了單個邏輯羣組,聚類算法有益於識別羣組
在本章中,咱們將聚類可視化爲一個幾何問題。聚類的核心是使用幾何的技術表達不一樣距離的測算。咱們找到一些重要的距離測算法和聚類關係。平面聚類點與文本聚類之間的具體類似性就能夠抽象出來。
在後面的章節中,咱們探討了普遍用於聚類的方法數據,以及mahout 中使用
方法。圖書館的例子是將書分堆直到達到必定閾值的一種策 略。在這個例子中造成的簇的數目取決於數據;基於許多書和臨界值,你可能發現了100後者20,甚至是1個類簇。一個更好的策略是創建目標簇,而不是一個臨界值,而後找到最好的羣組與約束。接下來咱們將詳細的介紹目標簇和不一樣的變量
7.2項目的類似性測量
聚類的重要問題是找到一方法,經過任何兩個數中的一個數來量化類似性。注意一下咱們整片文章中使用的專業術語 :項目和點,這兩個是聚類數據的單位。
在X-Y平面的例子,類似性的度量(類似性度量)的分爲兩個點之間的歐幾里德距離。圖書館的例子沒有這種清晰的數學手段,而不是徹底依賴的智慧館員之間的類似度來判斷書。這工做不在咱們的案例,由於咱們須要一個度量,可在計算機上實現.
一個可能的度量是基於兩本書的標題共同含有的詞的數量。基於哈利·波特:哲學家的石頭和哈利·波特這兩本書:阿茲卡班的囚徒中常見的三個詞:哈利、波特、the。即時魔戒也:兩塔是相似於哈利·波特系列,這一措施類似不會捕獲這一切。你須要改變的類似性度量來對書籍自己的內容賬戶。你能夠將單詞計數。
只惋惜,說的容易作起來難。這些書不只有幾百個網頁的文本,並且英語的特色也使的分類方法更加困難。在英語文本中有一些很頻繁的次例如 a,an ,the 等等,它老是常常發生但又不能說明這是這兩本書的類似點。
爲了對抗這種影響,你能夠在計算中使用的加權值,而且使用低權重表示這些詞來減小對類似度值的影響。在出現不少次的詞使用低權重值,出現少的用高權重。你能夠衡量一個特定的書常常出現的,好比那些強烈建議內容的書籍–相似於魔術類的哈利波特。
你給書中的每個單詞一個權重,就能算出這本中的類似性–就是全部詞的詞頻乘以每個詞的權重的和。若是這兩本書的長度相同,那麼這個就是一個比較適當的方法。
若是一本書有300頁,另外一本有1000頁呢?固然書頁大的書的詞也多。
K-means須要用戶設定一個聚類個數(k)做爲輸入數據,有時k值可能很是大(10,000),這是Mahout閃光的(shines)地方,它確保聚類的可測量性。
爲了用k-means達到高質量的聚類,須要估計一個k值。估計k值一種近似的方法是根據你須要的聚類個數。好比100萬篇文章,若是平均500篇 分爲一類,k值能夠取2000(1000000/500)。這種估計聚類個數很是模糊,但k-means算法就是生成這種近似的聚類。
下面看一下k-means算法的細節,K-means算法是硬聚類算法,是典型的局域原型的目標函數聚類方法的表明,它是數據點到原型的某種距離做爲優化的目標函數,利用函數求極值的方法獲得迭代運算的調整規則。算法採用偏差平方和準則函數做爲聚類準則函數。K-means算法是很典型的基於距離的聚類算法,採用距離做爲類似性的評價指標,即認爲兩個對象的距離越近,其類似度就越大。該算法認爲簇是由距離靠近的對象組成的,所以把獲得緊湊且獨立的簇做爲最終目標。k個初始類聚類中心點的選取對聚類結果具備較大的。
算法步驟:
(1)隨機選取任意k個對象做爲初始聚類中心,初始表明一個簇;
(2)計算點到質心的距離,並把它歸到最近的質心的類;
(3)從新計算已經獲得的各個類的質心;
(4)迭代2~3步直至新的質心與原質心相等或小於指定閾值,算法結束。
這種兩步算法是最大指望算法(EM)的典型例子,
第一步是計算指望(E),利用對隱藏變量的現有估計值,計算其最大似然估計值;
第二步是最大化(M),最大化在 E 步上求得的最大似然值來計算參數的值。
M 步上找到的參數估計值被用於下一個 E 步計算中,這個過程不斷交替進行。
K-mean聚類用到KMeansClusterer或KMeansDriver類,前一個是在內存(in-memory)裏對節點聚類,後者採用 MapReduce任務執行。這兩種方法均可以就像一個普通的Java程序運行,而且能夠從硬盤讀取和寫入數據。它們也能夠在hadoop上執行聚類,通 過度布式文件系統讀寫數據。
下面舉例,使用一個隨機點生成器函數來建立一些點。這些點生成矢量格式的點做爲一個正態分佈圍繞着一箇中心。使用Mahout的in-memory K-means 聚類方法對這些點聚類。
建立節點:generateSamples方法,取(1,1)爲中心點,標準差爲2,400個圍繞着(1,1)的隨機點,近似於正態分佈。另外又取了2個數據集,中心分別爲(1,0)和(0,2),標準差分別爲0.5和0.1。
KMeansClusterer.clusterPoints()方法用到一下參數:
Mahout-example裏的DisplayKMeans類能夠直觀的看到該算法在二維平面的結果,9.2節將介紹運行一個Java Swing application的DisplayKMeans。
若是數據量很大時,應採起MapReduce運行方式,將聚類算法運行在多個機器上,每一個mapper獲得一個子集的點,每一個子集運行一個mapper。這些mapper任務計算出最近的集羣做爲輸入流。
K-means聚類的MapReduce Job
採用KMeansDriver類的run()方法,須要輸入的參數有:
public static void run(Configuration conf,Path input,PathclustersIn,Path output,
DistanceMeasure measure,
double convergenceDelta,
int maxIterations,
boolean runClustering,
boolean runSequential)
採用SparseVectorsFromSequenceFile工具,將sequenceFile轉換成Vector,由於K-means算法須要用戶初始化k個質心。