如果看了《Fast Algorithms for Mining Association Rules in Large Databases》,會發現對於 findLargeItemSets 來說,有兩種算法。第一種就是Weka用的 apriori,另外一種叫做AprioriTid.兩者殊途同歸,最後得到相同的結果。往下深究,會發現其實區別僅僅在對新產生的集合每一項的Support更新上面。我下面簡單介紹兩者之前的不同點。
Apriori:每一步生成的Candidate。用Database(或者說是Instances)來更新Support。對於每一個Instance,如果它所包含的子集存在於Candidate中,那麼就對Candidate該項+1 。(論文裏說 對每一個Item hash。其實就是這個意思)。
AprioriTid:Database(Instances)只會用到一次。這裏,對於每一個instance。會產生一個集合的集合。比如instance={i1,i2,i3}那麼會產生{{i1},{i2},{i3}}.然後可以用一個數組或者一個Map將<TID,SetOfItemSet>存放起來,由於TID一般爲數字,因此我的算法裏用的是一個數組TIDs。我對於算法的理解是:對於每一個TID,維持一個和CandidateK同步的K-SetOfItemSet,如果對於K-SetOfItemSet中的ItemSet存在於CandidateK中,那麼ItemSet.count++。這裏有一個提高算法速度的方法,將<TID,SetOfItemSet>中Suport<m_support的刪除,因爲這些項不可能產生與LargeK中。總結起來,也就是說對於每一個<TID,SetOfItemSet>,它維護的是LargeK的子集。(哈,這也是我邊寫邊總結出來的)。之所以這和Apriori殊途同歸是因爲:首先對於每一個<TID,SetOfItemSet>,她每一次產生的集合都是Instances[TID]的子集。而它每次刪除的都是一定不會出現在LargeK中的ItemSet。綜上得證。
下面是我實現的AprioriTid,經測試與Weka產生的結果一樣。
if(!m_car){
// Find large itemsets and rules
//findLargeItemSets();
findLargeItemSetsTID();
public void findLargeItemSetsTID() throws Exception { FastVector kMinusOneSets, kSets; FastVector kMinusOneTids,kTids; FastVector kCandidateSets; Hashtable hashtable; int necSupport, necMaxSupport,i = 0; // Find large itemsets // minimum support necSupport = (int)(m_minSupport * (double)m_instances.numInstances()+0.5); necMaxSupport = (int)(m_upperBoundMinSupport * (double)m_instances.numInstances()+0.5); kSets = AprioriItemSet.singletons(m_instances); AprioriItemSet.upDateCounters(kSets,m_instances); kTids=AprioriItemSet.singletonsTID(m_instances);//利用database生成1-Tids kSets = AprioriItemSet.deleteItemSets(kSets, necSupport, m_instances.numInstances()); if (kSets.size() == 0) return; do { m_Ls.addElement(kSets); kMinusOneSets = kSets; kMinusOneTids=kTids; /** * 下面四行代碼生成了論文裏的Ck。 */ kMinusOneTids=AprioriItemSet.pruneItemSetsTID(kMinusOneTids, kMinusOneSets);//根據kMinusOneSets刪除kMinusOneTids中不是Large的項 kSets = AprioriItemSet.mergeAllItemSets(kMinusOneSets, i, m_instances.numInstances()); hashtable = AprioriItemSet.getHashtable(kMinusOneSets, kMinusOneSets.size()); m_hashtables.addElement(hashtable); kSets = AprioriItemSet.pruneItemSets(kSets, hashtable); AprioriItemSet.upDateCountersTID(kSets,kMinusOneTids,kTids,i,m_instances.numInstances());//用的是論文裏的AprioriTID // AprioriItemSet.upDateCounters(kSets, m_instances);//這用的是論文裏的Apriori。 kSets = AprioriItemSet.deleteItemSets(kSets, necSupport, m_instances.numInstances()); i++; } while (kSets.size() > 0); }
public static FastVector singletonsTID(Instances instances) throws Exception { FastVector setOfItemSets = new FastVector(); Enumeration enu=instances.enumerateInstances(); while(enu.hasMoreElements()) { Instance instance=(Instance) enu.nextElement(); FastVector tid=new FastVector(); /** * 對於每一個TID,把所有出現的Item都生成一個集合存在 FastVector tid 中。 */ for(int i=0;i<instance.numAttributes();i++) { ItemSet current; current = new AprioriItemSet(instances.numInstances()); current.m_items = new int[instances.numAttributes()]; for(int j=0;j<current.m_items.length;j++) current.m_items[j]=-1; current.m_items[i]=(int) instance.value(i); tid.addElement(current); } setOfItemSets.addElement(tid); } return setOfItemSets; }
public static void upDateCountersTID(FastVector kSets,
FastVector kMinusOneTids, FastVector kTids,int i,int totalTrans) {
FastVector newSets = AprioriItemSet.mergeAllItemSetsTID(kMinusOneTids, i, totalTrans);
Enumeration enu=newSets.elements();
while(enu.hasMoreElements())
{
FastVector tid=(FastVector) enu.nextElement();
FastVector newTid=new FastVector();
Enumeration enuTID=tid.elements();
while(enuTID.hasMoreElements())
{
ItemSet cur=(ItemSet) enuTID.nextElement();
for(int j=0;j<kSets.size();j++)
{
ItemSet item=(ItemSet) kSets.elementAt(j);
if(cur.equals(item))
{
item.m_counter++;
cur.m_counter++;
newTid.addElement(cur);
break;
}
}
}
if(newTid.size()>0)kTids.addElement(newTid);
}
}
以上就不一一解釋了。太晚了。該睡覺了。相信看了之前我對Apriori和AprioriTid的差別的分析。代碼很容易理解。