機械学習実戦---読書ノート:11章Aprioriアルゴリズムを用いた関連分析

7382 ワード

#!/usr/bin/env python
# encoding: utf-8

'''
<>       11    Apriori        

  :
1     
  :                   
    :               

2 Apriori  
  :       
  :           
      :          

    :           
    :              
    :                  

  :
          
0             ,  
1             ,  ,   ,  
2             ,  ,   ,  
3             ,  ,  ,     
4             ,  ,  ,  

   :                  。
     ,{  }    4/5
5       3 : {  ,  },{  ,  }     3/5
     :         

   /   :
  :         {  }->{   }         。
         :  "   ({  ,   })/   ({  })
  {  ,   }    3/5, {  }    4/5,
      ->         =3/4=0.75
   ,           ,        75%      。

3 Apriori  
  :            。
  :           ,             。
                 ,              。
        :  {0, 1}    ,  {0} {1}       。
apriori:      。      ,          ,         。
          :      。
                    ,          。
    :   Apriori         ,      。


4   Apriori         
       :              。
    :        ,        。
           。

Apriori  :
  :       
    :
  1:              
  2:                      ,      
  3:                      
  4:        ,             。
  5:       ,         。

5    Apriori  
  :
          0 
        k            
               
             k+1           

apriori      :
    :    dataSet(     ,           );      minSupport(   )
    :         (                    ,         frozenset     )
                     
  :
  1:      1      C1,        :
        1.1      (     )     
            1.1.1            ;
            1.1.2             ,         ;
        1.2          ,    fronzenset   
  2:   C1,                        L1,            ,
                         :
        2.1:         ssCnt
        2.2:                C1       。
                2.2.1   C1            ,            。
        2.3:                    。
        2.4:     2.1    ssCnt     ,      。
                2.4.1               ,             
                2.4.2             
        2.5:            ,            
  3:             L,  k=2
  4:   L[k-2]     0,     5;  ,    ,        L             
  5:        L[k-2]             k,        Ck,        :
       5.1                       
       5.2            k-2    ,           ,         
       5.3       ,  Ck
  6:   Ck,                 Lk Lk          ,               
  7:            L         Lk,   k  

  :
     Ck,   ,      -->    Lk
     Lk,            k+1 ->    Ck+1
     Ck+1,    ,      -->    Lk+1



'''

def loadDataSet():
    return [ [1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5] ]

'''
  :      1          
  :
  1:          
  2:            ;
        2.1             ,         ;
  3:          ,    fronzenset   
'''
def createC1(dataSet):
    if not dataSet:
        return frozenset()
    result = []
    for arr in dataSet:
        for value in arr:
            if [value] not in result:
                result.append([value])
    result.sort()
    '''
         frozenset:       ,      ,         
          。
    '''
    return map(frozenset, result)


'''
  :    C1  L1。
    :    D,      Ck,            minSupport
   :             
  :
  1:         ssCnt
  2:                C1       。
        2.1   C1            ,            。
  3:                    。
  4:     1    ssCnt     ,      。
        4.1               ,             
        4.2             
  5:            ,           

  :             。
                       ,             
                  ,         ,                      。
'''
def scanD(D, Ck, minSupport):
    if not D or not Ck:
        print "D is empty or Ck is empty, D is: {D} , Ck is: {Ck}".format(D=D, Ck=Ck)
    canToTimes = {}
    for tid in D:
        for can in Ck:
            if can.issubset(tid):
                if canToTimes.has_key(can):
                    canToTimes[can] += 1
                else:
                    canToTimes[can] = 1
    result = []
    canToSupport = {}
    length = len(D)
    for can, times in canToTimes.iteritems():
        support = float(times) / length
        if support >= minSupport:
            result.insert(0, can)
        canToSupport[can] = support
    return result, canToSupport


'''
  :
    :       Lk,       k(                   +1)
    :   Ck。
  :     {0}, {1},{2}    ,   {0, 1}, {0, 2} {1,2}
  :
  1:                       
  2:            k-2    ,           ,         
'''
def aprioriGen(Lk, k):
    if not Lk or k < 2:
        print "Lk is empty or k < 2, Lk: {Lk}, k: {k}".format(Lk=Lk, k=k)
        return
    length = len(Lk)
    results = []
    for i in range(length):
        for j in range(i + 1, length):
            list1 = list(Lk[i])[: k - 2]
            list2 = list(Lk[j])[: k - 2]
            list1.sort()
            list2.sort()
            if list1 == list2:
                result = Lk[i] | Lk[j]
                results.append(result)
    return results

'''
  :
    :    dataSet(     ,           );      minSupport(   )
    :         (                    ,         frozenset     )
                     
  :
  1:      1      C1,        :
        1.1      (     )     
            1.1.1            ;
            1.1.2             ,         ;
        1.2          ,    fronzenset   
  2:   C1,                        L1,            ,
                         :
        2.1:         ssCnt
        2.2:                C1       。
                2.2.1   C1            ,            。
        2.3:                    。
        2.4:     2.1    ssCnt     ,      。
                2.4.1               ,             
                2.4.2             
        2.5:            ,            
  3:             L,  k=2
  4:   L[k-2]     0,     5;  ,    ,        L             
  5:        L[k-2]             k,        Ck,        :
       5.1                       
       5.2            k-2    ,           ,         
       5.3       ,  Ck
  6:   Ck,                 Lk Lk          ,               
  7:            L         Lk,   k  

  :
     Ck,   ,      -->    Lk
     Lk,            k+1 ->    Ck+1
     Ck+1,    ,      -->    Lk+1
...

'''
def apriori(dataSet, minSupport=0.5):
    C1 = createC1(dataSet)
    D = map(set, dataSet)
    L1, supportDict = scanD(D, C1, minSupport)
    L = [L1]
    k = 2
    while len(L[k - 2]) > 0:
        Ck = aprioriGen(L[k-2], k)
        Lk, partialSupportDict = scanD(D, Ck, minSupport)
        supportDict.update(partialSupportDict)
        # note, Lk may be empty, if Lk is empty, it needs to end this recycle
        if not Lk:
            break
        L.append(Lk)
        k += 1
    return L, supportDict



def process():
    dataSet = loadDataSet()
    L, supportDict = apriori(dataSet)
    print "         : {supportDict}".format(
        supportDict=supportDict
    )
    for i, arr in enumerate(L):
        print "       {length}       : {arr} ".format(length=i+1, arr=arr)
    # C1 = createC1(dataSet)
    # print "C1: {C1}".format(C1=C1)
    # D = map(set, dataSet)
    # print "D: {D}".format(D=D)
    # minSupport = 0.5
    # L1, canToSupport = scanD(D, C1, minSupport)
    # print "L1: {L1},canToSupport: {canToSupport}".format(L1=L1, canToSupport=canToSupport)



if __name__ == "__main__":
    process()