Apriori算法的Java实现

Apriori算法是数据挖掘中十分经典的算法,在使用MapReduce 对其进行之前,先试着用java写一个简单的程序。
1.算法流程及伪代码描述

1.1 从数据文件data.txt 中按照文件的格式读入数据
data.txt:
T100        I1        I2        I5
T200        I2        I4
T300        I2        I3
T400        I1        I2        I4
T500        I1        I3
T600        I2        I3
T700        I1        I3
T800        I1        I2        I3        I5
T900        I1        I2        I3


1.2 将每一个Item 作为一个项集,并 统计出它在所有 输入数据文件中出现的次数
即得到:

I1 : 6 ,  I2 : 6,  I3 : 6 , I4 : 2 , I5 : 2
上面的数据相当于 是 C(k-1) 即 , 候选集 C k-1 :此处仅仅是抽象理解,以为这个是 第一次读入数据 ,
不过要是泛化了思考的话,可以理解为 在多次迭代中的第 C k-1 次,
这样的话,后续的步骤 就是 从 C k-1 -> L k-1 -> C k-> L k 

其中C 代表的是候选集的描述, 即 candidate ,
而L表示的是 频繁项集 。

1.3  然后,设定绝对支持度为 3, 
这样的话,就可以将 I4 ,I5 它们在整个 数据集中出现的次数是 2 要小于最小支持度,
所以在 Ck-1 -> Lk-1 (Lk-1 为第 k-1 次 ,筛选出来的频繁项集) 的时候,I4 , I5 是被排除的。

得到 Lk-1 :

I1: 6 , I2 : 6 , I3: 6

1.4 
这一步骤中要进行的是,从Lk-1 -> Ck ,也就是 对Lk-1 中的数据进行 连接
然后连接后的集合就是 第K次的候选项集了
但是这里的连接需要满足下面的条件才可以的。

比如说,将 位于 集合 Lk-1 中的两个 集合  l1 , l2 进行 连接的话,
l1 ,l2 必须满足下面的条件:
1.  Length(l1 ) = length (l2)
2. differentElementNumber( l1, l2 ) = 1
3. l1 + x => l3 (对这个操作的解释是: 讲 l2 中唯一一个不同于 l1 的元素 归并到 l1 中之后 得到的新的集合 l3)
任意l3 的子集 都必须属于 Lk-1 对应的集合中

这个地方举个例子说明一下:
就是 假定 Lk-1 中的记录如下:
{I1, I2} ->l1 
{I1,I3}->l2
{I1,I4}->l3
{I2,I3}->l4

l1 and l2 => l5:{l1,l2,l3} 
l5 的所有子集集合为 {{l1}, {l2}, {l3},{l1,l2},{l2,l3},{l2,l3} } 它们都是Lk-1 中的 子集
当然 l5 中还有子集 {l1,l2,l3}这种情况我们不要考虑。

但是 l2 and l3 => l6:{ l1,l3,l4}
l6  中的所有子集的集合为(全集){{l1},{l2},{l3}, {l1,l3}, {l1,l4} ,{l3,l4} }
l6 就不能够将其归纳入到 Ck 中, 因为{l3,l4} 在 Lk-1 中是不存在的。

在这个地方用到的是 先验规则,就是说: 出现在Lk-1 中的所有 itemset 都是 k-1次,
筛选出来的 频繁相机,如果在Ck 中的 itemset 中的子集不在这个 k-1次 的频繁itemset 中的话,
那么他一定不是频繁itemset ,因为子集不是 frequent set 的话,它的任意 super set 都不可能是
frequent set . 即便 在Lk-1 到 Ck 这一步 该itemset 会被保留下来,但是,
Ck 到 Lk 这一步,也会 和 原始的数据集 进行比较 由于 支持度 小于最小支持度而被 删除,
提前一步删除的话,会降低
1. 生成过多的候选集合, 
2, 减小与原始数据连接而浪费的时间 

这样的话,我们就得到了 Ck, 然后再根据Ck中的项集 在最初数据源中
出现的次数进行统计,统计出来结果之后,对比最小支持度进行 记录的赛选就得到了
Lk,
按照上面的步骤一次迭代下去,直到求出的 满足 支持度的集合数目 为0 程序停止。


