1. 程式人生 > >關聯規則—頻繁項集Apriori演算法

關聯規則—頻繁項集Apriori演算法

轉載地址:http://liyonghui160com.iteye.com/blog/2080531

一、前言  

            頻繁模式和對應的關聯或相關規則在一定程度上刻畫了屬性條件與類標號之間的有趣聯絡,因此將關聯規則挖掘用於分類也會產生比較好的效果。

         關聯規則就是在給定訓練項集上頻繁出現的項集與項集之間的一種緊密的聯絡。其中“頻繁”是由人為設定的一個閾值即支援度 (support)來衡量,“緊密”也是由人為設定的一個關聯閾值即置信度(confidence)來衡量的。這兩種度量標準是頻繁項集挖掘中兩個至關重 要的因素,也是挖掘演算法的關鍵所在。對項集支援度和規則置信度的計算是影響挖掘演算法效率的決定性因素,也是對頻繁項集挖掘進行改進的入口點和研究熱點。
基於關聯規則的分類主要分為以下以個步驟:
1.  對訓練資料進行預處理(包括離散化、缺失值處理等)
2.  關聯規則挖掘
     2.1  頻繁項集挖掘
     2.2  關聯規則生成
3.  規則處理
4.  對測試集進行測試

二、頻繁項集挖掘

目前頻繁項集挖掘已經有很多比較成熟的演算法,在網上也可以找到相關的優秀論文或原始碼。演算法中最經典的莫過於Apriori演算法,它可以算得上是頻 繁項集挖掘演算法的鼻祖,後續很多的改進演算法也是基於Apriori演算法的。但是遺憾的是Apriori演算法的效能實在不咋的,噹噹玩具玩玩還可以,但是即 使如此,該演算法卻是頻繁項集挖掘必須要掌握的入門演算法。
題外話:關健是要了解演算法的思想,你可以不瞭解一個東西是怎樣具體實現的,但是一定得了解它是如何出來的。這樣遇到相關的問題,你可以有一個參考的 解決方法,或者在關鍵時刻可以跟別人忽悠忽悠。當然,瞭解思想的最佳途徑就是自己動手去實現實現了,哪怕實現得不咋樣,起碼思想掌握了,也是個不小的收 獲。
下面就要具體介紹如何利用Apriori演算法進行頻繁項集挖掘了。

(1)相關概念
項集:“屬性-值”對的集合,一般情況下在實際操作中會省略屬性。
候選項集:用來獲取頻繁項集的候選項集,候選項集中滿足支援度條件的項集保留,不滿足條件的捨棄。
頻繁項集:在所有訓練元組中同時出現的次數超過人工定義的閾值的項集稱為頻繁項集。
極大頻繁項集:不存在包含當前頻繁項集的頻繁超集,則當前頻繁項集就是極大頻繁項集。
支援度:項集在所有訓練元組中同時出現的次數。
置信度:形如A->B,置信度為60%表示60%的A出現的同時也出現B。
k項集:項集中的每個項有k個“屬性-值”對的組合。

(2)兩個定理
i:連線定理。若有兩個k-1項集,每個項集按照“屬性-值”(一般按值)的字母順序進行排序。如果兩個k-1項集的前k-2個項相同,而最後一 個項不同,則證明它們是可連線的,即這個k-1項集可以聯姻,即可連線生成k項集。使如有兩個3項集:{a, b, c}{a, b, d},這兩個3項集就是可連線的,它們可以連線生成4項集{a, b, c, d}。又如兩個3項集{a, b, c}{a, d, e},這兩個3項集顯示是不能連線生成3項集的。要記住,強扭的瓜是不甜的,也結不了果的。
ii:頻繁子集定理。若一個項集的子集不是頻繁項集,則該項集肯定也不是頻繁項集。這個很好理解,舉一個例子,若存在3項集{a, b, c},如果它的2項子集{a, b}的支援度即同時出現的次數達不到閾值,則{a, b, c}同時出現的次數顯然也是達不到閾值的。因此,若存在一個項集的子集不是頻繁項集,那麼該項集就應該被無情的捨棄。倘若你捨不得,那麼這個項集就會無情 的影響你的效率以及處理器資源,所以在這時,你必須無情,斬立決!

