机器学习 - Apriori算法关联规则学习

关联分析是在大规模数据中发现有趣关系的算法。这种关系包括:

1)频繁项集:经常出现在一起的物品组合。

2)关联规则:暗示两种物品之间存在很强的关系。


1. 频繁项集

怎么定义一个组合是不是频繁,有多频繁?

交易号码商品
0豆奶 莴苣
1莴苣 尿布 葡萄酒 甜菜
2豆奶 尿布 葡萄酒 橙汁
3莴苣 豆奶 尿布 葡萄酒
4莴苣 豆奶 尿布 橙汁

1.1 支持度 - support

数据集中包含该组合的记录的频率。例如支持度(豆奶) = 0.8;支持度(豆奶,尿布)= 0.6,因此可以定义一个最小支持度来排除一些非频繁项集。


1.2 置信度 - confidence

置信度定义某条关联规则的可信程度。比如从豆奶到尿布的一条关联规则,置信度(豆奶 -> 尿布)= 支持度(豆奶,尿布)/ 支持度(豆奶)= 0.75。即若某条规则适用于豆奶,则其75%适用于(豆奶,尿布)组合。


2. Apriori算法

寻找频繁项集的最简单方法是暴力搜索,但是这个计算量是随物品种类呈阶乘增长的。因此使用更加智能的Apriori算法来过滤集合寻找频繁项集。Apriori算法的核心:频繁项集的子集仍是频繁项集,非频繁项集的超集都是非频繁项集


3. 频繁项集生成

频繁项集的度量标准:最小支持度。

# -*- coding: utf-8 -*-
""" 关联规则学习, Apriori算法 """

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


class Apriori:
    """ apriori
    1. 计算单元素集合:
        [{1}, {2}, {3}, {4}, {5}]
    2. 剃掉不满足最小支持度的元素: 
        [{1}, {2}, {3}, {5}]
    3. 计算二元素集合: 
        [{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5}, {3, 4}, {3, 5}, {4, 5}]
    4. 剃掉不满足最小支持度的元素: 
        [(1, 3), (2, 3), (3, 5), (2, 5)]
    5. ....重复上述步骤, 知道集合元素包含所有单元素[{1, 2, 3, 5}]
    6. 获取最终的频繁集:
        [[{1}, {2}, {3}, {4}, {5}],
         [(1, 3), (2, 3), (3, 5), (2, 5)],
         [(2, 3, 5)]]
    """
    def __init__(self, minSupport):
        #  最小支持度
        self.minSupport = minSupport
    
    def _single_ele_set(self, train_x):
        """ 创建单元素集合列表 
        train_x:        全部训练数据, 如[[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
        single_ele_set: 单元素集合, 如[{1}, {3}, {4}, {2}, {5}]
        """
        single_ele_set = []
        length = len(train_x)
        for i in range(length):
            for j in range(len(train_x[i])):
                if set([train_x[i][j]]) not in single_ele_set:
                    single_ele_set.append(set([train_x[i][j]]))
        return single_ele_set
    
    def _cal_support(self, train_x, k_ele_set):
        """ 计算支持度 
        train_x:    全部训练数据, 如[[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
        k_ele_set:  如[{1}, {3}, {4}, {2}, {5}]
        """
        recordCnt = len(train_x)
        train_x = map(set, train_x)
        support = {}
        
        # k_ele_set中, 每个元素集在train_x中出现的次数
        for record in map(set, train_x):
            for j in k_ele_set:
                if j.issubset(record):
                    if tuple(j) not in support.keys():
                        support[tuple(set(j))] = 1
                    else:
                        support[tuple(set(j))] += 1
        
        # 求每个元素集的支持度
        for i in support.keys():
            support[i] = support[i] / recordCnt
        
        # 剔除不满足最小支持度的元素集
        temp = support.copy()
        for i in temp.keys():
            if temp[i] < self.minSupport:
                support.pop(i)
        
        # 求出频繁项集
        support = list(support.keys())
        return support
        
    def _k_ele_set(self, freqSet_k, k):
        """ 根据k-1元素集合创建k元素集合列表 
        fregSet_k:  k-1元素集合, 如[{1}, {3}, {2}, {5}]
        k_ele_set:  单元素集合, 如[{1, 3}, {1, 2}, {1, 5}, {2, 3}, {3, 5}, {2, 5}]
        """
        k_ele_set = []
        for i in range(len(freqSet_k)):
            for j in range(i+1, len(freqSet_k)):
                k_ele_set.append(set(freqSet_k[i]) | set(freqSet_k[j]))
                
        # 列表去重
        temp = k_ele_set.copy()
        k_ele_set = []
        for i in range(len(temp)):
            if temp[i] not in k_ele_set:
                k_ele_set.append(temp[i])
        return k_ele_set
    
    def apriori(self, train_x):
        """ apriori """
        single_ele_set = self._single_ele_set(train_x)
        print("1元素集合列表为: ")
        print(single_ele_set)
        
        freqSet_1 = [self._cal_support(train_x, single_ele_set)]
        print("1个元素的频繁集为: ")
        print(freqSet_1, "\n")
            
        k = 2
        while len(freqSet_1[k-2]) > 0:
            k_ele_set = self._k_ele_set(freqSet_1[k-2], k)
            print("{0}元素集合列表为: ".format(k))
            print(k_ele_set)
            
            freqSet_k = self._cal_support(train_x, k_ele_set)
            print("{0}个元素的频繁集为: ".format(k))
            print(freqSet_k, "\n")
            
            freqSet_1.append(freqSet_k)
            k += 1
        return freqSet_1
            

if __name__ == "__main__":
    train_x = load_data()
    
    obj = Apriori(minSupport=0.5)
    freqSet = obj.apriori(train_x)

4. 关联规则生成

如图{0, 1, 2, 3}频繁集内能生成的所有关联规则,其中深色表示置信度低,浅色表示置信度高。可以发现(0,1,2 -> 3)及其下面所有叶子节点全部置信度低。即如果某个频繁项集的某条规则不满足最小置信度,那么他的子规则也不满足最小置信度。



以频繁集{莴苣,豆奶,尿布}为例,假设现在的关联规则为(莴苣,豆奶 -> 尿布):

confidence(莴苣,豆奶 -> 尿布) = support(莴苣,豆奶,尿布) / support(莴苣,豆奶);


其子集为:

confidence(莴苣 -> 豆奶, 尿布) = support(莴苣,豆奶,尿布) / support(莴苣);

显然support(莴苣,豆奶) < support(莴苣);即confidence(莴苣,豆奶 -> 尿布) > confidence(莴苣 -> 豆奶, 尿布).

即若某个频繁项集的关联规则不满足最小置信度,那么这条关联规则的子规则也不满足最小置信度。通过这个规则,我们可以过滤集合,减少计算量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值