数据挖掘算法(一)——Apriori

1.关联分析

关联分析是一种在大规模中寻找关系的非监督学习算法。

这些关系可以有两种形式:频繁项集、关联规则

        频繁项集:经常出现在一块的物品的集合

        关联规则:暗示两种物品之间可能存在很强的关系

一个例子:

数据挖掘算法(一)——Apriori_第1张图片

在这里,我们不关心顾客买了几件,只关心买了什么,在这里明确几个定义。

事务:每一条交易称为一个事务。例如,在这个例子中包含了5个事务。

:交易的每一个物品称为一个项,例如,豆奶、尿布等。

项集:包含零个或者多个项的集合叫做项集,例如{豆奶,莴苣}。

k-项集:包含k个项的项集叫做k-项集。例如{豆奶}叫做1-项集,{豆奶,尿布,啤酒}叫做3-项集。

前件和后件:对于规则{尿布}-→{啤酒}, {尿布}叫做前件,{啤酒}叫做后件。

频繁项集是指那些经常出现在一起的物品,例如上图的{葡萄酒、尿布、豆奶},从上面的数据集中也可以找到尿布->葡萄酒的关联规则,这意味着有人买了尿布,那很有可能他也会购买葡萄酒。那如何定义和表示频繁项集和关联规则呢?这里引入支持度和可信度(置信度)。

2.评估频繁项集标准

2.1支持度

支持度就是几个关联数据在数据集中出现的次数占总数据集的比重。上图中,豆奶的支持度为4/5,(豆奶、尿布)为3/5。

                                                   Support(X,Y)=P(XY)= \frac{number(XY)}{num(AllSample)}

一般来说, 支持度高的数据不一定构成频繁项集,但是支持度太低的数据肯定不构成频繁项。对项集来说的,因此,可以定义一个最小支持度,而只保留满足最小支持度的项集,起到一个过滤的作用。

2.2置信度

置信度体现一个数据出现以后,另一个数据出现的概率,或者说针对数据的条件概率,如果我们有数据X和Y,X对Y的置信度为

                                                  Confidence(X->Y)=P(XY)/P(X)

其实就是当x出现之后,y出现的概率。如{尿布}->{葡萄酒}这样的关联规则来定义的。计算为 支持度{尿布,葡萄酒}/支持度{尿布},其中{尿布,葡萄酒}的支持度为3/5,{尿布}的支持度为4/5,所以“尿布->葡萄酒”的可行度为3/4=0.75,这意味着尿布的记录中,我们的规则有75%都适用。

为什么使用支持度和置信度?支持度是一种重要度量,因为支持度很低的规则可能只是偶然出现,从商务角度来看,低支持度的规则多半也是无意义的,因为对顾客很少同时购买的商品进行促销可能并无益处。因此,支持度通常用来删去那些无意义的规则,此外,支持度还具有一种期望的性质,可以用于关联规则的有效发现。

另一方面,置信度度量通过规则进行推理具有可靠性。对于给定的规则X->Y, 置信度越高,Y在包含X的事务中出现的可能性就越大。置信度也可以估计Y在给定X下的条件概率。

同时,应当小心解释关联分析的结果。由关联规则作出的推论并不必然蕴涵因果关系。它只表示规则前件和后件同时出现的一种概率。


3.Apiroir算法原理

有了可以量化的计算方式,我们却还不能立刻运算,这是因为如果我们直接运算所有的数据,运算量极其的大,很难实现,这里说明一下,假设我们只有 4 种商品:商品0,商品1,商品 2,商品3. 那么如何得可能被一起购买的商品的组合?

数据挖掘算法(一)——Apriori_第2张图片

上图显示了物品之间所有可能的组合,从上往下一个集合是 Ø,表示不包含任何物品的空集,物品集合之间的连线表明两个或者更多集合可以组合形成一个更大的集合。我们的目标是找到经常在一起购买的物品集合。这里使用集合的支持度来度量其出现的频率。一个集合出现的支持度是指有多少比例的交易记录包含该集合。例如,对于上图,要计算 0,3 的支持度,直接的想法是遍历每条记录,统计包含有 0 和 3 的记录的数量,使用该数量除以总记录数,就可以得到支持度。而这只是针对单个集合 0,3. 要获得每种可能集合的支持度就需要多次重复上述过程。对于上图,虽然仅有4中物品,也需要遍历数据15次。随着物品数目的增加,遍历次数会急剧增加,对于包含 N 种物品的数据集共有 2^N−1 种项集组合。为了降低计算时间,研究人员发现了 Apriori 原理,可以帮我们减少感兴趣的频繁项集的数目。

