常見數據挖掘算法的Map-Reduce策略(2)

       接着上一篇文章常見算法的mapreduce案例(1)繼續挖坑,本文涉及到算法的基本原理,文中會大概講講,但具體有關公式的推導還請你們去查閱相關的文獻文章。下面涉及到的數據挖掘算法會有:Logistict 迴歸,SVM算法,關聯規則apriori算法,SlopeOne推薦算法,二度人脈社交 推薦算法
 
logistict regression的 map-reduce
       邏輯迴歸做爲經典的分類算法,工業界也是應用的很是普遍( 點擊率預估,廣告投放等 ),貌似大部分互聯網公司都會用吧,關於logistict regression的應用研究主要分兩塊:1)用什麼樣的正則(L2,L1); 2)使用什麼優化算法;關於第一點,若是維度超級多選L1較好,L1自然具備特徵選擇的優點,另外經常使用的優化算法有:梯度降低,LBFGS、隨機梯度降低,以及微軟針對L1提出的OWLQN算法;本來的logisitc迴歸,是針對線性可分的的,業界的一淘企業的工程師擴展了Logistic迴歸,用它來處理非線性的問題。
       針對多種優化算法,梯度降低,LBFGS,OWLQN都是能夠無損的並行化(執行結果與串行的同樣),而基於隨機梯度降低的只能進行有損的並行化。
       以梯度降低爲例:梯度降低的核心步驟 ,每一次迭代的個過程能夠轉換成一個map-reduce過程,按行或者按列拆分數據,分配到N各節點上,每一個節點再經過計算,最後,輸出到reduce,進行合併更新W權重係數,完成一次迭代過程。下圖文獻1中也提到LR的並行,不過用的優化方法是
Newton-Raphson,節點須要計算海森矩陣。
       
        針對隨機梯度的並行,下圖文獻2中提到
 
       算法1是基本的SGD算法,算法2,3是並行的SGD,   能夠看出每臺worker分配T個數據,利用這些數據來SGD優化更新W,而後輸出W由reduce端進行歸約。
 
SVM的 map-reduce
       支持向量機,最近十五年機器學習界的明星算法,學術界也是各類研究,現今已經達到一個瓶頸,屋漏偏逢連夜雨,隨着深度學習的雄起,SVM弄的一我的走茶涼的境遇(也許正是90年代神經網絡的感覺吧,呵呵),如今講一講關於SVM的並行,因爲原算法較難應用並行策略,而它的另外一個算法變種-pegasos 適合並行,下面是該算法的過程。
 
初始化W=0(向量形式)
for i in t:
      隨機選擇K個樣本
     for j in K:
          if 第j個樣本分錯
              利用該樣本更新權重
     累加W的更新
end for
     