(3)Apriori演算法流程
    1. 掃描資料庫,生成候選1項集和頻繁1項集。
    2. 從2項集開始迴圈,由頻繁k-1項集生成頻繁頻繁k項集。
           2.1  頻繁k-1項集生成2項子集,這裡的2項指的生成的子集中有兩個k-1項集。使如有3個2項頻繁集{a, b}{b, c}{c, f},則它所有的2項子集為{{a, b}{b, c}}{{a, b}{e, f}}{{b, c}{c, f}}
        2.2  對由2.1生成的2項子集中的兩個項集根據上面所述的定理 i 進行連線,生成k項集。
        2.3  對k項集中的每個項集根據如上所述的定理 ii 進行計算,捨棄掉子集不是頻繁項集即不在頻繁k-1項集中的項集。
        2.4  掃描資料庫,計算2.3步中過濾後的k項集的支援度,捨棄掉支援度小於閾值的項集,生成頻繁k項集。
    3.  噹噹前生成的頻繁k項集中只有一個項集時迴圈結束。

      關聯規則(Association Rules)是反映一個事物與其他事物之間的相互依存性和關聯性,是資料探勘的一個重要技術, 用於從大量資料中挖掘出有價值的資料項之間的相關關係。 其中關聯規則挖掘的最經典的例子就是沃爾瑪的啤酒與尿布的故事 ,通過對超市購物籃資料進行分析,即顧客放入購物籃中不同商品之間的關係來分析顧客的購物習慣,發現美國婦女們經常會叮囑丈夫下班後為孩子買尿布,30%-40%的丈夫同時會順便購買喜愛的啤酒,超市就把尿布和啤酒放在一起銷售增加銷售額。

三、基本概念

關聯規則挖掘是尋找給定資料集中項之間的有趣聯絡。如下圖所示:


 
其中,I={I1,I2,…Im}是m個不同專案的集合,集合中的元素稱為專案(Item)。專案的集合I稱為專案集合(Itemset),長度為k的項整合為k-項集。設任務相關的資料D是資料庫事務的集合,其中每個事務T是項的集合,使得 T ⊆ I 。每個事務有一個識別符號TID;設A是一個項集,事務T包含A當且僅當 A⊆I ,則關聯規則形式為A=>B(其中 A ⊂ I , B ⊂ I ,並且 A ∩ B = ∅)。
 
在關聯規則度量中有兩個重要的度量值:支援度和置信度 。對於關聯規則R:A=>B,則:
1. 支援度(suppport ): 是交易集中同時包含A和B的交易數與所有交易數之比。
Support(A=>B)=P(A∪B)=count(A∪B)/|D|
2. 置信度(confidence ): 是包含A和B交易數與包含A的交易數之比。
Confidence(A=>B)=P(B|A)=support(A∪B)/support(A)


 
  
如上圖中資料庫D,包含4個事務,項集I={I1,I2,I3,I4,I5},分析關聯規則:I1=>I4,事務1、4包含I1,事務4同時包含I1和I4。
支援度support=1/4=25%(1個事務同時包含I1和I4,共有4個事務)指 在所有交易記錄中有25%的交易記錄同時包含I1和I4專案
置信度confidence=1/2=50%(1個事務同時包含I1和I4,2個事務包含I1)指 50%的顧客在購買I1時同時還會購買I4
 
使用關聯規則對購物籃進行挖掘,通常採用兩個步驟進行: 下面將通超市購物的例子對關聯規則挖掘進行分析。
a.找出所有頻繁項集(文章中我使用Apriori演算法>=最小支援度的項集)
b.由頻繁項集產生強關聯規則(>=最小支援度和最小置信度)

四、舉例:Apriori演算法挖掘頻繁項集

        Apriori演算法是一種對有影響的挖掘布林關聯規則頻繁項集的演算法,通過演算法的連線和剪枝即可挖掘頻繁項集。 補充頻繁項集相關知識: K-項集:指包含K個項的項集; 項集的出現頻率:指包含項集的事務數,簡稱為項集的頻率、支援度計數或計數; 頻繁項集:如果項集的出現頻率大於或等於最小支援度計數閾值,則稱它為頻繁項集,其中頻繁K-項集的集合通常記作L k 。
