②机器学习推荐算法之关联规则(Apriori)——支持度;置信度;提升度

简介: 机器学习推荐算法之关联规则(Apriori)——支持度;置信度;提升度

先验原则

简单地说,先验原则是指,如果某个项集出现得不频繁,那么包含它的任何更大的项集必定也出现得不频繁。这就是说,如果{啤酒}是非频繁项集,那么{啤酒,比萨}也必定是非频繁项集。因此,在整理频繁项集列表时,既不需要考虑{啤酒,比萨},也不需要考虑其他任何包含啤酒的项集。


随后就会引入最小支持度和最小置信度的概念


步骤1:列出只包含一个元素的项集,比如{苹果}和{梨}。


步骤2:计算每个项集的支持度,保留那些满足最小支持度阈值条件的项集,淘汰不满足的项集。


步骤3:向候选项集(淘汰步骤2不满足的项集后的结果)中增加一个元素,并利用在步骤2中保留下来的项集产生所有可能的组合。


步骤4:重复步骤2和步骤3,为越来越大的项集确定支持度,直到没有待检查的新项集。


image.png


举个例子,假设我们的任务是找到具有高置信度的关联规则。如果{啤酒,薯片→苹果}规则的置信度很低,那么所有包含相同元素并且箭头右侧有苹果的规则都有很低的置信度,包括{啤酒→苹果,薯片}和{薯片→苹果,啤酒}。如前所述,根据先验原则,这些置信度较低的规则会被移除。这样一来,待检查的候选规则就更少了。


这样对计算的复杂度和效率就会有很大的提升空间


实际案例

🍝下面给出一个具体的关联规则的案例🍝


image.png


代码实战

频繁项集和支持度

from numpy import *
# 构造数据
def loadDataSet():
    return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
# 将所有元素转换为frozenset型字典,存放到列表中
def createC1(dataSet):
    C1 = []
    for transaction in dataSet:
        for item in transaction:
            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:    # 统计该值在整个记录中满足子集的次数(以字典的形式记录,frozenset为键)
                    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 # 排除不符合支持度元素后的元素 每个元素支持度
# 生成所有可以组合的集合
# 频繁项集列表Lk 项集元素个数k  [frozenset({2, 3}), frozenset({3, 5})] -> [frozenset({2, 3, 5})]
def aprioriGen(Lk, k):
    retList = []
    lenLk = len(Lk)
    for i in range(lenLk): # 两层循环比较Lk中的每个元素与其它元素
        for j in range(i+1, lenLk):
            L1 = list(Lk[i])[:k-2]  # 将集合转为list后取值
            L2 = list(Lk[j])[:k-2]
            L1.sort(); L2.sort()        # 这里说明一下:该函数每次比较两个list的前k-2个元素,如果相同则求并集得到k个元素的集合
            if L1==L2:
                retList.append(Lk[i] | Lk[j]) # 求并集
    return retList  # 返回频繁项集列表Ck
# 封装所有步骤的函数
# 返回 所有满足大于阈值的组合 集合支持度列表
def apriori(dataSet, minSupport = 0.5):
    D = list(map(set, dataSet)) # 转换列表记录为字典  [{1, 3, 4}, {2, 3, 5}, {1, 2, 3, 5}, {2, 5}]
    C1 = createC1(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)

也可以直接调用包:


from efficient_apriori import apriori
# 挖掘频繁项集和频繁规则
itemsets, rules = apriori(transactions, min_support=0.5,  min_confidence=1)
print("频繁项集:", itemsets)
print("关联规则:", rules)

置信度调用

#!/usr/bin/python
# -*- coding:utf-8 -*-
from itertools import combinations
#读取数据
def readdata(filename):
    data = []
    with open(filename, 'r') as f:
        while True:
            line = f.readline()
            if not line:
                break
            data.append([int(_) for _ in line.split()])
    return data
def subtract_item_set(pre_discard_itemset, candidate_set):
    '''
    首先去除候选集中不符合非频繁项集的那些元素,
    在当前候选集中去掉上一轮删除的项集,
    比如{2, 3}是非频繁项集,那么就将删除candidate_set中的{2, 3, x}这些项集
    Parameters:
    -----------
    pre_discard_itemset: 上一轮删除的项集
    candidate_set: 上一次产生的候选集
    Returns:
    --------
    返回经过pre_discard_itemset筛选后的项集列表
    '''
    saved_item_set = set()
    discard_item_set = set()
    for item in candidate_set:
        is_discard = False
        for d_item in pre_discard_itemset:
            if d_item.issubset(item):
                is_discard = True
        if is_discard:
            discard_item_set.add(tuple(item))
        else:
            saved_item_set.add(tuple(item))
    # saved_item_set, discard_item_set
    return [set(i) for i in saved_item_set], [set(i) for i in discard_item_set]