下面是基於mrjob的map-reduce版   
  1 class MRsvm(MRJob):
  2 
  3     DEFAULT_INPUT_PROTOCOL = 'json_value'
  4 
  5     #一些參數的設置
  6 
  7     def __init__(self, *args, **kwargs):
  8 
  9         super(MRsvm, self).__init__(*args, **kwargs)
 10 
 11         self.data = pickle.load(open('data_path'))
 12 
 13         self.w = 0
 14 
 15         self.eta = 0.69 #學習率
 16 
 17         self.dataList = [] #用於收集樣本的列表
 18 
 19         self.k = self.options.batchsize
 20 
 21         self.numMappers = 1 
 22 
 23         self.t = 1 # 迭代次數
 24 
 25 
 26     def map(self, mapperId, inVals): 
 27 
 28         #<key,value> 對應着 <機器mapperID,W值或者樣本特徵跟標籤>
 29 
 30         if False: yield
 31 
 32         #判斷value是屬於W仍是樣本ID
 33 
 34         if inVals[0]=='w': 
 35 
 36             self.w = inVals[1]
 37 
 38         elif inVals[0]=='x':
 39 
 40             self.dataList.append(inVals[1])
 41 
 42         elif inVals[0]=='t': self.t = inVals[1] 
 43 
 44 
 45     def map_fin(self):
 46 
 47         labels = self.data[:,-1]; X=self.data[:,0:-1]#解析樣本數據
 48 
 49         if self.w == 0: self.w = [0.001]*shape(X)[1] #初始化W
 50 
 51         for index in self.dataList:
 52 
 53             p = mat(self.w)*X[index,:].T #分類該樣本 
 54 
 55             if labels[index]*p < 1.0:
 56 
 57                 yield (1, ['u', index])#這是錯分樣本id,記錄該樣本的id 
 58 
 59         yield (1, ['w', self.w]) #map輸出該worker的w
 60 
 61         yield (1, ['t', self.t])
 62 
 63 
 64     def reduce(self, _, packedVals):
 65 
 66         for valArr in packedVals: #解析數據,錯分樣本ID,W,迭代次數
 67 
 68             if valArr[0]=='u': self.dataList.append(valArr[1])
 69 
 70             elif valArr[0]=='w': self.w = valArr[1]
 71 
 72             elif valArr[0]=='t': self.t = valArr[1] 
 73 
 74         labels = self.data[:,-1]; X=self.data[:,0:-1]
 75 
 76         wMat = mat(self.w); wDelta = mat(zeros(len(self.w)))
 77 
 78         for index in self.dataList:
 79 
 80             wDelta += float(labels[index])*X[index,:] #更新W
 81 
 82         eta = 1.0/(2.0*self.t) #更新學習速率
 83 
 84         #累加對W的更新
 85 
 86         wMat = (1.0 - 1.0/self.t)*wMat + (eta/self.k)*wDelta
 87 
 88         for mapperNum in range(1,self.numMappers+1):
 89 
 90             yield (mapperNum, ['w', wMat.tolist()[0] ])
 91 
 92             if self.t < self.options.iterations:
 93 
 94                 yield (mapperNum, ['t', self.t+1])
 95 
 96                 for j in range(self.k/self.numMappers):
 97 
 98                     yield (mapperNum, ['x', random.randint(shape(self.data)[0]) ])
 99 
100         
101     def steps(self):
102 
103         return ([self.mr(mapper=self.map, reducer=self.reduce, 
104 
105                          mapper_final=self.map_fin)]*self.options.iterations)   

 

關聯規則Apriori的 map-reduce
         啤酒跟尿布的傳奇案例,相信你們都應該很是熟悉了,可是很悲劇的是這個案例貌似是假的,呵呵,超市的管理者通常會把這兩個放在相差很遠的位置上擺放,拉長顧客光顧時間,或許就不止買尿布跟啤酒了。前段時間看到一個東北笑話也許會更容易理解關聯規則,「一天,一隻小雞問小豬說:主人去哪了? 小豬回答說:去買蘑菇去了;小雞聽完後,立馬撒腿就跑了,小豬說你走這麼急幹啥,小雞回頭說:主人若是買粉條回來,你也照樣急。。。。」很形象生動的講述了關聯規則,好了,又扯遠了了,如今回到關聯規則的並行上來吧,下面以一個例子簡述並行的過程。
 
假設有一下4條數據
id,交易記錄
1,[A,B]
2,[A,B,C]
3,[A,D]
4,[B,D]
首先,把數據按行拆分,搞到每一個worker上面,key=交易id,value=交易記錄(假設1,2在第一個mapper上,3,4在第二個mapper上)
其次,每一個worker,計算頻次(第一個mapper生成<A,1>,<B,1>,<A,1>,<B,1>,<C,1> ;第二個mapper 就會生成<A,1>,<D,1>,<B,1>,<D,1>)
接着,進行combine操做(減輕reduce的壓力) (第一個mapper生成<A,2>,<B,2>,<C,1> ;第二個mapper 就會生成<A,1>,<B,1>,<D,2>)
最後,送到reduce上面進行歸約,獲得1-頻繁項集
而後再重複上面的動做,知道K-頻繁項集
 
       總結:這是對 Apriori的並行實現,可是該算法的一個缺點是須要屢次掃描數據,性能是個問題,對此,韓教授設計了另一個更巧妙的數據結構fp-tree,這個在mahout裏面是有實現的(0.9的版本里面貌似把這算法給kill了。。),整體來講關聯規則這個算法是一個聽起來是一個很實用的算法,實際操做過程當中要仔細調節支持度、置信度等參數,否則會挖掘出不少不少的價值低的規則。
 