下面直接通過例子描述該演算法:如下圖所示(注意Items已經排好序),使用Apriori演算法關聯規則挖掘資料集中的頻繁項集。(最小支援度技術為2)
 

 
具體過程如下所示:


 
具體分析結果:
第一次掃描:對每個候選商品計數得C1,由於候選{D}支援度計數為1<最小支援度計數2,故刪除{D}得頻繁1-項集合L1;
第二次掃描:由L1產生候選C2並對候選計數得C2,比較候選支援度計數與最小支援度計數2得頻繁2-項集合L2;
第三次掃描:用Apriori演算法對L2進行連線和剪枝產生候選3項集合C3的過程如下:
1.連線:
C3=L2  (連線)L2={{A,C},{B,C},{B,E},{C,E}}  {{A,C},{B,C},{B,E},{C,E}}={{A,B,C},{A,C,E},{B,C,E}}
2.剪枝:
{A,B,C}的2項子集{A,B},{A,C}和{B,C},其中{A,B}不是 2項子集L2,因此不是頻繁的,從C3中刪除;
{A,C,E}的2項子集{A,C},{A,E}和{C,E},其中{A,E}不是2項子集L2,因此不是頻繁的,從C3中刪除;
{B,C,E}的2項子集{B,C},{B,E}和{C,E},它的所有2項子集都是L2的元素,保留C3中.
經過Apriori演算法對L2連線和剪枝後產生候選3項集的集合為C3={B,C,E}. 在對該候選商品計數,由於等於最小支援度計數2,故得頻繁3-項集合L3,同時由於4-項集中僅1個,故C4為空集,演算法終止。

五、舉例:頻繁項集產生強關聯規則

強關聯規則是指:如果規則R:X=>Y滿足support(X=>Y)>=supmin(最小支援度,它 用於衡量規則需要滿足的最低重要性)且confidence(X=>Y)>=confmin(最小置信度,它表示關聯規則需要滿足的最低可靠 性)稱關聯規則X=>Y為強關聯規則,否則稱關聯規則X=>Y為弱關聯規則。


例:下圖是某日超市的購物記錄(注意Items已經排好序),使用上面敘述的Apriori演算法實現了挖掘頻繁項集,其中頻繁項集I={i1,i2,i5}為頻繁3-項集合L3,求由I產生哪些強關聯規則?(最小支援度閾值為20%,最小置信度閾值為80%)



 


I的非空子集有{i1,i2}、{i1,i5}、{i2,i5}、{i1}、{i2}和{i5}。
結果關聯規則如下,每個都列出置信度
1).i1 ∧i2=>i5 ,共10個事務;5個事務包含i1,i2;2個事務包含i1,i2和i5   confidence=2/5=40%,support=2/10=20%
2).i1 ∧i5=>i2 ,共10個事務;2個事務包含i1,i5;2個事務包括i1,i2和i5   confidence=2/2=100%,support=2/10=20%
3).i2 ∧i5=>i1 ,共10個事務;2個事務包含i2,i5;2個事務包含i1,i2和i5    confidence=2/2=100%,support=2/10=20%
4).i1=>i2 ∧i5 ,共10個事務;7個事務包含i1;2個事務包含i1,i2和i5       confidence=2/7=28%,support=2/10=20%
5).i2=>i1 ∧i5 ,共10個事務;8個事務包含i2;2個事務包含i1,i2和i5       confidence=2/8=25%,support=2/10=20%
6).i5=>i1 ∧i2 ,共10個事務;2個事務包含i5;2個事務包含i1,i2和i5       confidence=2/2=100%,support=2/10=20%
因最小置信度閾值為80%,最小支援度閾值為20%,則236規則符合要求,是頻繁項集I={i1,i2,i5}產生的強關聯規則且可以輸出。


