Weka学习 Apriori算法if( !m_car)

来源:互联网 发布:大数据泄露 编辑:程序博客网 时间:2024/05/29 03:49

  weka里Apriori算法涉及两篇文章,一篇是《Fast Algorithms for Mining Association Rules in Large Databases》 另外一篇《Integrating Classification and Association Rule Mining》 。在算法里区别体现在 m_car变量是否为真。 这一篇先说if( !m_car) 情况。

 算法入口函数:public void buildAssociations(Instances instances)。

下面是部分代码示例: 

  if(!m_car){        // Find large itemsets and rules        findLargeItemSets();        if (m_significanceLevel != -1 || m_metricType != CONFIDENCE)             findRulesBruteForce();        else            findRulesQuickly();      }      else{          findLargeCarItemSets();          findCarRulesQuickly();      }

  根据上面步骤,可以生成 m_allTheRules。例如,规则 P{A=>B}存在m_allTheRules里面就是 m_allTheRules[0]=A,m_allTheRules[1]=B,m_allTheRules[2]=P.

m_allTheRules[0] m_allTheRules[1] m_allTheRules[2] 分别又是三个数组,存了所有的规则。

  先看 findLargeItemSets() 得到所有满足m_support的大集合。

 kSets = AprioriItemSet.singletons(m_instances);//Step 1.1
    AprioriItemSet.upDateCounters(kSets,m_instances););//Step 1.2    kSets = AprioriItemSet.deleteItemSets(kSets, necSupport, m_instances.numInstances()););//Step 1.3    if (kSets.size() == 0)      return;    do {      m_Ls.addElement(kSets);      kMinusOneSets = kSets;      kSets = AprioriItemSet.mergeAllItemSets(kMinusOneSets, i, m_instances.numInstances());//Step 1.4      hashtable = AprioriItemSet.getHashtable(kMinusOneSets, kMinusOneSets.size());//Step 1.5      m_hashtables.addElement(hashtable);      kSets = AprioriItemSet.pruneItemSets(kSets, hashtable););//Step 1.6      AprioriItemSet.upDateCounters(kSets, m_instances);//Step 1.7      kSets = AprioriItemSet.deleteItemSets(kSets, necSupport, m_instances.numInstances());//Step 1.8      i++;    } while (kSets.size() > 0);


PS:kSets是一个FastVector,由于weka编写的时间较久,可能还没有ArrayList类型。为了提快速度,没有 用Vector变量而是自己实现了一个数组。
 上述代码涉及到如下几个过程:

Step 1.1:把instances换成另外一种类型的矩阵存放。比如一共有两个属性,age{young,old},sex{m,f} 。有两个实例分别是{young ,m}和{old,f}得到的kSets={{0,-1},{1,-1},{-1,0},{-1,1}}并统计了每个item的数量,每个类似{0,-1}的item都用AprioriItemSet封装;

Step1.2&Step1.3:

 得到一个1-itemset(也就是说集合里的每个集合大小为1)并且统计出出现的次数。从而得到 L1,接着利用L1生成2-itemset。具体怎么样生成需要看

Step1.4  :

kSets = AprioriItemSet.mergeAllItemSets(kMinusOneSets, i, m_instances.numInstances());

public static FastVector mergeAllItemSets(FastVector itemSets, int size,     int totalTrans) {    FastVector newVector = new FastVector();    ItemSet result;    int numFound, k;    for (int i = 0; i < itemSets.size(); i++) {      ItemSet first = (ItemSet)itemSets.elementAt(i);    out:      for (int j = i+1; j < itemSets.size(); j++) {ItemSet second = (ItemSet)itemSets.elementAt(j);result = new AprioriItemSet(totalTrans);result.m_items = new int[first.m_items.length];// Find and copy common prefix of size 'size'numFound = 0;k = 0;while (numFound < size) {  if (first.m_items[k] == second.m_items[k]) {    if (first.m_items[k] != -1)       numFound++;    result.m_items[k] = first.m_items[k];  } else     break out;  k++;}
// Check differencewhile (k < first.m_items.length) {  if ((first.m_items[k] != -1) && (second.m_items[k] != -1))    break;  else {    if (first.m_items[k] != -1)      result.m_items[k] = first.m_items[k];    else      result.m_items[k] = second.m_items[k];  }  k++;}if (k == first.m_items.length) {  result.m_counter = 0;  newVector.addElement(result);}      }    }    return newVector;  }


取出两个ItemSet first ,ItemSet second ,第一步,检查前size-1(如果size为0,则不检查)项是否相等,如果相等,那么ItemSet得到前size-1项,在看第size项,如果在同一位置不一样,则没法合并(同一属性对应的值没法合并,比如age{young,old}的young和old没法合并。如果位置不一样 则可以合并。这样可以保证每次增长1。

 

Step1.5:

  hashtable = AprioriItemSet.getHashtable(kMinusOneSets, kMinusOneSets.size());这步很简单 把每个ItemSet和出现的次数 存成一个<K,V>的Map。方便后面的Step1.6

Step1.6:

public static FastVector pruneItemSets(FastVector toPrune, Hashtable kMinusOne) {    FastVector newVector = new FastVector(toPrune.size());    int help, j;    for (int i = 0; i < toPrune.size(); i++) {      ItemSet current = (ItemSet)toPrune.elementAt(i);      for (j = 0; j < current.m_items.length; j++)if (current.m_items[j] != -1) {  help = current.m_items[j];  current.m_items[j] = -1;  if (kMinusOne.get(current) == null) {    current.m_items[j] = help;    break;  } else{     current.m_items[j] = help;          }}      if (j == current.m_items.length) newVector.addElement(current);    }    return newVector;  }

这个也很明了,对于toPrune中的每个K-ItemSet。必须保证它的K-1子集都存在kMinueOne里。最后j==current.m_items.length 就保证了这一点 所以才会newVector.addElement(current);最后返回newVector。
step1.7和1.8比较简单,就是根据实例统计每个ItemSet的次数(PS:根据论文可以知道用的算法是apriori而不是用的aprioritid)