根据老师共享的 <数据挖掘导论> 这本书中的介绍,伪代码描述如下

record = getDataSet ( data.txt ) ;

record\'s content :
I1        I2        I5
I2        I4
I2        I3
I1        I2        I4
I1        I3
I2        I3
I1        I3
I1        I2        I3        I5
I1        I2        I3


cItemset = getFirstCandidate () ; ----> get Ck-1  
lItemset = getSupportedItemset( cItemset ) ; -----> get Lk-1 from Ck-1

while ( cItemset not null  )
{
    ckItemset = getNextCandidate ( lItemset) ; -----> get Ck from Lk-1
    lkItemset = getSupportedItemset ( ckItemset) ; -----> get Lk from Ck 


   cItemset = ckItemset ;
   lItemset = lkItemset ; //for next loop 
}

2.Apriori类中的各个模块方法描述

我将 Ck-1 Ck 也就是 相应的 候选集使用数据结构
List<List<String>> 来对其进行表示,
这样的话 对于一个 {I1, I2 ,I5} {I1, I3} 就可以存储成 : List<<<I1>, <I2> ,<I5>>, <<I1>,<I3>>的数据格式了。

将频繁itemset 使用 Map<List<String>, Integer> 来对其进行表示,
这样, itemset {I1, I2 , I5 } 在record 出现的次数 为 4 次的话,就可以表示成:

<<<I1>,<I2>,<I5>> , 4> 这样的数据类型了。

List<List<String>> : getFirstCandidate () : 用于直接从record中读取 1项集 对应出现的次数 以及 项集对应的名字

Map<List<String>, Integer> :getSupportedItemset( List<List<String>> cItemset) :
这个方法 是从 Ck-1 中获取 支持度 满足最小支持度 的 集合,

