Apriori演算法學習和java實現

來源:互聯網
上載者:User

標籤:資料採礦   關聯規則   apriori演算法實現   頻繁項集   

關聯規則挖掘可以發現大量資料中項集之間有趣的關聯或相關聯絡。一個典型的關聯規則挖掘例子是購物籃分析,即通過發現顧客放入其購物籃中的不同商品之間的聯絡,分析顧客的購物習慣,從而可以協助零售商指定營銷策略,引導銷售等。國外有"啤酒與尿布"的故事,國內有泡麵和火腿的故事。本文以Apriori演算法為例介紹關聯規則挖掘並以java實現。

什麼是關聯規則:

對於記錄的集合D和記錄A,記錄B,A,B屬於D:  A--->B  [support(A->B)=p(AUB) ,confidence(A->B)=p(B|A) ]

關聯規則的表示形式:

泡麵 ------>火腿[support=0.2,confidence=0.8]

規則的支援度和信賴度是兩個規則興趣度度量,它們分別反映發現規則的有用性和確定性。上式表示同時購買泡麵和火腿的記錄佔全部記錄的2%(實際應該沒這麼多的,不然天天吃泡麵),信賴度0.8表示在購買泡麵的記錄中,有80%的人同時購買火腿(反正我就是屬於80%的。

如果挖掘的關聯規則滿足最小支援閾值和最小信賴度閾值,則稱關聯規則是有趣的。

重要性質:頻繁項集的所有非空子集都必須是頻繁的。(一個集合如果不能通過測試,則它的所有超集也不能通過測試)


Apriori演算法思想:逐層搜尋的迭代方法,首先尋找1-項頻繁集的集合,集合記做L1, L1用於尋找兩項頻繁集合L2,L2用於尋找L3,如此下去,直到不能找K項頻繁集合。

Apriori演算法迭代的兩個階段:

 1串連步;為找L(k) ,通過將L(k-1)與自身串連產生候選K項集的集合。

2減枝步;根據項的支援度計數去掉非頻繁的候選集合,確定頻繁集反覆迭代直到不能產生滿足最小支援度的集合為止。

Apriori重要性質:頻繁項集的所有非空子集都必須是頻繁的在減枝中的應用就在於,對於候選集只要它不是頻繁的,就可以刪除掉,這樣大大減少資料量。

下面直接上演算法流程圖:


下面舉例說明:



下面直接貼代碼:部分地方寫的有點冗餘,程式有點長的主要原因是向控制台輸出挖掘的過程,這樣便於理解演算法的挖掘過程

但是演算法思路是清晰的,基本上一個while就能搞定。


package cluster;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.HashSet;import java.util.Iterator;import java.util.List;/** * Apriori演算法實現 最大模式挖掘,涉及到支援度,但沒有信賴度計算 * @author push_pop * */public class AprioriMyself {private static final double MIN_SUPPROT = 0.2;//最小支援度private static boolean endTag = false;//迴圈狀態static List<List<String>> record = new ArrayList<List<String>>();//資料集public static void main(String args[]){//*************讀取資料集**************record = getRecord();//控制台輸出記錄System.out.println("以矩陣形式讀取資料集record");for(int i=0;i<record.size();i++){List<String> list= new ArrayList<String>(record.get(i));for(int j=0;j<list.size();j++){System.out.print(list.get(j)+" ");}System.out.println();}//************擷取候選1項集**************List<List<String>> CandidateItemset = findFirstCandidate();//控制台輸出1項候選集System.out.println("第一次掃描後的1級 備選集CandidateItemset");for(int i=0;i<CandidateItemset.size();i++){List<String> list = new ArrayList<String>(CandidateItemset.get(i));for(int j=0;j<list.size();j++){System.out.print(list.get(j)+" ");}System.out.println();}//************擷取頻繁1項集***************List<List<String>> FrequentItemset = getSupprotedItemset(CandidateItemset);//控制台輸出1項頻繁集System.out.println("第一次掃描後的1級 頻繁集FrequentItemset");for(int i=0;i<FrequentItemset.size();i++){List<String> list = new ArrayList<String>(FrequentItemset.get(i));for(int j=0;j<list.size();j++){System.out.print(list.get(j)+" ");}System.out.println();}//***************迭代過程**************while(endTag!=true){//**********串連操作****由k-1項頻繁集      擷取      候選k項集**************List<List<String>> nextCandidateItemset = getNextCandidate(FrequentItemset);System.out.println("掃描後備選集");for(int i=0;i<nextCandidateItemset.size();i++){List<String> list = new ArrayList<String>(nextCandidateItemset.get(i));for(int j=0;j<list.size();j++){System.out.print(list.get(j)+" ");}System.out.println();}//**************減枝操作***由候選k項集       擷取     頻繁k項集****************List<List<String>> nextFrequentItemset = getSupprotedItemset(nextCandidateItemset);System.out.println("掃描後頻繁集");for(int i=0;i<nextFrequentItemset.size();i++){List<String> list = new ArrayList<String>(nextFrequentItemset.get(i));for(int j=0;j<list.size();j++){System.out.print(list.get(j)+" ");}System.out.println();}//*********如果迴圈結束,輸出最大模式**************if(endTag == true){System.out.println("Apriori演算法--->頻繁集");for(int i=0;i<FrequentItemset.size();i++){List<String> list = new ArrayList<String>(FrequentItemset.get(i));for(int j=0;j<list.size();j++){System.out.print(list.get(j)+" ");}System.out.println();}}//****************下一次迴圈初值********************CandidateItemset = nextCandidateItemset;FrequentItemset = nextFrequentItemset;}}/** * 讀取txt資料 * @return */public static List<List<String>> getRecord() {List<List<String>> record = new ArrayList<List<String>>();try {String encoding = "GBK"; // 字元編碼(可解決中文亂碼問題 )File file = new File("simple.txt");if (file.isFile() && file.exists()) {InputStreamReader read = new InputStreamReader(new FileInputStream(file), encoding);BufferedReader bufferedReader = new BufferedReader(read);String lineTXT = null;while ((lineTXT = bufferedReader.readLine()) != null) {//讀一行檔案String[] lineString = lineTXT.split("");List<String> lineList = new ArrayList<String>();for (int i = 0; i < lineString.length; i++) {//處理矩陣中的T、F、YES、NOif (lineString[i].endsWith("T")|| lineString[i].endsWith("YES"))lineList.add(record.get(0).get(i));else if (lineString[i].endsWith("F")|| lineString[i].endsWith("NO"));// F,NO記錄不儲存elselineList.add(lineString[i]);}record.add(lineList);}read.close();} else {System.out.println("找不到指定的檔案!");}} catch (Exception e) {System.out.println("讀取檔案內容操作出錯");e.printStackTrace();}return record;}/** * 有當前頻繁項集自串連求下一次候選集 * @param FrequentItemset * @return */private static List<List<String>> getNextCandidate(List<List<String>> FrequentItemset) {List<List<String>> nextCandidateItemset = new ArrayList<List<String>>();for (int i=0; i<FrequentItemset.size(); i++){HashSet<String> hsSet = new HashSet<String>();HashSet<String> hsSettemp = new HashSet<String>();for (int k=0; k< FrequentItemset.get(i).size(); k++)//獲得頻繁集第i行hsSet.add(FrequentItemset.get(i).get(k));int hsLength_before = hsSet.size();//添加前長度hsSettemp=(HashSet<String>) hsSet.clone();for(int h=i+1; h<FrequentItemset.size(); h++){//頻繁集第i行與第j行(j>i)串連   每次添加且添加一個元素組成    新的頻繁項集的某一行,   hsSet=(HashSet<String>) hsSettemp.clone();//!!!做串連的hasSet保持不變for(int j=0; j< FrequentItemset.get(h).size();j++)hsSet.add(FrequentItemset.get(h).get(j));int hsLength_after = hsSet.size();if(hsLength_before+1 == hsLength_after && isSubsetOf(hsSet,record)==1 && isnotHave(hsSet,nextCandidateItemset)){//如果不相等,表示添加了1個新的元素,再判斷其是否為record某一行的子集     若是則其為  候選集中的一項Iterator<String> itr = hsSet.iterator();List<String>  tempList = new ArrayList<String>();while(itr.hasNext()){String Item = (String) itr.next();tempList.add(Item);}nextCandidateItemset.add(tempList);}}}return nextCandidateItemset;}/** * 判斷新添加元素形成的候選集是否在  新的候選集中 * @param hsSet * @param nextCandidateItemset * @return */private static boolean isnotHave(HashSet<String> hsSet,List<List<String>> nextCandidateItemset) {// TODO Auto-generated method stubList<String>  tempList = new ArrayList<String>();Iterator<String> itr = hsSet.iterator();while(itr.hasNext()){String Item = (String) itr.next();tempList.add(Item);}for(int i=0; i<nextCandidateItemset.size();i++)if(tempList.equals(nextCandidateItemset.get(i)))return false;return true;}/** * 判斷hsSet是不是record2中的某一記錄子集 * @param hsSet * @param record2 * @return */private static int isSubsetOf(HashSet<String> hsSet,List<List<String>> record2) {//hsSet轉換成ListList<String>  tempList = new ArrayList<String>();Iterator<String> itr = hsSet.iterator();while(itr.hasNext()){String Item = (String) itr.next();tempList.add(Item);}for(int i=1;i<record.size();i++){List<String>  tempListRecord = new ArrayList<String>();for(int j=1;j<record.get(i).size();j++)tempListRecord.add(record.get(i).get(j));if(tempListRecord.containsAll(tempList))return 1;}return 0;}/** * 由k項候選集剪枝得到k項頻繁集 * @param CandidateItemset * @return */private static List<List<String>> getSupprotedItemset(List<List<String>> CandidateItemset) {// TODO Auto-generated method stubboolean end = true;List<List<String>> supportedItemset = new ArrayList<List<String>>();int k = 0;for (int i = 0; i < CandidateItemset.size(); i++){int count = countFrequent(CandidateItemset.get(i));//統計記錄數if (count >= MIN_SUPPROT * (record.size()-1)){supportedItemset.add(CandidateItemset.get(i));end = false;}}endTag = end;//存在頻繁項集則不會結束if(endTag==true)System.out.println("無滿足支援度項集,結束串連");return supportedItemset;}/** * 統計record中出現list集合的個數 * @param list * @return */private static int countFrequent(List<String> list) {// TODO Auto-generated method stubint count = 0;for(int i = 1; i<record.size(); i++) {boolean notHaveThisList = false;for (int k=0; k < list.size(); k++){//判斷record.get(i)是否包含listboolean thisRecordHave = false;for(int j=1; j<record.get(i).size(); j++){if(list.get(k).equals(record.get(i).get(j)))//list。get(k)在record。get(i)中能找到thisRecordHave = true;}if(!thisRecordHave){//只要有一個list元素找不到,則退出其餘元素比較,進行下一個record。get(i)比較notHaveThisList = true;break;}}if(notHaveThisList == false)count++;}return count;}/** * 獲得一項候選集 * @return */private static List<List<String>> findFirstCandidate() {// TODO Auto-generated method stubList<List<String>> tableList = new ArrayList<List<String>>();HashSet<String> hs  = new HashSet<String>();for (int i = 1; i<record.size(); i++){  //第一行為商品資訊for(int j=1;j<record.get(i).size();j++){hs.add(record.get(i).get(j));}}Iterator<String> itr = hs.iterator();while(itr.hasNext()){List<String>  tempList = new ArrayList<String>();String Item = (String) itr.next();tempList.add(Item);tableList.add(tempList);}return tableList;}}





Apriori演算法的缺陷也是很明顯的:

1 .若資料量較大,將大量的候選集。N個頻繁1項集可能產生(N-1)*N/2個候選2項集

 2   資料庫需要多邊掃描,頻繁集每自串連一次,就要重新掃面一次資料。

關於其改進將在下一篇部落格寫出--不產生候選集的關聯規則挖掘演算法FPTree  

Apriori演算法學習和java實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.