(自己的推測:如果給定的是最小支援度計數為2,則有10個事務,最小支援度閾值supmin=2/10=20%)

在實際應用中訂單每天增加,我們採用增量的方式計算,去掉支援度的限制。

演算法實現(java):

演算法主體類:

package com.datamine.apriori;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 本程式用於頻繁集的挖掘
 * 首先用List<List<String>>型別的record將矩陣形式的資料讀入記憶體
 * 
 * 程式先求出k-1候選集,由後選集和資料庫記錄record求得滿足支援度的k-1級集合,
 * 在滿足支援度集合中求出滿足置信度的集合
 * 若滿足置信度的集合為空,程式停止
 * 否則輸出滿足自信度的集合,以及對應的支援度和置信度
 * 並由滿足支援度的k-1級集合求出候選k級集合,進入下一輪迴圈
 * 
 * 直至程式結束,輸出全部頻繁集
 * @author Administrator
 *
 */
public class Apriori {

	static boolean endTag = false;
	static Map<Integer,Integer> dCountMap = new HashMap<Integer, Integer>(); //k-1頻繁集的記數表
	static Map<Integer,Integer> dkCountMap = new HashMap<Integer, Integer>(); //k頻繁集的記數表
	static List<List<String>> record = new ArrayList<List<String>>(); //資料記錄表
//	final static double MIN_SUPPORT = 0.2; //最小支援度
//	final static double MIN_CONF = 0.8;  //最小置信度
	static double MIN_SUPPORT = 0.2; //最小支援度
	static double MIN_CONF = 0.8;  //最小置信度
	static int lable = 1; //用於輸出時的一個標記,記錄當前列印第幾級關聯集
	static List<Double> confCount = new ArrayList<Double>(); //置信度記錄表
	static List<List<String>> confItemset = new ArrayList<List<String>>(); //滿足支援度的集合
	
	/*public static void main(String[] args) throws Exception {
		
		record = new TxtReader().getRecord(); //獲取資料
		//System.out.println(record);
		List<List<String>> cItemset = findFirstCandidate(); //獲取第一次的候選集
		//System.out.println(cItemset);
		List<List<String>> lItemset = getSupportedItemset(cItemset); //獲取候選集cItemset滿足支援的集合
		
		while(endTag != true){ //只要能繼續挖掘
			
			List<List<String>> ckItemset = getNextCandidate(lItemset); //獲取下一次的候選集

			List<List<String>> lkItemset = getSupportedItemset(ckItemset); //獲取候選集ckItemset滿足支援的集合
			
			System.out.println(lkItemset);
			
			getConfidencedItemset(lkItemset,lItemset,dCountMap,dkCountMap);
			
			if(confItemset.size() != 0) //滿足置信度的集合不為空
				printConfItemset(confItemset); //列印滿足置信度的集合
			confItemset.clear(); //清空置信度集合
			
			cItemset = ckItemset;
			lItemset = lkItemset;
			
			dCountMap.clear();
			dCountMap.putAll(dkCountMap);
			
		}
		
	}*/
	
	
	public void run(List<List<String>> record2,double support,double conf){
		
		record = record2;
		MIN_SUPPORT = support;
		MIN_CONF = conf;
		
		List<List<String>> cItemset = findFirstCandidate(); //獲取第一次的候選集
		
		List<List<String>> lItemset = getSupportedItemset(cItemset); //獲取候選集cItemset滿足支援的集合
		
		while(endTag != true){ //只要能繼續挖掘
			
			List<List<String>> ckItemset = getNextCandidate(lItemset); //獲取下一次的候選集

			List<List<String>> lkItemset = getSupportedItemset(ckItemset); //獲取候選集ckItemset滿足支援的集合
			
			System.out.println(lkItemset);
			
			getConfidencedItemset(lkItemset,lItemset,dCountMap,dkCountMap);
			
			if(confItemset.size() != 0) //滿足置信度的集合不為空
				printConfItemset(confItemset); //列印滿足置信度的集合
			confItemset.clear(); //清空置信度集合
			
			cItemset = ckItemset;
			lItemset = lkItemset;
			
			dCountMap.clear();
			dCountMap.putAll(dkCountMap);
			
		}
	}

	
	/**
	 * 列印結果
	 * @param confItemset2
	 */
	private static void printConfItemset(List<List<String>> confItemset2) {
		
		System.out.println("*******************頻繁模式挖掘結果***********************");
		for(int i = 0; i < confItemset2.size();i++){
			int j =0;
			for(j = 0; j < confItemset2.get(i).size()-3;j++)
				System.out.print(confItemset2.get(i).get(j)+" ");
			System.out.print("-->");
			System.out.print(confItemset2.get(i).get(j++));
			System.out.print(" 相對支援度:"+confItemset2.get(i).get(j++));
			System.out.print(" 自信度:"+confItemset2.get(i).get(j++)+"\n");
		}
		
	}