List<List<String>> : getNextCandidate( Map<List<String>,Integer>) 
这个方法, 是从Lk-1 中获取 Ck 的方法。

  1. package myApriori;

  2. //Aprioiri 
  3. import java.util.Iterator;
  4. import java.util.List ;
  5. import java.util.Map ;
  6. import java.util.ArrayList ;
  7. import java.util.HashMap; 
  8. import java.util.Map.Entry;
  9. import java.util.Set;




  10. public class myApriori {

  11.         static private boolean endTag = false ;
  12.         static private List<List<String>> cItemset ;
  13.         static private List<List<String>> ckItemset ;
  14.         static private Map<List<String>, Integer> lItemset ;
  15.         static private Map<List<String>,Integer>  lkItemset ;
  16.         
  17.         static List<List<String>> record = new ArrayList<List<String>> () ;
  18.         
  19.         final static double MIN_SUPPORT = 2 ;
  20.         static Map<List<String>, Double > confItemset = new HashMap<List<String>,Double >() ;
  21.         
  22.         
  23.         public static  List<List<String>> getDataSet ()
  24.         {
  25.                 return FileReader.getDatabase();
  26.         }
  27.         
  28.         
  29.         public static List<List<String>> getFirstCandidate ()
  30.         {
  31.                 
  32.                 List<List<String>> cItemset = new ArrayList<List<String>> () ;
  33.                 List<String> tempLine = new ArrayList<String>() ;
  34.                 
  35.                 for( int i = 0 ; i < record.size() ; i++ )
  36.                 {
  37.                         
  38.                         for (int j = 0 ; j < record.get(i).size(); j++)
  39.                         {
  40.                                 if(tempLine.contains(record.get(i).get(j))) ;
  41.                                 else
  42.                                 {
  43.                                         tempLine.add(record.get(i).get(j)) ;
  44.                                          
  45.                                 }
  46.                         }
  47.                         
  48.                 }
  49.                 
  50.                 for ( int i = 0 ; i < tempLine.size() ;i++)
  51.                 {
  52.                         List<String> str = new ArrayList<String>() ;
  53.                         str.add(tempLine.get(i));
  54.                         
  55.                         cItemset.add(str) ;
  56.                          
  57.                 }
  58.                 
  59.                 return cItemset ;
  60.         }
  61.         
  62.         static Map<List<String>,Integer> getSupportedItemset( List<List<String>> cItemset )
  63.         {
  64.                 Map<List<String>,Integer> supportedItemset = new HashMap<List<String>,Integer> () ;
  65.                 
  66.                 boolean end = true ;
  67.                 
  68.                 for( int i = 0 ; i < cItemset.size(); i++ )
  69.                 {
  70.                         int count = countFrequent ( cItemset.get(i)) ;
  71.                         
  72.                         if( count >= MIN_SUPPORT )
  73.                         {
  74.                         supportedItemset.put(cItemset.get(i), count) ;
  75.                         end = false ;
  76.                 
  77.                         }
  78.                 }
  79.                 
  80.                 endTag = end ;
  81.                 
  82.                 
  83.                 //System.out.println(\"value of the endTag here !!!\"+endTag);
  84.                 
  85.                 return supportedItemset  ;
  86.         }
  87.         
  88.         static int countFrequent ( List<String> list)
  89.         {
  90.                 
  91.                 int count = 0 ;
  92.                 
  93.                 for ( int i = 1 ; i < record.size() ; i++ )
  94.                 {
  95.                         boolean curRecordLineNotHave = false ;
  96.                         
  97.                         for ( int k = 0 ; k < list.size(); k++)
  98.                         {
  99.                                 if(!record.get(i).contains(list.get(k)))
  100.                                 {
  101.                                         curRecordLineNotHave = true ;
  102.                                         break ;
  103.                                 }
  104.                         }
  105.                         
  106.                         if(curRecordLineNotHave == false )
  107.                         {
  108.                                 count++ ;
  109.                         }
  110.                 }
  111.                 
  112.                 return count ;
  113.         }
  114.         
  115.         
  116.         /**
  117.          * method following is the getNextCandidata usually can be known as 
  118.          * get Ck from Lk-1 
  119.          * */
  120.         private static List<List<String>> getNextCandidate ( Map<List<String>,Integer> lItemset )
  121.         {
  122.                 List<List<String>> nextItemset = new ArrayList<List<String>>() ;
  123.                 
  124.                 List<List<String>> preItemset = getLItemset(lItemset ) ;
  125.                 
  126.                 int count = 0 ;
  127.                 
  128.                 for ( int i = 0 ; i < preItemset.size() ; i++ )
  129.                 {
  130.                         List<String> tempLine = new ArrayList<String> () ;
  131.                         tempLine.addAll(preItemset.get(i)) ;
  132.                    
  133.                         for( int j = i+1 ; j < preItemset.size(); j++)
  134.                         {
  135.                                  if( preItemset.get(i).size() == preItemset.get(j).size())
  136.                                  {
  137.                                                               
  138.                                          if( 1 == differElemNum(preItemset.get(i),preItemset.get(j)))
  139.                                          {
  140.                                                  int index = getDifferIndex ( preItemset.get(i), preItemset.get(j)) ;
  141.                                                  
  142.                        
  143.                                                  tempLine.add(preItemset.get(j).get(index)) ;
  144.                                                  
  145.                      
  146.                                                  if( isSubSets ( tempLine, preItemset))
  147.                                                  {
  148.                                                                                        
  149.                                                          List<String> aLine = new ArrayList() ;
  150.                                                          
  151.                                                          for(int m = 0 ; m < tempLine.size() ;m++)
  152.                                                          {
  153.                                                                  aLine.add(tempLine.get(m));
  154.                                                          }
  155.                                                          
  156.                                                          if( nextItemSetNotHave( aLine, nextItemset ))
  157.                                                                  nextItemset.add(aLine) ;
  158.                                                          
  159.                                                  }
  160.                                          }
  161.                                  }//outer if 
  162.                                  
  163.                                  tempLine.remove(tempLine.size()-1 ) ;
  164.                         }//for j 
  165.                 }
  166.                                 
  167.                  return nextItemset ;
  168.                                                  
  169.         }
  170.         
  171.         
  172.         private static boolean nextItemSetNotHave( List<String> aLine , List<List<String>> nextItemset )
  173.         {
  174.                 boolean notHave = true ;
  175.                 
  176.                 for( int i = 0 ; i < nextItemset.size(); i++ )
  177.                 {
  178.                         if(aLine.equals(nextItemset.get(i)))
  179.                         {
  180.                                 notHave = false ;
  181.                         }
  182.                 }
  183.                 
  184.                 return notHave ;
  185.         }
  186.         
  187.         
  188.         private static int getDifferIndex ( List<String> list1 , List<String> list2)
  189.         {
  190.                 int index = -1 ;
  191.                 
  192.                 for ( int i = 0 ; i < list1.size() ; i++ )
  193.                 {
  194.                         for( int j = 0 ; j < list1.size(); j++ )
  195.                         {
  196.                                 if ( !list1.get(i).equals(list2.get(j)))
  197.                                 {
  198.                                         index = j ;
  199.                                 }
  200.                         }
  201.                         
  202.                         if ( index != -1 )
  203.                                 break ;
  204.                 }
  205.                 
  206.                 return index ;
  207.         }
  208.         
  209.         private static int differElemNum ( List<String> list1, List<String>list2 )
  210.         {
  211.                 int count = 0 ;
  212.                 
  213.                 boolean flag ;
  214.                 
  215.                 for( int i = 0 ; i < list1.size() ; i++ )
  216.                 {
  217.                         flag = true ;
  218.                         
  219.                         for(int j = 0 ; j < list1.size(); j++ )
  220.                         {
  221.                                 if(list1.get(i).equals(list2.get(j)))
  222.                                 {
  223.                                          flag = false ;
  224.                                         break;
  225.                                 }
  226.                         }
  227.                         
  228.                         if( flag == true )
  229.                         {
  230.                                 count++ ;
  231.                         }
  232.                 }
  233.                 
  234.                 return count ;
  235.         }
  236.          
  237.         
  238.         
  239.         /**
  240.          * method following is used to justice whether 
  241.          * @param tempList all subsets except itself is the subsets of 
  242.          * @param lItemset
  243.          * 
  244.          * @return boolean true : all subsets of tempList are all in
  245.          * lItemset\'s set
  246.          * */
  247.         
  248.         private static boolean isSubSets ( List<String> tempList , List<List<String>> lItemset)
  249.         {
  250.                 
  251.                 boolean flag = false ;
  252.                 
  253.                 for ( int i = 0 ; i < tempList.size() ; i++ )
  254.                 {
  255.                         List<String> testLine = new ArrayList() ;
  256.                         
  257.                         for (int j = 0 ; j < tempList.size(); j++ )
  258.                         {
  259.                                 if (i!= j )
  260.                                 {
  261.                                         testLine.add(tempList.get(j)) ;
  262.                                 }
  263.                         }
  264.                         
  265.                          for ( int k = 0 ; k < lItemset.size() ; k++ )
  266.                         {
  267.                                 if ( testLine.equals(lItemset.get(k)))
  268.                                 {
  269.                                         flag = true ;
  270.                                         break ;
  271.                                 }
  272.                         }
  273.                         
  274.                         
  275.                         if ( flag == false )
  276.                         {
  277.                               
  278.                                 return false ;
  279.                         }
  280.                 }
  281.                 
  282.                 
  283.                 return flag ; //return true ;
  284.                 
  285.         }
  286.               
  287.         
  288.         private static List<List<String>> getLItemset ( Map<List<String>, Integer> lItemset )
  289.         {
  290.                 List<List<String>> itemset = new ArrayList<List<String>> () ;
  291.                 
  292.                 Iterator<Map.Entry<List<String>, Integer>> iterator = lItemset.entrySet().iterator();
  293.                 Entry<List<String>, Integer> entry ;
  294.                 
  295.                 
  296.                 while ( iterator.hasNext() )
  297.                 {
  298.                         entry = iterator.next();
  299.                         List<String> key = entry.getKey() ;
  300.                         
  301.                         itemset.add(key) ;
  302.                         
  303.                          
  304.                 }
  305.                 return itemset ;
  306.         }
  307.         
  308.         public static void main ( String [] args ) throws Exception 
  309.         {
  310.                 record =getDataSet() ;
  311.                 
  312.                 
  313.          
  314.                  cItemset = getFirstCandidate() ;
  315.                 
  316.                 lItemset = getSupportedItemset( cItemset ) ;
  317.                 
  318.                  printfLKitemset ( lItemset) ;
  319.                 
  320.                 
  321.                 
  322.                   while ( endTag != true )
  323.                  {
  324.                          ckItemset = getNextCandidate(lItemset ) ;
  325.                          lkItemset = getSupportedItemset ( ckItemset ) ;
  326.                          
  327.                          if(lkItemset.size() != 0 )
  328.                                  printfLKitemset ( lkItemset) ;
  329.                          
  330.                          cItemset = ckItemset ;
  331.                          lItemset = lkItemset ;
  332.                  }  
  333.                  
  334.                   System.out.println(\"finish \") ;
  335.                  
  336.                  
  337.         }
  338.         
  339.          private static void printfLKitemset ( Map<List<String> , Integer> lkItemset )
  340.          {
  341.                  Iterator<Entry<List<String>,Integer>> iterator = lkItemset.entrySet().iterator();
  342.                  
  343.                  Entry<List<String>,Integer> entry ;
  344.                  
  345.                  while ( iterator.hasNext() )
  346.                  {
  347.                          entry = iterator.next() ;
  348.                          
  349.                          List<String> key = entry.getKey() ;
  350.                          Integer value = entry.getValue() ;
  351.                          
  352.                          System.out.println(\"the key : \");
  353.                          
  354.                          for ( int i = 0 ; i < key.size() ; i++ )
  355.                          {
  356.                                  System.out.print(key.get(i));
  357.                                  System.out.print(\"  \"); 
  358.                          }
  359.                          
  360.                          System.out.println(\"the value : \"+ value.intValue());
  361.                          
  362.                  }
  363.          }
  364.         
  365.         
  366.         
  367. }
复制代码


//reader.java

  1. package myApriori;

  2. import java.io.BufferedReader ;
  3. import java.io.File ;
  4. import java.io.FileInputStream ;
  5. import java.io.InputStreamReader; 
  6. import java.util.ArrayList ;
  7. import java.util.List ;

  8. public class FileReader 
  9. {
  10.         public static List<List<String>> getDatabase()
  11.         {
  12.                 List<List<String>> db = new ArrayList<List<String>>() ;
  13.                 
  14.                 try
  15.                 {
  16.                         File file = new File(\"data.txt\") ;
  17.                         
  18.                         if ( file.isFile() && file.exists())
  19.                         {
  20.                                 InputStreamReader read = new InputStreamReader
  21.                                                         (
  22.                                                         new FileInputStream(file)
  23.                                                                         ) ;
  24.                                 
  25.                                 BufferedReader reader = new BufferedReader( read ) ;
  26.                                 
  27.                                 
  28.                                 String line = null ;
  29.                                 
  30.                                 while ( (line = reader.readLine())!= null )
  31.                                 {
  32.                                         String [] strToknizer = line.split(\"        \") ;
  33.                                         
  34.                                         List<String> tmpLine = new ArrayList<String>() ;
  35.                                         
  36.                                         for ( int i = 1 ; i < strToknizer.length ; i++ )
  37.                                         {
  38.                                                 
  39.                                                 tmpLine.add(strToknizer[i]) ;
  40.                                                 
  41.                                         }
  42.                                         db.add(tmpLine) ;
  43.                                 }
  44.                                 
  45.                                 reader.close();
  46.                         }
  47.                         else
  48.                         {
  49.                                 System.out.println(\"fail to find target file !\");
  50.                         }
  51.                 }
  52.                 catch (Exception e)
  53.                 {
  54.                         System.out.println(\"fail in reading file\'s content \");
  55.                         e.printStackTrace();
  56.                 }
  57.                 
  58.                 return db ;
  59.         }

  60. }
复制代码

  myApriori.zip (10.68 KB) 


3.出处: 这个算法的源代码是 来自: http://www.cnblogs.com/fengfenggirl/p/associate_apriori.html#2752667
LZ在拜读他的代码之后,对其中的一些地方进行了修改得出的这个算法的代码,
通过阅读他的 github 上面的代码,学习到了很多东西,博主的很多关于数据挖掘的算法文章都是相当好的,极力推荐一下。
本算法,不是十分的严谨与完善,没有涉及到关于置信度那个地方的知识,
也希望起到一个抛砖引玉的作用,
有同学实现了的话,可以将代码贴上一起分享一下。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值