机器学习实战2:关联规则:议会投票+毒蘑菇

  本人看过的关联规则博文,很少有清晰的把关联规则的算法说很明白的,希望读者读完本文可以有新的收获。本文是在默认读者有相关机器学习算法基础的,总结和提升对关联规则代码实现的理解,并介绍相关案例。语言:python

  一 引言

  关联规则起初是在购物篮分析中发现的,沃尔玛超市在美国某地区啤酒和尿布放在一起卖,这种关联规则有利于市场营销决策的制定。

  关联规则是非监督学习的一种。

  

  二 两个重要的概念

  我们认定满足支持度置信度的规则是有趣的,

    支持度:P(A),及项集A出现的概率(频数);

    置信度:P(B / A), 条件概率; P(B / A)= P(AB)/P(A),所以支持度可以用来计算置信度,代码是学习算法最好的途径。

  

  三 Apriori算法

  网上很多文章介绍Apriori算法都是云里雾里,下面梳理一下脉络。

  

  核心是apriori原理:如果某个项集是频繁的,那么它是所有子集也是频繁的。

  apriori原理的精妙在于他的逆否命题,若子集不是频繁的,则所有包含它的项集都是不频繁的。这样剪掉不频繁项集时,就可以同时剪掉很多包含这个项集的不频繁的项集了。若蛮力查找大频项集,时间复杂度是指数型,例如4个项集,它的所有组合的复杂度是15。同理,可以剪掉后件不满足置信度规则时,同时剪掉后件包含这个规则后件的规则。形象的说,看下图:

  eg

  项集{0,1,2,3},计算所有的组合情况如下图,好像一个格,时间复杂度是指数型的,按照项集元素数由小到大计算每个组合的支持度,{2,3}黑色圈不满足最小支持度,由apriori定理,则所有以它为子集的项集均不满足最小支持度,需要剪掉。  

  

  下面继续考虑置信度,规则{012}->{3}不满足最小置信度,由apriori定理,所有后件包含这条规则后件的规则需要剪掉,即二后件规则:{01}->{23},{02}->{1,3},{12}->{03}和三后件规则{0}->{123},{1}->{023},{2}->{013}。

  

  读到这里有关联规则基础的人应该会有感悟,通过下面代码介绍可以细致的明白apriori算法的机制。

 

  四 apriori实现

  1 加载demo数据集(可以改成真实数据集,读文件):

from numpy import *

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

  2 生成一频繁项集作为起始点,即长度为1的频繁集,图中的第一层:使用frozenset结构是因为set不可以作为dict的关键字

def createC1(dataSet):#create one item
    C1 = []
    for transaction in dataSet:
        for item in transaction:
            if not [item] in C1:
                C1.append([item])
   
    C1.sort()
    # print C1   
    return map(frozenset, C1)#use frozen set so we
                            #can use it as a key in a dict    

  3 计算Ck支持度,并剪掉不满足最小指出的项集。

def scanD(D, Ck, minSupport):#create one or more big frequence item
    ssCnt = {}
    for tid in D:
        for can in Ck:
            if can.issubset(tid):
                if not ssCnt.has_key(can): ssCnt[can]=1
                else: ssCnt[can] += 1
    numItems = float(len(D))
    retList = []
    supportData = {}
    for key in ssCnt:
        support = ssCnt[key]/numItems
        if support >= minSupport:
            retList.insert(0,key)
        supportData[key] = support
    return retList, supportData

  4 由m频繁项集生成m+1频繁项集:举例,Ck为1频繁项集{01}{12}{02},生成{012},有个技巧,只合并前m-2项一样的项集,这样不会重复操作,如这个例子,{01}和{12}不合并,{12}{02}也不合并,只有{01}{02}合并,生成最后的{012};否则前几个合并都是重复的。值得注意的是0-3项集要排好序,否则前k-2个没有比较的必要。

def aprioriGen(Lk, k): #creates Ck
    retList = []
    lenLk = len(Lk)
    # print Lk
    for i in range(lenLk):
        for j in range(i+1, lenLk): 
            L1 = list(Lk[i])[:k-2]; L2 = list(Lk[j])[:k-2]
            L1.sort(); L2.sort()
            # print L1,'--',L2
            if L1==L2: #if first k-2 elements are equal
                retList.append(Lk[i] | Lk[j]) #set union
            # print retList
    return retList

  5 生成打频项集的算法:

    思路,生成1频项集,根据最小支持度过滤;依次由m频项集生成m+1频项集,直到m+1频项集为空停止迭代。

def apriori(dataSet, minSupport = 0.5):
    C1 = createC1(dataSet)
    D = map(set, dataSet)
    L1, supportData = scanD(D, C1, minSupport)#create one big frequence item L1
    # print L1
    L = [L1]
    k = 2
    # print L
    while (len(L[k-2]) > 0):
        # print 'L[k-2]',L[k-2]
        # print L
        Ck = aprioriGen(L[k-2], k)
        Lk, supK = scanD(D, Ck, minSupport)#scan DB to get Lk
        supportData.update(supK)
        L.append(Lk)
        k += 1
    return L, supportData

  以上都是大频项集的生成算法,下面继续有趣的关联规则的发现算法:

 

  6 计算后件为H的规则的置信度,代码可以看出只是一个条件概率公式而已;根据最小置信度,筛选出有趣的规则;