Apriori 的原理:如果某个项集是频繁项集,那么它所有的子集也是频繁的。即如果 {0,1} 是频繁的,那么 {0}, {1} 也一定是频繁的。

这个原理直观上没有什么用,但是反过来看就有用了,也就是说如果一个项集是非频繁的,那么它的所有超集也是非频繁的。如下图所示:

 

数据挖掘算法(一)——Apriori_第3张图片

 

 

 

四.Apiroir算法过程

 

数据挖掘算法(一)——Apriori_第4张图片

C1, C2, ... Ck分别表示1-项集, 2-项集,... k-项集; .

L1, L2, ... Lk分别表示有k个数据项的频繁项集。

Scan表示数据集扫描函数。该函数起到的作用是支持度过滤,满足最小支持度的项集才留下,不满足最小支持度的项集直接舍掉。

下面我们用python代码来实现这一过程~

 

1.先把数据集中1-项集找出来

[frozenset({1}), frozenset({2}), frozenset({3}), frozenset({4}), frozenset({5})]

2.利用Scan,计算支持度并过滤

3.循环:利用过滤后的k-项集,找到k+1-项集,构成候选项集;

              利用Scan过滤。

    直到全部完成

也就是数据挖掘算法(一)——Apriori_第5张图片

"""找出[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]的频繁项集"""
from numpy import *
# 构造数据
def loadDataSet():
    return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]

#将所有元素转化为frozenset字典型
def createC(dataSet):
    C1=[]
    for transcation in dataSet:
        for item in transcation:
            if not [item] in C1:
                C1.append([item])

    C1.sort()
    # 使用frozenset是为了后面可以将这些值作为字典的键
    return list(map(frozenset,C1))# frozenset一种不可变的集合,set可变集合

# 过滤掉不符合支持度的集合
# 返回 频繁项集列表retList 所有元素的支持度字典
def scanD(D, Ck, minSupport):
    ssCnt={}
    for tid in D:
        for can in Ck:
            if can.issubset(tid):   # 判断can是否是tid的《子集》 (这里使用子集的方式来判断两者的关系)
                if can not in ssCnt:
                    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.append(key)
        supportData[key]=support
    return retList,supportData


# 生成所有可以组合的集合
# 频繁项集列表Lk 项集元素个数k  [frozenset({2, 3}), frozenset({3, 5})] -> [frozenset({2, 3, 5})]

def aprioriGen(Lk, k):
    print("Lk",Lk)
    retList = []
    lenLk = len(Lk)
    for i in range(lenLk):  # 两层循环比较Lk中的每个元素与其它元素
        for j in range(i+1,lenLk):
            L1=list(Lk[i])[:k-2]## 这里说明一下:该函数每次比较两个list的前k-2个元素,如果相同则求并集得到k个元素的集合
            L2=list(Lk[j])[:k-2]##比如要[frozenset({2, 3}), frozenset({3, 5})] -> [frozenset({2, 3, 5})]这里k=3,[:1]
            # 只需要比较第一个元素,两个集合只有最后一个数不同,就可以把集合扩展为2+1
            L1.sort()
            L2.sort()
            if(L1==L2):
                print("L1",L1,"L2",L2)
                retList.append(Lk[i]|Lk[j])
                print("Lk[i]",Lk[i],"Lk[j]",Lk[j])
    print("retList",retList)
    return retList

def apriori(dataSet, minSupport = 0.5):
    D = list(map(set, dataSet))  # 转换列表记录为字典  [{1, 3, 4}, {2, 3, 5}, {1, 2, 3, 5}, {2, 5}]
    C1 = createC(dataSet)  # 将每个元素转会为frozenset字典    [frozenset({1}), frozenset({2}), frozenset({3}), frozenset({4}), frozenset({5})]
    L1, supportData = scanD(D, C1, minSupport)  # 过滤数据
    L = [L1]
    k = 2
    while (len(L[k - 2]) > 0):  # 若仍有满足支持度的集合则继续做关联分析
        Ck = aprioriGen(L[k - 2], k)  # Ck候选频繁项集
        Lk, supK = scanD(D, Ck, minSupport)  # Lk频繁项集
        supportData.update(supK)  # 更新字典(把新出现的集合:支持度加入到supportData中)
        L.append(Lk)
        k += 1  # 每次新组合的元素都只增加了一个,所以k也+1(k表示元素个数)
    return L, supportData



dataSet = loadDataSet()
L,suppData = apriori(dataSet)
print(L)
print(suppData)

k-2解惑:
数据挖掘算法(一)——Apriori_第6张图片

 

 

 

 

你可能感兴趣的:(数据挖掘)