def scan_data_set(data_set, candidate_set, min_support):
    '''
    扫描一遍数据集,从候选集中挑出满足支持度的频繁项集,
    同时记录每个项集的支持度(供后面置信度计算)
    '''
    data_set = [set(i) for i in data_set]
    data_set_size = len(data_set)
    candidate_set_size = len(candidate_set)
    cand_set_count = [0 for i in range(candidate_set_size)]
    # 对候选集中的元素通过遍历数据集得到他们出现的次数
    for i in range(candidate_set_size):
        for ds in data_set:
            if candidate_set[i].issubset(ds):
                cand_set_count[i] += 1
    saved_item_set = []
    discard_item_set = []
    support_data = []
    # 删除不满足支持度的
    for i in range(candidate_set_size):
        support = cand_set_count[i] * 1.0 / data_set_size
        if support >= min_support:
            saved_item_set.append(candidate_set[i])
            support_data.append(support)
        else:
            discard_item_set.append(candidate_set[i])
    return saved_item_set, discard_item_set, support_data
def gen_cand_set(data_set, previous_freq_set, k):
    '''
    从上一次生成的候选集中产生本次的候选集(未经过支持度筛选处理的),
    只是单纯生成下一轮的组合集
    Parameters:
    -----------
    data_set: 数据集,用以生成k为1的项集
    previous_freq_set: 上一次产生的候选集
    k: 本次产生的候选集中项目的大小
    Returns:
    --------
    返回列表存储的项集,每个项集是一个集合set, [{0}, {1}, {2}, {3}, {4}...]
    '''
    if k == 1:
        # 列表解析
        item_set = set([item for sublist in data_set for item in sublist])  # 或者item_set = set(sum(data_set, []))
        return [set([i]) for i in item_set]
    elif k > 1:
        cur_freq_set = set()
        pre_fre_set_len = len(previous_freq_set)
        for i in range(pre_fre_set_len):
            for j in range(i + 1, pre_fre_set_len):
                # 遍历所有的两两组合,并将其加入到集合中
                # {(1, 2, 3), (1, 3, 5), (2, 3, 4)}
                s = previous_freq_set[i] | previous_freq_set[j]
                if len(s) == k:
                    cur_freq_set.add(tuple(s))
    return [set(i) for i in cur_freq_set]
def gen_frequecy_set(data_set, min_support):
    '''
    生成频繁项集
    Returns:
    --------
    freq_item_set: [[set(item1), set(item2)..]...] 存储频繁项集
    item_set_support: [[support_score1, s_score2..]] 每个项集对应的支持度分值
    '''
    freq_item_set = []
    item_set_support = []
    discard_item_set = None
    cur_dis_item_set_1, cur_dis_item_set_2 = [], []
    cur_item_set_size = 0
    while True:
        # 循环产生项集大小为1, 2...的项集
        cur_item_set_size += 1
        if cur_item_set_size == 1:
            # 产生初始的候选集
            cur_candiate_set = gen_cand_set(data_set, [], cur_item_set_size)
            # 将候选集分成要满足支持度的集合和不满足支持度的集合,同时记录满足支持度集合对应的支持度分值
            saved_item_set, cur_dis_item_set_1, support_data = scan_data_set(data_set, cur_candiate_set, min_support)
        else:
            # 生成该轮候选集
            cur_candiate_set = gen_cand_set(data_set, freq_item_set[-1], cur_item_set_size)
            # 去除候选集中不符合非频繁项集的那些元素
            cur_candiate_set, cur_dis_item_set_1 = subtract_item_set(discard_item_set, cur_candiate_set)
            # 对剩下的候选集,进行遍历数据集,得到保存、丢弃、支持度集合
            saved_item_set, cur_dis_item_set_2, support_data = scan_data_set(data_set, cur_candiate_set, min_support)
        if saved_item_set == []:  # 如果该轮没有产生任何频繁项集,则下一轮也不会产生新的频繁项集了,退出
            break
        freq_item_set.append(saved_item_set)  # freq_item_set存储每一轮产生的频繁项集
        discard_item_set = cur_dis_item_set_1  # discard_item_set存储每一轮产生的要丢弃的项集
        discard_item_set.extend(cur_dis_item_set_2)
        item_set_support.append(support_data)  # item_set_support存储每一轮产生的频繁项集对应的支持度值
    return freq_item_set, item_set_support
def gen_association_rules(freq_item_set, support_data, min_confd):
    '''
    生成关联规则
    Returns:
    --------
    association_rules: [(set(item1, item2, ...), itemx, confidence_score), ..]
    存储关联规则,list存储,每个元素都是一个3元组,分别表示item1 和 item2.. 推出 itemx,置信度为confidence_score
    '''
    association_rules = []
    for i in range(1, len(freq_item_set)):
        for freq_item in freq_item_set[i]:  # 对频繁项集的每一项尝试生成关联规则
            gen_rules(freq_item, support_data, min_confd, association_rules)
    return association_rules
