Apriori算法--机器学习实战总结

一原理:

       为了我们的决策,我们需要从数据海洋中寻找元素之间的隐含关系(注意:这里的隐含很重要,因为数据量很大的情况下,人脑很难胜任这种复杂的计算),基于这些关联规则分析,我们可以更好的理解我们客户的行为。但问题是,元素之间的关系往往需要大量计算,为了在合理的时间范围内寻找频繁项集和关联规则,可以使用Apriori算法。

 二 Apriori算法基如下结论:

         如果一个项集是非频繁的,那么这个项集的超集也是非频繁的,这样可以减少我们关注的项集的个数。如果R->H不满足可信度要求,那么subset(R)->H肯定也不会满足。

   三 基本过程:

     首先,定义两个量化指标,支持度和可信度。

 

   

  

      支持度用来衡量某个项集在样本集中出现的频率,出现频率高的作为频繁项集。可信度用来衡量元素之间的关联关系,如上面例子,买尿布的人当中,同时买葡萄酒的人越多,说明这种倾向就越明显,也就是关联关系越明显(同时买尿布和葡萄酒的是单独买尿布的子集,固定分母,分子越大,说明这类人中买葡萄酒的人越多)。其实,支持度就是集合出现的概率,可信度就是条件概率。P(A)=counter(A)/Counter(total)    A->B P(B|A)=p(AB)/P(A) p(AB)<P(A)或P(B)

 

       我们可以根据输入样本集合,构造初始集合,初始集合只包含单个元素组合,记做C1, 然后计算符合支持度(实际上,就是一个算法的度量指标,在样本集中出现的次数(是否为子集)/样本总数,即该元素出现的概率,很明显,概率越大,出现的频率越高,支持度越高吗,相应关联度也越大),不断迭代,通过Ck-1生成Ck(通过元素组合,每次取k-1前缀相同的集合然后取并集即可,想想A(4,4)是咋计算的就明白了),不断过滤掉不符合支持度的样本组合,直到无法找到新的组合为止,这样我们就得到了所有符合支持度的元素组合集合。

 

      得到符合支持度的集合和对应支持度的列表,我们可以基于此计算可信度,R->H  conf  条件:Count(R U H)>=2  Count(H)<=Count(R U H)-1    可信度的计算: conf(R->H)=S(R U H)/S(R),我们会先固定RUH,取符合支持度的集合列表且元素个数大于等于2 (RUH),根据符合支持度的集合列表得到单个元素,然后计算到单个元素及其组合的可信度,选出符合条件的,放到列表中,元素为元祖(R,H,conf) ,这里会用到一个理论:如果R->H不满足可信度要求,那么subset(R)->H肯定也不会满足。

 

       貌似监督类的机器学习算法,试图利用样本,枚举“所有可能性”(涉及到一些数据过滤,比如剪枝,尽量减少数据计算量),并通过一定的指标评估这些可能性,得出某种结论(量化的)。而非监督类的机器学习算法,也试图利用样本,也是度量一定的指标,但总是会形成数学模型,然后利用这种模型去进行预测。//没想明白。。。。。呵呵呵呵。。。。。

   四。算法实现

import matplotlib.pyplot as plt
import numpy as np
import random
from numpy import *
from operator import  *


def loadDataSet():

    return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]

#创建C1集合,包含单个元素的集合,这里假设数据集包含两层
def createC1Set(dataSet):
    c1=[]
    for items in  dataSet:
        for item in items:
            #元素未包含在集合中,就添加,转化成单个列表元素
            if not item in c1:
                c1.append([item])

    #使用默认排序规则进行排序
    c1.sort()
    print(c1)

    #转化成单个集合元素的list
    c1list = list(map(set,c1))

    c2list=[]

    #这里自己实现了个转换函数,比较长,看着比较恶心
    for i in c1list:

        if not i in c2list:
               c2list.append(i)

    c2list=list(map(frozenset,c2list))

    print(c2list)

    return c2list


def scanD(D,ck,minSupport):
    #记录子集的出现个数
    counterDict={}
    for item in D:
        for k in ck:

            #print(type(item),type(k))
            #查看k是否为总的样本集合的子集
            if k.issubset(item) :
               #统计子集的出现次数
               #集合的key只能为可以hash的类型(非可变类型),set不能hash,需要转换下

               if not k in counterDict:
                   counterDict[k]=1
               else:
                   counterDict[k]+=1

    print('样本出现频率:\n',counterDict)

    #总的样本数
    totalCount=len(D)

    retList=[]
    supportDict={}
    #计算支持度
    for key in counterDict.keys():

        support=(counterDict[key])/totalCount

        #如果大于传入的支持度,就保留下来

        if support>=minSupport :

            retList.append(key)

        supportDict[key]=support


    print('符合支持度的候选项集:\n',retList)
    print('各个候选项集的支持度:\n',supportDict)


    return retList,supportDict


