Fp關聯規則算法計算置信度及MapReduce實現思路
說明:參考Mahout FP算法相關相關源代碼。
算法project能夠在FP關聯規則計算置信度下載:(僅僅是單機版的實現,並沒有MapReduce的代碼)
使用FP關聯規則算法計算置信度基於以下的思路:
1. 首先使用原始的FP樹關聯規則挖掘出全部的頻繁項集及其支持度;這裏須要註意,這裏是輸出全部的頻繁項集,並沒有把頻繁項集合並,所以須要改動FP樹的相關代碼,在某些步驟把全部的頻繁項集輸出;(ps:參考Mahout的FP樹單機版的實現,進行了改動,暫不確定是否已經輸出了全部頻繁項集)
為舉例簡單,能夠以以下的數據為例(原始事務集):
牛奶,雞蛋,面包,薯片 雞蛋,爆米花,薯片,啤酒 雞蛋,面包,薯片 牛奶,雞蛋,面包,爆米花,薯片,啤酒 牛奶,面包,啤酒 雞蛋,面包,啤酒 牛奶,面包,薯片 牛奶,雞蛋,面包,黃油,薯片 牛奶,雞蛋,黃油,薯片
2. 得到全部的頻繁項集例如以下:
0,2,3=4 2,4=3 0,1,2,3=3 3=6 2=7 1,2=5 1=7 0=7 0,3=5 0,2=6 0,1=5 4=4 0,1,2=4 0,1,3=4 1,3=5 1,4=3上面的頻繁項集中,等號後面的是支持度;每條頻繁項集顯示的是經過編碼的,編碼的規則例如以下:{薯片=0, 牛奶=3, 雞蛋=2, 面包=1, 啤酒=4}。同一時候。能夠看到上面的頻繁項集中的編碼是依照順序排列的(從小到大);
計算每條頻繁項集的置信度(僅僅計算2項和2項以上的頻繁項集):
1) 對於頻繁n項集,查找其前向(前向定義為前面n-1項集。比方頻繁項集:0,2,3那麽其前向為0,2)的支持度。假設頻繁n項集存在。那麽其前向(頻繁n-1項集)必定存在(假設頻繁項集是全部的頻繁項集的話,這個規則一定是成立的);
2)使用n項集的支持度除以n項集的前向的支持度就可以得到n項集的置信度。
3. 依照2中的計算方法是能夠計算全部的頻繁項集的置信度的。可是這裏有個問題:僅僅能計算比方0,2,3這個頻繁項集的置信度,而不能計算0,3,2這個頻繁項集的置信度(FP算法中頻繁項集0,2,3和0,3,2是一樣的頻繁項集。可是計算置信度的時候就會不一樣);
4. 針對3的問題,能夠給出以下的解決方式。
針對每條記錄(包括n個項)。把每一個項作為後向(定義為最後一個項。比方頻繁項集0,1,2,3能夠分別把0、1、2、3作為後向。輸出相對於置信度不同的頻繁項集),其它前向保持相對順序不變。 比方針對頻繁項集:0,1,2,3 =3,應該輸出: 1,2,3,0=3 0,2,3,1=3 0,1,3,2=3 0,1,2,3=3 因為針對同一個後向,其前向的順序事實上對於計算置信度是沒有影響的(比方針對0作為後向,1,2,3和2,1,3和3,2,1其支持度應該是一樣的),這樣對於算法來說其輸出的含有置信度的頻繁項集是比較完備的; 使用4的方法把原來FP樹的頻繁項集進行擴充就可以得到2中計算方法的數據了。5. 針對4的輸出(4的輸出事實上僅僅是頻繁項集和支持度,較3的結果來說僅僅是把1條記錄變為了n條而已),計算各個頻繁項集的置信度,事實上就是兩個表的互查,即以A表的n項頻繁集參考B表的n-1項頻繁集來計算n項置信度。A表和B表是一樣的。能夠使用MapReduce的思路。稍後細說。參考Mahout的單機FP實現,給出的計算置信度的代碼主要例如以下:1. 因為mahout裏面的實現其交互是和HDFS文件交互的,這裏能夠和本地文件進行交互,或者直接存入內存,本文的實現是直接存入內存的,假設要存入文件也是能夠的(只是可能要經過過濾反復記錄的操作);所以把單機版的FP中某些代碼做了改動。比方以下的代碼:
// generateTopKFrequentPatterns(new TransactionIterator<A>( // transactionStream, attributeIdMapping), attributeFrequency, // minSupport, k, reverseMapping.size(), returnFeatures, // new TopKPatternsOutputConverter<A>(output, reverseMapping), // updater);改動為以下的代碼:
generateTopKFrequentPatterns(new TransactionIterator<A>( transactionStream, attributeIdMapping), attributeFrequency, minSupport, k, reverseMapping.size(), returnFeatures,reverseMapping );這種改動在FPTree裏面有非常多,就不一一贅述,詳情參考本文源代碼下載的project;
2. 因為mahout的FP樹最後輸出的頻繁項集是經過整合的,所以有些頻繁項集沒有輸出(即僅僅輸出了最大頻繁項集),而上面提出的算法是須要全部頻繁項集都進行輸出的。所以在函數generateSinglePathPatterns(FPTree tree, int k,long minSupport) 和函數generateSinglePathPatterns(FPTree tree,int k,long minSupport)的return中加上一句:
addFrequentPatternMaxHeap(frequentPatterns);
這種方法的詳細代碼為:
/** * 存儲全部頻繁項集 * @param patternsOut */ private static void addFrequentPatternMaxHeap(FrequentPatternMaxHeap patternsOut){ String[] pStr=null; // 這裏的Pattern有問題。臨時使用字符串解析 for(Pattern p:patternsOut.getHeap()){ pStr=p.toString().split("-"); if(pStr.length<=0){ continue; } // 對字符串進行下處理,這樣能夠降低存儲 pStr[0]=pStr[0].replaceAll(" ", ""); pStr[0]=pStr[0].substring(1,pStr[0].length()-1); if(patterns.containsKey(pStr[0])){ if(patterns.get(pStr[0])<p.support()){// 僅僅取支持度最大的 patterns.remove(pStr[0]); patterns.put(pStr[0], p.support()); } }else{ patterns.put(pStr[0], p.support()); } } }這裏假定這種操作能夠得到全部的頻繁項集。而且存入到了patterns靜態map變量中。
3. 依據思路第4中的描寫敘述。把FP產生的頻繁項集進行擴充:
/** * 依據排序頻繁相機支持度 生成多頻繁項集支持度 */ public void generateFatPatterns(){ int[] patternInts=null; for(String p :patterns.keySet()){ patternInts = getIntsFromPattern(p); if(patternInts.length==1){// 針對頻繁一項集 fatPatterns.put(String.valueOf(patternInts[0]), patterns.get(p)); }else{ putInts2FatPatterns(patternInts,patterns.get(p)); } } } /** * 把數組中的每一項作為後向進行輸出,加入到fatpatterns中 * @param patternInts * @param support */ private void putInts2FatPatterns(int[] patternInts, Long support) { // TODO Auto-generated method stub String patternStr =Ints2Str(patternInts); fatPatterns.put(patternStr, support);// 處理最後一個後向 for(int i=0;i<patternInts.length-1;i++){// 最後一個後向在前面已經處理 // 不能使用同一個數組 patternStr=Ints2Str(swap(patternInts,i,patternInts.length-1)); fatPatterns.put(patternStr, support); } }
4. 針對上面輸出的頻發項集進行置信度的計算:
public void savePatterns(String output,Map<String,Long> map){ // 清空patternsMap patternsMap.clear(); String preItem=null; for(String p:map.keySet()){ // 單項沒有前向。不用找 if(p.lastIndexOf(",")==-1){ continue; } // 找出前向 preItem = p.substring(0, p.lastIndexOf(",")); if(map.containsKey(preItem)){ // patterns.get(p) 支持度,patterns.get(preItem)前向支持度 patternsMap.put(p, map.get(p)*1.0/map.get(preItem)); } } FPTreeDriver.createFile(patternsMap, output); }因為把頻繁項集和支持度都放入了Map中,所以這樣計算比較簡單。對照使用擴充的和沒有使用擴充的頻繁項集產生的關聯規則例如以下圖所看到的:
這裏能夠看到擴充後的關聯規則1,3和3,1 是不一樣的,其置信度一個是0.714,一個是0.8。所以能夠解釋為從1推出3的概率沒有從3推出1的概率大。舉個生活簡單的實例:買了電視機。再買遙控器的概率肯定比買了遙控器再買電視機的概率大。
可是假設全部擴充後的頻繁項集和支持度數據太大而不能全然放入內存應該怎樣操作呢。
這裏能夠使用MapReduce的思路來實現。
MapReduce實現計算置信度的思路:0. 這裏假設已經得到了擴充後的頻繁項集的支持度,並存在與HDFS文件系統上面。假設為文件A。
1. 把文件A復制一份得到文件B;2. 參考《hadoop多文件格式輸入》http://blog.csdn.net/fansy1990/article/details/26267637,設計兩個不同的Mapper,一個處理A,一個處理B。
對A的處理為直接輸出頻繁項集,輸出的key為頻繁項集,value是支持度和A的標簽;對B的處理為輸出全部的頻繁項集中項大於1的頻繁項集,其輸出的key是頻繁項集的前向(定義為頻繁項集前面n-1個項)。value是頻繁項集的後向(後向定義為頻繁項集的最後一項)和支持度和標簽。
3. 在2中不同的Mapper進行處理的數據會在Reducer中進行匯集。在Reducer中進行例如以下的處理:針對同樣的key。遍歷其value集合。假設被貼了A標簽那麽就賦值一個變量,用於做分母,假設是B標簽那麽就進行計算。計算是把B標簽的數據的支持度除以剛才A標簽的變量。得到置信度confidence,輸出的key為輸入的key+B標簽的後向,value是confidence。 比方A的輸出為 <(0,2,3),5+A>; 當中(0,2,3)為頻繁項集,是key。5+A是value。當中5是支持度。A是標簽 B中的輸出為: <(0,2,3),4+3+B> ; 當中(0,2,3,4)為頻繁項集。key是前向(0,2,3);4+3+B是value,當中4是後向,3是支持度,B是標簽; <(0,2,3),5+3+B> ; 當中(0,2,3,5)為頻繁項集。key是前向(0,2,3);5+3+B是value。當中5是後向,3是支持度,B是標簽;<(0,2,3),6+2+B>。當中(0,2,3,6)為頻繁項集,key是前向(0,2,3);6+2+B是value。當中6是後向。2是支持度,B是標簽。
那麽Reducer中匯總的數據就是:<(0,2,3),[(5+A),(4+3+B),(5+3+B),(6+2+B)>;遍歷當中的value集合,首先,把標簽A的支持度作為分母,即分母是5;接著, 遍歷B的標簽,比方(4+3+B),因為是B的標簽那麽就計算支持度除以A的分母為3/5 , 輸出為<(0,2,3,4),3/5>;接著遍歷,就可以輸出:<(0,2,3,5),3/5>; <(0,2,3,6),2/5>; 等記錄;
這裏須要註意 1)當Reducer中僅僅有A的標簽數據時。這時是不須要進行輸出的,因為這個是最大頻繁項集。不能作為不論什麽頻繁項集的前向; 2)上面的value能夠自行設計為自己定義Writable類型,而不是簡單的字符串。 3) 計算置信度的MapReduce代碼暫沒有實現,本文提供的下載是單機版的。且擴充頻繁項集是能夠放入內存的;
分享,成長,快樂
轉載請註明blog地址:http://blog.csdn.net/fansy1990
Fp關聯規則算法計算置信度及MapReduce實現思路