def gen_rules(freq_item, support_data, min_confd, association_rules):
    '''
    生成关联规则,然后存储到association_rules中
    '''
    if len(freq_item) >= 2:  # 遍历二阶及以上的频繁项集
        for i in range(1, len(freq_item)):  # 生成多种关联规则
            for item in combinations(freq_item, i):  # 遍历长度为1的item的组合
                conf = support_data[frozenset(freq_item)] / float(support_data[frozenset(freq_item) - frozenset(item)])
                if conf >= min_confd:
                    association_rules.append((freq_item - set(item), item, conf))
                    gen_rules(freq_item - set(item), support_data, min_confd, association_rules)
def support_map(freq_item_set, item_set_support):
    '''
    将生成的频繁项集和每个项集对应的支持度对应起来
    Returns:
    --------
    support_data: {frozenset(item1, item2..): support_score, ..}
    '''
    support_data = {}
    for i in range(len(freq_item_set)):
        for j in range(len(freq_item_set[i])):
            support_data[frozenset(freq_item_set[i][j])] = item_set_support[i][j]
    return support_data
def apriori_gen_rules(data_set, min_support, min_confd):
    '''
    利用apriori算法生成关联规则分为两步:
    Step1:生成频繁项集
    Step2:生成关联规则
    Parameters:
    -----------
    data_set: item list
    min_support: 项集需要满足的最小支持度,|X U Y| / |All|
    min_confd: 项集之间关系需要满足的最小置信度,|X U Y| / |X|
    Returns:
    --------
    rules: 通过apriori算法挖掘出的关联规则
    '''
    freq_item_set, item_set_support = gen_frequecy_set(data_set, min_support)  # 利用Apriori算法生成频繁项集和对应的支持度
    support_data = support_map(freq_item_set, item_set_support)  # 将频繁项集和支持度联系起来
    rules = gen_association_rules(freq_item_set, support_data, min_confd)  # 利用频繁项集、对应的支持度和置信度生成关联规则
    return rules
if __name__ == '__main__':
    data_set = readdata("DATA.txt")
    min_support = 0.2 # 最小支持度
    min_confd = 0.4  # 可信度或支持度
    rules = apriori_gen_rules(data_set=data_set, min_support=min_support, min_confd=min_confd)
    print(sorted(rules, key=lambda x: x[2], reverse=True))

image.png

相关文章
|
2月前
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
117 4
|
16天前
|
算法
PAI下面的gbdt、xgboost、ps-smart 算法如何优化?
设置gbdt 、xgboost等算法的样本和特征的采样率
39 2
|
2月前
|
机器学习/深度学习 算法 数据挖掘
C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出
本文探讨了C语言在机器学习中的应用及其重要性。C语言以其高效性、灵活性和可移植性,适合开发高性能的机器学习算法,尤其在底层算法实现、嵌入式系统和高性能计算中表现突出。文章还介绍了C语言在知名机器学习库中的作用,以及与Python等语言结合使用的案例,展望了其未来发展的挑战与机遇。
51 1
|
2月前
|
机器学习/深度学习 自然语言处理 算法
深入理解机器学习算法:从线性回归到神经网络
深入理解机器学习算法:从线性回归到神经网络
|
2月前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
105 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
|
3月前
|
机器学习/深度学习 人工智能 自然语言处理
【MM2024】阿里云 PAI 团队图像编辑算法论文入选 MM2024
阿里云人工智能平台 PAI 团队发表的图像编辑算法论文在 MM2024 上正式亮相发表。ACM MM(ACM国际多媒体会议)是国际多媒体领域的顶级会议,旨在为研究人员、工程师和行业专家提供一个交流平台,以展示在多媒体领域的最新研究成果、技术进展和应用案例。其主题涵盖了图像处理、视频分析、音频处理、社交媒体和多媒体系统等广泛领域。此次入选标志着阿里云人工智能平台 PAI 在图像编辑算法方面的研究获得了学术界的充分认可。
【MM2024】阿里云 PAI 团队图像编辑算法论文入选 MM2024
|
2月前
|
机器学习/深度学习 算法
深入探索机器学习中的决策树算法
深入探索机器学习中的决策树算法
42 0
|
2月前
|
机器学习/深度学习 算法 Python
机器学习入门:理解并实现K-近邻算法
机器学习入门:理解并实现K-近邻算法
39 0
|
3月前
|
机器学习/深度学习 算法 Java
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
机器学习、基础算法、python常见面试题必知必答系列大全:(面试问题持续更新)
|
3月前
|
机器学习/深度学习 算法 决策智能
【机器学习】揭秘深度学习优化算法:加速训练与提升性能
【机器学习】揭秘深度学习优化算法:加速训练与提升性能