#生成列表,列表元素包含k个元素的集合,创建Ck

def aprioryGen(Lk,k):


    retList=[]

    length=len(Lk)

    for i in range(length):

         for j in range(i+1,length):

             #注意每次集合元素个数加1,需要比较前缀是否相同,只有相同的才能合并,固定k-2,添加k-2+1个元素
             #并集生成新的元素
             #检查Lk[i]和Lk[j]的k-2的前缀是否相同
             L1=list(Lk[i])[:k-2]
             L2=list(Lk[j])[:k-2]

             L1.sort()
             L2.sort()

             if L1==L2:
                  retList.append(Lk[i].union(Lk[j]))


    #print('生成的Ck列表:\n',retList)

    return retList


#apriori算法实现
#原理:如果一个项集是非频繁的,那么这个项集的超集也是非频繁的,这样可以减少我们关注的项集的个数。
#我们可以发现那些频繁出现的项集,评价的标准也是使用该项集出现的概率,出现的概率越大,表明越频繁
#输入数据集 最小支持度
#返回不同元素个数组合的大于等于最小支持度的元素集合
def apriori(dataSet,minSupport=0.5):
    #将传入的数据集-元素为列表的-列表转换成-元素为集合的-列表
    listDataSet = list(map(set, dataSet))
    #创建C1集合,即列表元素为集合;而集合只有一个元素
    c1 = createC1Set(dataSet)
    #计算符合支持度的集合元素
    retList,supportDict=scanD(listDataSet,c1,minSupport)
    #定义列表存储所有满足支持度条件的集合元素
    L=[retList]
    k=2
    #不断遍历,直到找到所有满足支持度条件且不同元素的个数组合的集合元素
    while len(L[k-2])>0 :

        #根据Ck-1产生Ck组合
        retListCk=aprioryGen(L[k-2],k)
        #对Ck组合评估支持度
        Lck, supportDictCk=scanD(listDataSet,retListCk,minSupport)
        #收集符合支持度的Ck
        L.append(Lck)
        supportDict.update(supportDictCk)
        k+=1



    return L,supportDict


#关联规则生成函数
#输入:频繁项集L 对应的支持度集合 关联规则的可信度
def genRules(L,supportDict,minReliability=0.5):

    #存储所有符合可信度的规则列表,元素格式:(R,H,conf)
    bigRules=[]
    #R->H conf Count(R U H)>=2 Count(H)<=Count(R U H)-1 conf(R->H)=S(R U H)/S(R)
    #遍历频繁项集,从第1个开始(总是从0开始),即集合元素至少要两个
    for i in range(1,len(L)):
        #H中的元素肯定来源于R中的元素及其组合,现在考虑H只有两个元素的情况
        for RUH in L[i]:
            #取出里面的每个元素,把单个元素作为一个不变集合,frozenset(x) x必须是可遍历的
            singleElemFroSet=[frozenset([item]) for item in RUH]
            m = 1
            LenR = len(RUH)
            HSet = singleElemFroSet
            LenH = len(HSet[0])

            while LenR > LenH:
                # 计算可信度
                for H in HSet:
                    # 这里使用差集还是原集??? 感觉使用原集更好理解吧??
                    conf = supportDict[RUH] / supportDict[RUH-H]
                    if conf >= minReliability:
                        # 如果可信,记录到规则列表
                        bigRules.append((RUH-H, H, conf))
                m += 1
                HSet = aprioryGen(HSet, m)
                LenH = len(HSet[0])

    return bigRules












dataSet=loadDataSet()


L,supportDict=apriori(dataSet,0.5)
print("所有元素为:\n",mat(dataSet))
print('所有符合支持度的Ck:\n', L)
print('所有组合的支持度:\n', supportDict)
bigRules=genRules(L,supportDict,0.5)
print('规则列表为:\n',bigRules)

 

 

from collections import Counter
#注意
ls=[1,2,3]

print(set(ls))

ls=[[1],[2],[3]]

#TypeError: unhashable type: 'list'
#print(set(ls))

t=(1,2,3)

print(set(t))

t=((1),(2),(3))

print(set(t))

t=[(1),(2),(3)]

print(set(t))

t=([1],[2],[3])
#元素为list,不可hash类型,无法使用set()
#print(set(t))

print(list(map(set,ls)))

ls=[1,2,3,2]

print(Counter(ls))

ls="1 1 1 2 2 2"


dicCounter=Counter(ls)

print(dicCounter)

#注意跟字典的update方法的区别
dicCounter.update("1 1 1")

print(dicCounter)

dic={'1':1,'1':1,'2':2}

print(dic)
#更新对应key的值,没有就新增
dic.update({'1':2,'3':3})


print(dic)


L=[]

ls=[[1],[2],[3]]

#添加元素,非添加引用
L.append(ls)

print(L)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值