	/**
	 * 根據4個引數求出滿足自信度的集合
	 * @param lkItemset k項候選集
	 * @param lItemset  k-1項集
	 * @param dCountMap2 k-1項頻繁項紀錄數
	 * @param dkCountMap2 k項頻繁項紀錄數
	 */
	private static void getConfidencedItemset(List<List<String>> lkItemset,
			List<List<String>> lItemset, Map<Integer, Integer> dCountMap2,
			Map<Integer, Integer> dkCountMap2) {
		
		for(int i = 0;i<lkItemset.size();i++){
			
			getConfItem(lkItemset.get(i),lItemset,dkCountMap2.get(i),dCountMap2);
		}
		
	}

	/**
	 * 檢驗集合list是否滿足最低自信度要求
	 * 若滿足則在全域性變數confiItemset新增list
	 * 不滿足返回null
	 * @param list k頻繁項集中第i個元組
	 * @param lItemset k-1項集
	 * @param count  k項集第i個元組計數
	 * @param dCountMap2 k-1項頻繁項紀錄map
	 */
	private static void getConfItem(List<String> list,
			List<List<String>> lItemset, Integer count,
			Map<Integer, Integer> dCountMap2) {
		
		for(int i = 0;i < list.size() ;i++){
			
			List<String> testList = new ArrayList<String>();
			
			for(int j = 0; j <list.size(); j++)
				if( i !=j )
					testList.add(list.get(j));
			//查詢testList中的內容在lItemset的位置
			int index = findConf(testList,lItemset);
			Double conf = count*1.0/dCountMap2.get(index);
			
			if(conf > MIN_CONF){
				testList.add(list.get(i));
				Double relativeSupport = count*1.0 /(record.size() - 1);
				testList.add(relativeSupport.toString());
				testList.add(conf.toString());
				confItemset.add(testList);
			}
			
		}
		
	}

	/**
	 * 查詢testList中的內容在lItemset的位置
	 * @param testList
	 * @param lItemset
	 * @return
	 */
	private static int findConf(List<String> testList,
			List<List<String>> lItemset) {
		
		for(int i = 0; i < lItemset.size(); i++){
			
			boolean notHaveTag = false;
			for(int j = 0;j < testList.size();j++){
				if(haveThisItem(testList.get(j),lItemset.get(i))==false){
					notHaveTag = true;
					break;
				}
			}
			if(notHaveTag == false)
				return i;
		}
		
		return -1;
	}

	/**
	 * 檢驗list中是否包含s
	 * @param s
	 * @param list
	 * @return boolean
	 */
	private static boolean haveThisItem(String s, List<String> list) {
		
		for(int i = 0; i<list.size() ;i++)
			if(s.equals(list.get(i)))
				return true;
		return false;
		
	}