SlopeOne推薦算法的 map-reduce
       有關這個算法的原理能夠參考網上或者本博客的另一篇文章(http://www.cnblogs.com/kobedeshow/p/3553773.html ),關於這個算法的並行最關鍵的,計算item跟item之間的評分差別,下面以一個例子開始:
例如一個評分矩數據(用戶,物品,評分)以下所示
A,one  ,2
A,two  ,3
A,three,1
B,one   ,3
B,two   ,5
C,one   ,4
C,three,2
 
首先把該數據集打成{用戶,[(物品1,評分),(物品2,評分),....,(物品n,評分)]}形式,很簡單的一個map-reduce操做
 
                 物品one          物品two        物品three
用戶A           2                     3                    1
用戶B            3                     5                   ?
用戶C            4                    ?                  2
固然真是的數據集確定是很是稀疏的,這裏只爲講清原理,接着對數據分片,分到不一樣的worker裏面,這裏假設3個,輸入是[A,(one,2) ,(two,3) ,(three,1) ], [B,(one,3) ,(two,5) ], [C,(one,4) (three,2) ]。
每個map的操做輸出<key,value> 對應了<(物品1,物品2),(評分1-評分2,1)>  最後面的1,是爲了對 (物品1,物品2)  計數1,上面第1個節點<(one,two),(-1,1)>, <(one,three),(1,1)>, <(two,three),(1,1)>;  第2個節點 <(one,two),(-2,1)>, <(one, three  ),(2,3,1)>;  第3個節點 <(one, three  ),(2,1)>。
接着能夠進行一下combine操做,把key相同的value,評分差值相加,計數相加
最後進行reduce操做,獲得物品跟物品之間的評分差
 
       總結:slopeone在mahout0.9版本里面也被kill掉了,悲劇,難道太簡單啦??關於該算法有另一個變種就是weighted  slopeone,其實就是在計算物品跟物品之間評分差的時候,進行了加權平均。
 
人脈二度推薦的 map-reduce
      最近社交類網站很是流行的給你推薦朋友/感興趣的人,利用好社交關係,就不愁找不到好的推薦理由了,舉個例子,假設A的好友是B,C,D,然而B的好友有E,C的好友有F,D的好友有E,那麼若是要給A推薦好友的話,那麼就會首推E了,由於B,C跟E都是好友,而F只是和C好友(有點關聯規則裏面支持度的味道)。OK,下面詳解給A用戶推薦好友的map-reduce過程
首先輸入文件每行是兩個id1,id2,假設id1認識id2,可是id2不認識id1,若是是好友的話,得寫兩行記錄(方便記錄單項社交關係)
A,B     //A認識B
B,A    //B認識A
A,C
C,A
A,D
D,A
B,E
E,B
C,F
F,C
D,E
E,D
第一輪map-reduce(爲簡單書寫,下面只對與A有關的行爲進行演示)
輸入上面數據,輸出<id,[(該id認識的人集合),(認識該id的人集合)]>
輸出:<B,[(A),(E)]>, <C,[(A),(E)]>, <D,[(A),(F)]>
 
第二輪map-reduce
map輸入上面數據,輸出<[ (該id認識的人),(認識該id的人)],id >
輸出: <[(A),(E)],B>, <[(A),(E)],C>, <[(A),(F)],D>
reduce輸入上面數據,輸出 <[ (該id認識的人),(認識該id的人)],[id集合] >
輸出: <[(A),(E)],[B,C]> <[(A),(F)],[D]>
 
OK這樣算法挖完了,id集合的長度做爲二度人脈的支持度,能夠從上面看到,A認識E,比A認識F更靠譜一點。
 
       總結:還有不少其餘的推薦算法諸如基於近鄰的CF,模型的CF(矩陣分解),關於矩陣分解的,前段時間,LibSvm團隊發表的Libmf,針對矩陣分解的並行化方面作出了很是好的貢獻
 
參考資料:
1,《Parallelized Stochastic Gradient Descent》Martin A. Zinkevich、Markus Weimer、Alex Smola and Lihong Li
2,《Map-Reduce for Machine Learning on Multicore NG的一篇nips文章》
5,Pegasos:primal estimated sub-gradient solver for svm
6,machine learning in action
7,http://my.oschina.net/BreathL/blog/60725
相關文章
相關標籤/搜索