def calcConf(freqSet, H, supportData, brl, minConf=0.7):
    prunedH = [] #create new list to return
    for conseq in H:
        conf = supportData[freqSet]/supportData[freqSet-conseq] #calc confidence
        if conf >= minConf: 
            brl.append((freqSet-conseq, conseq, conf))
            prunedH.append(conseq)
    return prunedH

  7 由后件数为m的规则集生成后件为后件数为m+1的规则集,并计算置信度;递归到没有可以合并的规则集停止;

  直观的过程可以查看上图的格,eq {23}->{01}和{12}->{03} 合并为{2}->{013};因为标红处前k-2相同,为了避免重复的合并操作,同上面打大频项集合并。

def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):if (len(freqSet) > (m + 1)): #try further merging
        Hmp1 = aprioriGen(H, m+1)#create Hm+1 new candidates
        Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf)if (len(Hmp1) > 1):    #need at least two sets to merge
            rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)

 

  8 产生关联规则的最后算法:

  思路,由于规则的前后件均不能为空,所以只有二频繁项集才能产生关联规则;

       1)首先由二频繁项集生成规则集,遍历所有的二频繁项集(每个元素轮流作为后件),根据最小置信度过滤规则集;

        eg 二频繁项集{12},则计算规则{1}->{2}和{2}->{1}的置信度;

      2)依次迭代,在三大频项集生成规则集(每个元素轮流作为后件),需要考虑规则的合并,

        eg 三大频项集{123},则{12}->{3},{13}->{2},{23}->{1},此外考虑合并,{1}->{23},{2}->{13},{3}->{12},还要继续合并:根据后件,前k-2个同的合并,本例前k-2个同的个数为0,所以停止,复杂的情况看步骤7;

def generateRules(L, supportData, minConf=0.7):  #supportData is a dict coming from scanD
    bigRuleList = []
    for i in range(1, len(L)):#only get the sets with two or more items
        for freqSet in L[i]:
            H1 = [frozenset([item]) for item in freqSet]
            if (i > 1):
                rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)
            else:
                calcConf(freqSet, H1, supportData, bigRuleList, minConf)
    return bigRuleList         

 

  五 应用

  关联规则可以应用到哪些问题呢?

  购物篮分析,搜索引擎的查询词,国会投票,毒蘑菇的相似特征提取等;

 

  六 毒蘑菇的相似特征提取

   毒蘑菇部分数据集如下:

1 3 9 13 23 25 34 36 38 40 52 54 59 63 67 76 85 86 90 93 98 107 113 
2 3 9 14 23 26 34 36 39 40 52 55 59 63 67 76 85 86 90 93 99 108 114 
2 4 9 15 23 27 34 36 39 41 52 55 59 63 67 76 85 86 90 93 99 108 115 
1 3 10 15 23 25 34 36 38 41 52 54 59 63 67 76 85 86 90 93 98 107 113 
2 3 9 16 24 28 34 37 39 40 53 54 59 63 67 76 85 86 90 94 99 109 114 
2 3 10 14 23 26 34 36 39 41 52 55 59 63 67 76 85 86 90 93 98 108 114 
2 4 9 15 23 26 34 36 39 42 52 55 59 63 67 76 85 86 90 93 98 108 115 
2 4 10 15 23 27 34 36 39 41 52 55 59 63 67 76 85 86 90 93 99 107 115 
1 3 10 15 23 25 34 36 38 43 52 54 59 63 67 76 85 86 90 93 98 110 114 
2 4 9 14 23 26 34 36 39 42 52 55 59 63 67 76 85 86 90 93 98 107 115 
2 3 10 14 23 27 34 36 39 42 52 55 59 63 67 76 85 86 90 93 99 108 114 
2 3 10 14 23 26 34 36 39 41 52 55 59 63 67 76 85 86 90 93 98 107 115 

  每一行代表一个蘑菇的特征,第一列是决策类,1代表有毒,2代表五毒;

  加载数据集:

dataset=[line.split() for line in open('mashroom.dat'),readline()]

  查找大频率项集:

L,supp=apriori(dataset,0.3)
 apriori函数在算法部分已经实现,直接调用即可。

  有时候我们只需要查找大频项集,并不需要关联规则,具体问题具体分析即可。

 

  七 总结

  整体算法就有两个核心,1计算满足最小支持度的大频率项集,2挖掘满足最小置信度的有趣规则;暴力遍历每种组 合的方式指数级,利用了apriori定理,剪掉了不满足要求的小项集和小后件规则的同时,剪掉包含他们的大频度项集和大后件规则;还有一点主意的是。按 照图中格的形式,一层一层有小到大迭代。

posted @ 2016-06-24 21:45  rongyux  阅读(3463)  评论(1编辑  收藏  举报