	/**
	 * 根據cItemset求得下一次的候選集合組,求出候選集合組中每一個集合的元素的個數比cItemset中的集合元素大1
	 * @param cItemset 
	 * [[I1], [I2], [I5], [I4], [I3]]
	 * @return nextItemset 
	 * [[I1, I2], [I1, I5], [I1, I4], [I1, I3], [I2, I5], [I2, I4], [I2, I3], [I5, I4], [I5, I3], [I4, I3]]
	 */
	private static List<List<String>> getNextCandidate(
			List<List<String>> cItemset) {
		
		List<List<String>> nextItemset = new ArrayList<List<String>>();
		
		for(int i =0;i<cItemset.size();i++){
			
			List<String> tempList = new ArrayList<String>(); 
			
			//tempList先存入一項
			for(int k = 0;k<cItemset.get(i).size();k++)
				tempList.add(cItemset.get(i).get(k));   
			
			//接下來每次新增下一項的一個元素
			for(int h=i+1;h<cItemset.size();h++){
				for(int j = 0;j<cItemset.get(h).size();j++){
					
					tempList.add(cItemset.get(h).get(j));
					
					//tempList的子集全部在cItemset中
					if(isSubsetInC(tempList,cItemset)){
						
						List<String> copyValueHelpList = new ArrayList<String>();
						for(int p =0;p<tempList.size();p++)
							copyValueHelpList.add(tempList.get(p));
						if(isHave(copyValueHelpList,nextItemset))
							nextItemset.add(copyValueHelpList);
					}
					tempList.remove(tempList.size()-1);
				}
			}
			
		}
		
		return nextItemset;
	}

	/**
	 * 檢驗nextItemset中是否包含copyValueHelpList
	 * @param copyValueHelpList
	 * @param nextItemset
	 * @return boolean
	 */
	private static boolean isHave(List<String> copyValueHelpList,
			List<List<String>> nextItemset) {
		
		for(int i =0;i<nextItemset.size();i++)
			if(copyValueHelpList.equals(nextItemset.get(i)))
				return false;
		return true;
	}

	/**
	 * 檢驗tempList是不是cItemset的子集
	 * @param tempList
	 * @param cItemset
	 * @return boolean
	 */
	private static boolean isSubsetInC(List<String> tempList,
			List<List<String>> cItemset) {

		boolean haveTag = false;
		
		for(int i = 0;i<tempList.size();i++){
			
			List<String> testList = new ArrayList<String>();
			for(int j = 0;j<tempList.size();j++)
				if(i != j )
					testList.add(tempList.get(j));  //testList記錄tempList中k-1級頻繁集
			
			for(int k = 0;k < cItemset.size();k++){
				if(testList.equals(cItemset.get(k))){ //子集存在於k-1頻繁集中
					haveTag = true;
					break;
				}
			}
			
			if(haveTag == false) //其中一個子集不再k-1頻繁集中
				return false;
		}
		
		return haveTag;
	}

	/** 返回候選集中滿足最低支援度的集合
	 * @param cItemset
	 * [[I1, I2], [I1, I5], [I1, I4], [I1, I3], [I2, I5], [I2, I4], [I2, I3], [I5, I4], [I5, I3], [I4, I3]]
	 * @return supportedItemset
	 * [[I1, I2], [I1, I5], [I1, I3], [I2, I5], [I2, I4], [I2, I3], [I4, I3]]
	 */
	private static List<List<String>> getSupportedItemset(
			List<List<String>> cItemset) {
		
		boolean end = true;
		List<List<String>> supportedItemset = new ArrayList<List<String>>();
		int k = 0;
		
		for(int i = 0; i < cItemset.size(); i++){
			
			int count = countFrequent(cItemset.get(i)); //統計記錄數
			//System.out.println(cItemset.get(i)+" " +count);
			
			if(count >= MIN_SUPPORT*(record.size()-1)){ //count值大於支援度與記錄數的乘積,即滿足支援度要求
				if(cItemset.get(0).size() == 1)
					dCountMap.put(k++, count);
				else
					dkCountMap.put(k++, count);
				supportedItemset.add(cItemset.get(i));
				end = false;
			}
		}
		
		endTag = end;
		return supportedItemset;
	}

