岳永斗,張婷婷
(無錫商業(yè)職業(yè)技術(shù)學(xué)院 江蘇 無錫 214153)
隨著科技的發(fā)展,世界范圍內(nèi)產(chǎn)生的數(shù)據(jù)已由原來的TB級(jí)達(dá)到PB級(jí),用過去的數(shù)據(jù)處理技術(shù)已經(jīng)很難適應(yīng)社會(huì)需求。云計(jì)算、神經(jīng)網(wǎng)絡(luò)等新興技術(shù)發(fā)展迅速。在這樣的時(shí)代背景下,云計(jì)算技術(shù)以其高靈活性、可擴(kuò)展性和高性價(jià)比等優(yōu)點(diǎn),成為當(dāng)下計(jì)算機(jī)領(lǐng)域的研究熱門。另一方面,于學(xué)生群體而言,圖書館是必不可少的知識(shí)獲取途徑。若能將云計(jì)算技術(shù)與數(shù)字圖書館相結(jié)合,針對(duì)不同用戶實(shí)現(xiàn)圖書的個(gè)性化推薦,那么對(duì)用戶而言將是更加良好的體驗(yàn),對(duì)科教興國(guó)的戰(zhàn)略目標(biāo)也有一定促進(jìn)作用。本文在本地環(huán)境進(jìn)行模擬實(shí)驗(yàn),將云計(jì)算技術(shù)與圖書館數(shù)據(jù)相結(jié)合,對(duì)讀者的文獻(xiàn)評(píng)分的歷史數(shù)據(jù)進(jìn)行挖掘,構(gòu)建文獻(xiàn)推薦模型框架,并將文獻(xiàn)推薦模型框架生成的圖書推薦列表進(jìn)行轉(zhuǎn)化,最終為采編部生成采購(gòu)清單。具體做法大致如下:先用Python對(duì)原始數(shù)據(jù)進(jìn)行清洗,將清洗后的結(jié)果上傳至虛擬化平臺(tái)上,使用Hive(數(shù)據(jù)倉(cāng)庫(kù)工具)和Spark對(duì)數(shù)據(jù)進(jìn)行分析,挖掘數(shù)據(jù)特征,構(gòu)建算法模型,用機(jī)器學(xué)習(xí)算法對(duì)模型進(jìn)行訓(xùn)練,最終實(shí)現(xiàn)書籍的個(gè)性化推薦[1]。
云計(jì)算是近年來發(fā)展起來的一項(xiàng)技術(shù),也叫網(wǎng)格計(jì)算,是一種分布式計(jì)算。云計(jì)算提供3種服務(wù),分別是基礎(chǔ)設(shè)施即服務(wù)(IaaS)、平臺(tái)即服務(wù)(PaaS)和軟件即服務(wù)(SaaS)?;A(chǔ)設(shè)施即服務(wù)是指向用戶提供虛擬化的各種資源。前面提到過云是由各種復(fù)雜的網(wǎng)絡(luò)和存儲(chǔ)資源通過虛擬化連成的整體,基礎(chǔ)設(shè)施即服務(wù)就是將其中的一部分按需提供給用戶。平臺(tái)即服務(wù)是更高一層的服務(wù),除了提供用戶所需的基礎(chǔ)設(shè)施外還提供一些項(xiàng)目開發(fā)的環(huán)境。軟件即服務(wù)相比平臺(tái)即服務(wù)是更高一層的服務(wù),不僅提供前兩者的資源,還額外加上具體的應(yīng)用程序。
Spark是Hadoop生態(tài)環(huán)境中的一個(gè)組件,同時(shí)也是一個(gè)相對(duì)獨(dú)立的、基于內(nèi)存的計(jì)算框架。Spark最初設(shè)計(jì)出來的目的是加快計(jì)算效率、簡(jiǎn)化編程難度,隨著時(shí)間推移,Spark漸漸地形成一個(gè)與Hadoop類似的、獨(dú)立的生態(tài)環(huán)境。Spark可以使用存儲(chǔ)在Hadoop的所有數(shù)據(jù),包括HDFS和HBase中的。且Spark相比Hadoop有更多的優(yōu)點(diǎn),比如計(jì)算效率。以Logistics算法為例,Spark的計(jì)算時(shí)間比Hadoop少了數(shù)百倍。因?yàn)镾park可以將數(shù)據(jù)載入到內(nèi)存,而無需像Hadoop般頻繁讀取,極大地節(jié)省了讀寫數(shù)據(jù)的時(shí)間消耗。Spark的靈活性也是Hadoop無法比擬的。Spark的計(jì)算模式是基于MapReduce的,但是Spark還有20余種更靈活的計(jì)算方法,且Spark支持更多的功能,例如交互式查詢、流式計(jì)算,基于GraphX的圖計(jì)算算法和基于MLlib的機(jī)器學(xué)習(xí)算法。Spark對(duì)不同語(yǔ)言的兼容性也很高,Spark本身是使用簡(jiǎn)潔的Scala語(yǔ)言開發(fā)的,但提供了Python、Java、R等語(yǔ)言的接口[2]。
交替最小二乘法(alternating least squares,ALS),是一種非常經(jīng)典的擬合算法,通常用于優(yōu)化和預(yù)測(cè),其數(shù)學(xué)基礎(chǔ)是最小二乘法。ALS是協(xié)同過濾算法的一種,是在基于用戶的協(xié)同過濾算法(UserCF)和基于物品的協(xié)同過濾算法的基礎(chǔ)上進(jìn)行改進(jìn)得到的結(jié)果,即混合協(xié)同過濾算法。ALS算法對(duì)數(shù)據(jù)源的輸入,要求是一個(gè)三元組,即
表1 用戶-物品矩陣
然而在實(shí)際問題當(dāng)中,有很多個(gè)用戶和很多的物品,用戶只會(huì)選擇物品當(dāng)中的其中一小部分進(jìn)行評(píng)分,甚至有的不活躍用戶都沒有評(píng)分記錄,這就導(dǎo)致了矩陣當(dāng)中只有少數(shù)部分有相應(yīng)的評(píng)分,而大部分是空的、缺失的。
由于通常這個(gè)矩陣規(guī)模非常龐大,為了后續(xù)的運(yùn)算,我們需要對(duì)其進(jìn)行降維處理。例如一個(gè)m×n的矩陣A,可以看作是R(m×k)和S(k×n)T的矩陣之乘積,如下公式。
圖1中,矩陣R代表用戶與兩者之間的一些關(guān)聯(lián)因子(比如性別、年齡、物品信息等)之間的關(guān)系,矩陣S代表物品與關(guān)聯(lián)因子之間的關(guān)系。關(guān)聯(lián)因子是高度濃縮的,也就是說k一定是遠(yuǎn)小于m、n的,這樣才有降維的意義。這種做法我們稱之為“隱語(yǔ)義因子分析”,而交替最小二乘法就采用了該分析方法。ALS的核心,就是找到對(duì)應(yīng)的矩陣R和S,使得他們的乘積無限接近于原矩陣A。在這個(gè)過程中,A的缺失部分會(huì)得到填補(bǔ),也就有了相應(yīng)的預(yù)測(cè)值。ALS求R和S是一個(gè)收斂的過程,因?yàn)橐婚_始的R和S是隨機(jī)生成的,與實(shí)際值相差很遠(yuǎn),需要一點(diǎn)點(diǎn)地修正、迭代,得到最接近的值。這個(gè)過程需要計(jì)算預(yù)測(cè)值與真實(shí)值的誤差,于是就有了下面的損失函數(shù):
這個(gè)式子當(dāng)中,aij表示的是原始矩陣A中第i用戶對(duì)第j個(gè)物品的評(píng)分,ri是矩陣R的第i行的元素,sjT表示矩陣S的第j列的元素,二者的乘積是第i個(gè)用戶對(duì)第j個(gè)物品的預(yù)測(cè)值。我們要做的就是盡可能地降低L(R,S)的值,這樣預(yù)測(cè)值才能盡可能地接近真實(shí)值。由于公式中的R、S都是變量,為了求解L(R,S)的極小值,ALS算法的做法就是先確定其中一個(gè)變量,對(duì)另一個(gè)變量進(jìn)行調(diào)整直到L(R,S)取值最小,然后確定調(diào)整后的變量,對(duì)原先確定的變量進(jìn)行調(diào)整。重復(fù)此步驟直到均方根誤差小于預(yù)設(shè)值,則結(jié)束該算法。計(jì)算過程大致如下:
(1)確定矩陣S,計(jì)算ri的偏導(dǎo)數(shù),令其為0,可得
從而求解。
(2)確定矩陣R,計(jì)算sj的偏導(dǎo)數(shù),令其為0,可得
近年來,中國(guó)境內(nèi)勘察設(shè)計(jì)企業(yè)、咨詢服務(wù)企業(yè)緊隨國(guó)家戰(zhàn)略方針,積極投入境外工程項(xiàng)目。但隨著境外項(xiàng)目的開展,設(shè)計(jì)咨詢類企業(yè)面臨著多種多樣的市場(chǎng)競(jìng)爭(zhēng)及外來挑戰(zhàn),如何采用更先進(jìn)的管理理念來降低成本,協(xié)調(diào)中國(guó)企業(yè)境內(nèi)外項(xiàng)目運(yùn)轉(zhuǎn)過程中的矛盾,成為設(shè)計(jì)咨詢企業(yè)走出去的關(guān)鍵。本文結(jié)合設(shè)計(jì)咨詢企業(yè)的行業(yè)情況、成本核銷管理中的現(xiàn)狀以及境外項(xiàng)目成本管理特點(diǎn),探討設(shè)計(jì)咨詢企業(yè)境外項(xiàng)目科學(xué)成本管理中的方式與方法,希望為以后的工作起到實(shí)際的參考作用。
從而求解si。
(3)重復(fù)上述步驟直到均方根誤差小于預(yù)設(shè)值。
這個(gè)過程是需要輪流確定矩陣R和矩陣S的,然后使用最小二乘法計(jì)算損失函數(shù),這就是交替最小二乘法的名字來源。
由于圖書館數(shù)據(jù)涉及用戶隱私問題不好爬取,本文將使用Book-Crossing讀書社區(qū)的數(shù)據(jù)作為替代品。數(shù)據(jù)集來源網(wǎng)站http://www2.informatik.uni-freiburg.de/~cziegler/BX/,數(shù)據(jù)是由一個(gè)外國(guó)網(wǎng)友花費(fèi)4周時(shí)間爬取的,共3個(gè)表。表BX-Users.csv包含用戶信息,共278,858條,共有3列屬性,分別是用戶ID、用戶位置和用戶年齡。表BX-Books.csv共271,379條數(shù)據(jù),包含圖書的ISBN標(biāo)識(shí)、圖書的名稱、作者(第一作者)、出版年和發(fā)布者,后面鏈接到封面圖片的URL,存放在3個(gè)不同的列(圖片-URL-S、圖片-URL-M、圖片-URL-L),即小、中、大。這些URL指向Amazon網(wǎng)站。表BX-Book-Ratings包含用戶ID、圖書ISBN號(hào)和評(píng)分信息,共1,149,780條數(shù)據(jù)[3]。
接下來使用Python對(duì)數(shù)據(jù)集進(jìn)行數(shù)據(jù)清洗。首先使用pandas模塊讀入數(shù)據(jù)表,數(shù)據(jù)存儲(chǔ)格式為DataFrame,然后使用匿名函數(shù)統(tǒng)計(jì)每個(gè)表每一列的缺失值,操作相應(yīng)的DataFrame,刪除不合法圖書數(shù)據(jù)的評(píng)分記錄、評(píng)分為空值的評(píng)分記錄,最后將結(jié)果保存到指定目錄下,使用分號(hào)作為分隔符。
將數(shù)據(jù)表上傳至/home/Hadoop/ubtshare/BX-new目錄下,并去表頭,最后使用dfs -put命令上傳至集群。
2.3.1 在idea中編寫?yīng)毩⑦\(yùn)行程序
下載、安裝IDEA,新建項(xiàng)目Book_Recomend_System,配置pom.xml,添加相關(guān)依賴,新建scala類ReadFromHive.scala,嘗試讀取Hive中的表,設(shè)置SDK。為讀取到Hive中的數(shù)據(jù)庫(kù),還需要將hive-site.xml復(fù)制到resource目錄下。為存儲(chǔ)結(jié)果,先在MySQL中新建表bxrecommendresult、user和personalratings,即推薦結(jié)果表、用戶表和個(gè)人評(píng)分表。
為了程序順利運(yùn)行,向個(gè)人評(píng)分表插入少許評(píng)分記錄,見圖2。
然后開始編寫推薦算法。
(1)ReadFromHive.scala主要負(fù)責(zé)從Hive中讀取數(shù)據(jù)集。目前共有4個(gè)方法。
①read():負(fù)責(zé)從bx_book_ratings_small讀入所有數(shù)據(jù),并與表bx_books_small內(nèi)連接,得到數(shù)據(jù)標(biāo)簽列index。返回類型為DataFrame。
②readPersonal(userid:Int):負(fù)責(zé)從MySQL中的personalratings表篩選出指定用戶的評(píng)分記錄,并與表bx_books_small內(nèi)連接得到數(shù)據(jù)標(biāo)簽列index。返回類型為DataFrame。
③change(ratings: DataFrame):負(fù)責(zé)將從bx_book_ratings_small中讀到的記錄進(jìn)行格式轉(zhuǎn)換,每一條評(píng)分記錄轉(zhuǎn)換為一個(gè)String類型的值,不同項(xiàng)之間用“::”分隔。返回類型為Array[String]。
④readBookTable():負(fù)責(zé)從bx_books_small讀取字段index、title,對(duì)讀取結(jié)果格式轉(zhuǎn)換,每一條記錄轉(zhuǎn)換為“::”分隔的字符串。返回類型為Array[String]。
(2)DeleteFromMysql.scala主要負(fù)責(zé)從MySQL中刪除先前的推薦結(jié)果,有1個(gè)方法。
delete(userid:Int)
連接MySQL中的bxrecommendresult表,刪除其中指定用戶的推薦結(jié)果。
(3)BookAls_new.scala主要負(fù)責(zé)構(gòu)建推薦模型,對(duì)數(shù)據(jù)進(jìn)行預(yù)測(cè)分析。有1個(gè)自定義類和3個(gè)方法。
①自定義類Rating:有3個(gè)屬性,userid:Int型,對(duì)應(yīng)用戶ID;book_rating:Double型,對(duì)應(yīng)用戶評(píng)分;index:Int型,書籍標(biāo)簽列,與ISBN對(duì)應(yīng)。
②loadRatings(lines: Array[String]):負(fù)責(zé)用戶評(píng)分?jǐn)?shù)據(jù)格式轉(zhuǎn)換,初步過濾掉非法評(píng)分?jǐn)?shù)據(jù)。返回類型為Seq[Rating]。
③computeRmse(model: ALSModel, df: DataFrame, n:Long):負(fù)責(zé)計(jì)算校驗(yàn)集預(yù)測(cè)數(shù)據(jù)和實(shí)際數(shù)據(jù)之間的均方根誤差。返回類型為Double。
④main(args: Array[String]):程序的主體和入口。實(shí)現(xiàn)了從數(shù)據(jù)庫(kù)讀取數(shù)據(jù)、劃分?jǐn)?shù)據(jù)集、構(gòu)建并循環(huán)訓(xùn)練模型、為指定用戶個(gè)性化推薦書籍的整個(gè)流程。
(4)InsertToMysql.scala主要負(fù)責(zé)推薦結(jié)果的保存,有1個(gè)方法。
insert(array:Array[String])
負(fù)責(zé)將接收到的字符串按“::”分隔,將分隔后的字串重塑成DataFrame格式,指定字段名稱,最后連接MySQL并寫入bxrecommendresult表。
運(yùn)行結(jié)果見圖3。
2.3.2 在集群中運(yùn)行
在Project Structure點(diǎn)擊Artifacts,添加要打包的項(xiàng)目,刪除多余條目。點(diǎn)擊OK后,在菜單欄找到Build,點(diǎn)擊Build Artifacts,選擇Build操作,就可以得到項(xiàng)目的jar包。運(yùn)行結(jié)果見圖4。
本文首先提出課題的研究背景與意義,表明選取該課題的目的及動(dòng)機(jī);而后簡(jiǎn)要介紹本文的主要工作,主要包括相關(guān)計(jì)算概述,涵蓋云計(jì)算、Hadoop、Spark、RDD、DataFrame和ALS算法。最后是實(shí)驗(yàn)驗(yàn)證及結(jié)果,在此展示了理論基礎(chǔ),將其在實(shí)踐中加以運(yùn)用。
本次研究存在的問題還有許多,最直觀的問題為可視化界面過于樸素。另一方面,數(shù)據(jù)挖掘的深度不足,目前只是實(shí)現(xiàn)了數(shù)據(jù)清洗和推薦模型的構(gòu)建,更深層次的信息沒有得到發(fā)掘;推薦系統(tǒng)所用的算法僅停留在經(jīng)典的ALS上,缺乏算法上的改進(jìn)和多樣化比較,代碼運(yùn)行時(shí)間過長(zhǎng),同時(shí)運(yùn)行效率低。