	/**
	 * 統計資料庫記錄record中出現list中的集合的個數
	 * @param list
	 * @return  頻繁項集 個數
	 */
	private static int countFrequent(List<String> list) {
		
		int count = 0;
		for(int i = 1; i<record.size(); i++){
			
			boolean notHaveThisList = false;
			
			for(int k = 0;k<list.size();k++){
				
				boolean thisRecordHave = false;
				
				for(int j = 1;j<record.get(i).size();j++){
					if(list.get(k).equals(record.get(i).get(j)))
						thisRecordHave = true;
				}
				
				if(!thisRecordHave){ // 掃描一遍記錄表的一行,發現list.get(i)不在記錄表的第j行中,即list不可能在j行中
					notHaveThisList = true;
					break;
				}
			}
			
			if(notHaveThisList == false)
				count++;
		}
		
		return count;
	}

	/**
	 * 根據資料庫記錄求出第一次候選集
	 * @return 返回一級候選集
	 */
	private static List<List<String>> findFirstCandidate() {
		
		List<List<String>> tableList = new ArrayList<List<String>>();
		List<String> lineList = new ArrayList<String>();
		
		int size = 0;
		for(int i = 1; i < record.size(); i++){
			for(int j = 1; j<record.get(i).size();j++){
				if(lineList.isEmpty())
					lineList.add(record.get(i).get(j));
				else{
					boolean haveThisItem = false;
					size = lineList.size();
					for(int k = 0; k<size;k++){
						if(lineList.get(k).equals(record.get(i).get(j))){
							haveThisItem = true;
							break;
						}
					}
					if(haveThisItem == false)
						lineList.add(record.get(i).get(j));
				}
			}
		}
		// [I1, I2, I5, I4, I3]
		// System.out.println(lineList);
		
		for(int i = 0; i<lineList.size();i++){
			List<String> helpList = new ArrayList<String>();
			helpList.add(lineList.get(i));
			tableList.add(helpList);
		}
		// [[I1], [I2], [I5], [I4], [I3]]
		// System.out.println(tableList);
		
		return tableList;
	}
	
	
}

測試資料讀取類:

package com.datamine.apriori;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

/**
 * 本程式用於讀取矩陣型的記錄資料,並轉換為List<List<String>> 格式資料
 * @author Administrator
 *
 */
public class TxtReader {

	public List<List<String>> getRecord() throws Exception {
		
		List<List<String>> record = new ArrayList<List<String>>();
		
		String encoding = "GBK"; //字元編碼 解決中文亂碼問題
		String simple = new File("").getAbsolutePath() + File.separator + "data\\Apriori.txt";
		File file = new File(simple);
		
		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、NO
					if(lineString[i].endsWith("T") || lineString[i].endsWith("YES"))
						lineList.add(record.get(0).get(i));  //儲存 T或者YES對應的頭(也就是商品)
					else if (lineString[i].endsWith("F") || lineString[i].endsWith("NO"))
						; //F、NO記錄不儲存   :當為F、NO時,說明沒有購買響應的商品
					else
						lineList.add(lineString[i]);
				}
				record.add(lineList);
			}
			read.close();
		}else{
			System.out.println("找不到 指定的檔案!");
		}
		return record;
	}

}

程式入口類:
package com.datamine.apriori;

import java.util.List;


public class TestApriori {

	public static void main(String[] args) throws Exception {
		
		//輸入資料
		TxtReader reader = new TxtReader();
		List<List<String>> record = reader.getRecord();
		//最小支援度
		double support = 0.2;
		//最小置信度
		double conf = 0.8;
	
		Apriori apriori = new Apriori();

		apriori.run(record, support, conf);
	}

}

實驗資料與結果:

實驗資料:

TID I1 I2 I3 I4 I5
T100 T T F F T
T200 T T F F F
T300 F T F T F
T400 T T F T F
T500 T F T F F
T600 T T T F T
T700 T T T F F
T800 F T F F T
T900 F T T T F
T1000 F F T T F

實驗結果:
[[I1, I2], [I1, I5], [I1, I3], [I2, I5], [I2, I4], [I2, I3], [I4, I3]]
*******************頻繁模式挖掘結果***********************
I1 -->I2 相對支援度:0.5 自信度:0.8333333333333334
I5 -->I2 相對支援度:0.3 自信度:1.0
[[I1, I2, I5], [I1, I2, I3]]
*******************頻繁模式挖掘結果***********************
I1 I5 -->I2 相對支援度:0.2 自信度:1.0
[]