• 【淘宝用户购物行为分析】数据挖掘实验四



    I、项目任务要求

    任务描述:

    • 关联分析用于发现用户购买不同的商品之间存在关联和相关联系,比如A商品和B商品存在很强的相关性,常用于实体商店或在线电商的推荐系统,例如某一客户购买A商品,那么他很有可能会购买B商品,通过大量销售数据找到经常在一起购买的商品组合,可以了解用户的购买行为,根据销售的商品推荐关联商品从而给出购买建议,寻找销售新的增长点。
    • 本次实验采用关联算法从两方面对淘宝用户购物行为进行分析:
      • (1)用户购买哪种商品次数最多;
      • (2)用户购买的商品中,哪些商品组合关联度高。
    • 实验内容:分别采用AprioriFP-growth算法实现淘宝用户购物行为分析,并写出实验结果分析。

    主要任务要求:

    • 1、数据集下载网页(https://zhuanlan.zhihu.com/p/76357500)。
    • 2、分别简述Apriori、FP-growth算法思想和实现原理。
    • 3、写出实验结果分析:
      • (1) 数据集描述。
      • (2) 实验运行环境描述:如开发平台、编程语言、调参情况(最小支持度、最小置信度)等。
      • (3) 采用Apriori算法实现淘宝用户购物行为分析。
      • (4) 采用FP-growth算法实现淘宝用户购物行为分析。
      • (5) 两种算法结果比较分析:
        • 算法性能比较;
        • 兴趣因子(支持度)评估比较;
        • 淘宝用户购物行为分析比较。

    参考资料网址: 基于Python的Apriori和FP-growth关联分析算法分析用户购物关联度


    II、原理描述

    Apriori算法和FP-growth算法都是用于数据挖掘中的频繁项集挖掘算法,用于发现数据集中频繁出现的项集。以下是它们的思想和实现原理的简述:

    Apriori

    Apriori 简介

    思想:

    Apriori算法的基本思想是利用频繁项集的性质,即如果一个项集是频繁的,那么它的所有子集也是频繁的。该算法从单个项集开始,逐渐生成更大的项集,直到不能再生成频繁项集为止。算法采用逐层扫描的方法,通过连接步骤生成候选项集,然后通过剪枝步骤排除非频繁项集,最终得到频繁项集。

    实现原理:

    生成候选项集: 初始阶段,生成所有单个项的候选项集。
    扫描数据集: 统计候选项集在数据集中的支持度(出现次数)。
    剪枝: 剪枝步骤通过判断候选项集的支持度是否满足最小支持度阈值,从而剪除非频繁项集。
    连接步骤: 利用频繁(k-1)项集生成候选k项集。
    迭代: 重复进行扫描数据集、剪枝和连接步骤,直到无法生成更多的频繁项集为止。

    Apriori算法公式推导:

      1. 支持度(Support):

    支持度是指某个项集在数据集中出现的频率,可以通过以下公式计算:
    在这里插入图片描述

    2. 置信度(Confidence):
    置信度是指当一个项集出现时,另一个项集也同时出现的概率,可以通过以下公式计算:
    在这里插入图片描述

    3. 提升度(Lift):
    提升度是指X的出现对Y的出现概率提升的程度,可以通过以下公式计算:
    在这里插入图片描述

    Apriori算法调参指导

    1. 最小支持度(Min Support): 这是一个用来控制频繁项集被发现的阈值。通常,选择一个合适的最小支持度阈值是非常重要的。如果设置得太低,算法会产生大量的候选项集,导致算法运行缓慢。如果设置得太高,可能会错过潜在的关联规则。一般而言,经验法则是选择一个0.1到0.5之间的数作为最小支持度阈值,然后根据具体数据集的大小和分布进行微调。

    2. 最小置信度(Min Confidence): 这是用来过滤关联规则的阈值。通常,选择一个合适的最小置信度阈值可以帮助过滤掉不太可靠的关联规则。合适的最小置信度阈值通常根据具体的应用领域和业务需求来确定。

    3. 最小提升度(Min Lift): 提升度大于1表示X和Y的关系比随机要好,所以可以设置一个大于1的最小提升度阈值来选择有意义的关联规则。

    4. 项集大小(Itemset Size): 可以限制关联规则的项集大小,例如,只关心包含两个或三个项的规则。这可以通过设置项集的最小和最大大小来实现。

    5. 算法优化参数: 在实现Apriori算法时,可以采用一些优化措施,例如剪枝策略,以提高算法的效率。具体的剪枝策略可以根据算法的实现版本进行选择。

    以上是Apriori算法的基本公式推导和调参指导。在实际应用中,调参需要根据具体的数据集和任务需求进行反复尝试和调整,以找到最优的参数组合。

    FP-growth

    FP-growth 简介

    当谈到FP-growth算法时,主要的关注点在于频繁模式树(FP-tree)的构建和频繁项集的挖掘。以下是FP-growth算法的基本公式推导和调参指导:

    FP-growth算法公式推导

    1. 支持度(Support):
    支持度的计算方式与Apriori算法相同,即某个项集在数据集中出现的频率。

    2. 条件模式基(Conditional Pattern Base):
    条件模式基是指以某个频繁项结尾的事务集合。在FP-growth算法中,通过FP树的条件模式基可以高效地挖掘频繁项集。

    3. 频繁模式树(FP-tree):
    FP-growth算法通过构建FP树来高效地表示和挖掘频繁项集。FP树是一种特殊的前缀树,用于存储事务数据库中的频繁项集。

    FP-growth算法调参指导

    1. 最小支持度(Min Support):
      与Apriori算法类似,最小支持度是控制频繁项集被发现的阈值。选择一个适当的最小支持度阈值是关键,通常需要根据具体的数据集特性进行调整。

    2. 最小项集大小(Min Itemset Size)和最大项集大小(Max Itemset Size):
      可以设置挖掘的频繁项集的大小范围。这两个参数可以用来限制生成的频繁项集的大小,避免生成过大或过小的项集。

    3. 算法优化参数:
      在FP-growth算法中,通常不需要手动进行剪枝等操作,因为FP-growth算法本身已经通过FP树的结构进行了优化。但是,如果你使用的是自定义的FP-growth算法实现,可能需要考虑一些剪枝策略来提高算法的效率。

    4. 性能优化:
      在实际应用中,可能需要考虑对FP树的构建过程进行性能优化,例如使用压缩技术来减少内存占用,或者使用多线程等并行计算技术来加速FP树的构建。

    5. 领域特定的调整:
      根据具体的数据集特性和挖掘任务,可能需要调整算法的参数或者结合其他技术(如特征选择、数据预处理等)来提高挖掘效果。


    III、数据集描述

    数据集来源

    阿里移动推荐算法数据集

    数据描述

    变量分析

    数据预处理


    IV、具体实现过程

    采用Apriori算法实现淘宝用户购物行为分析

    • 创建初始数据集,候选项1项集
    • 从候选项集中选出频繁项集并计算支持度
    • 根据频繁项集,生成新的候选项1项集
    • 循环生成候选集并计算其支持度
    • 生成关联规则
    # -*- coding: utf-8 -*-
    import numpy as np
    import pandas as pd
    
    # todo:创建初始数据集,候选项1项集
    def apriori(data_set):
        print('创建初始候选项1项集')
        c1 = set()
        for items in data_set:
            for item in items:
                # frozenset()返回一个冻结的集合,冻结后集合不能再添加或删除任何元素
                item_set = frozenset([item])
                c1.add(item_set)
    
    # todo:从候选项集中选出频繁项集并计算支持度
    def generate_freq_supports(data_set, item_set, min_support):
        print('筛选频繁项集并计算支持度')
        freq_set = set()  # 保存频繁项集元素
        item_count = {}  # 保存元素频次,用于计算支持度
        supports = {}  # 保存支持度
    
        # 如果项集中元素在数据集中则计数
        for record in data_set:
            for item in item_set:
                # issubset()方法用于判断集合的所有元素是否都包含在指定集合中
                if item.issubset(record):
                    if item not in item_count:
                        item_count[item] = 1
                    else:
                        item_count[item] += 1
    
        data_len = float(len(data_set))
    
        # 计算项集支持度
        for item in item_count:
            if (item_count[item] / data_len) >= min_support:
                freq_set.add(item)
                supports[item] = item_count[item] / data_len
    
        return freq_set, supports
    
    # todo:根据频繁项集,生成新的候选项1项集
    # 参数:频繁项集列表 freq_set 与项集元素个数 k
    def generate_new_combinations(freq_set, k):
        print('生成新组合')
        new_combinations = set()  # 保存新组合
        sets_len = len(freq_set)  # 集合含有元素个数,用于遍历求得组合
        freq_set_list = list(freq_set)  # 集合转为列表用于索引
    
        for i in range(sets_len):
            for j in range(i + 1, sets_len):
                l1 = list(freq_set_list[i])
                l2 = list(freq_set_list[j])
                l1.sort()
                l2.sort()
    
                # 若两个集合的前k-2个项相同时,则将两个集合合并
                if l1[0:k - 2] == l2[0:k - 2]:
                    freq_item = freq_set_list[i] | freq_set_list[j]
                    new_combinations.add(freq_item)
    
        return new_combinations
    
    # todo:循环生成候选集并计算其支持度
    def apriori(data_set, min_support, max_len=None):
        print('循环生成候选集')
        max_items = 2  # 初始项集元素个数
        freq_sets = []  # 保存所有频繁项集
        supports = {}  # 保存所有支持度
    
        # 候选项1项集
        c1 = set()
        for items in data_set:
            for item in items:
                item_set = frozenset([item])
                c1.add(item_set)
    
        # 频繁项1项集及其支持度
        l1, support1 = generate_freq_supports(data_set, c1, min_support)
    
        freq_sets.append(l1)
        supports.update(support1)
    
        if max_len is None:
            max_len = float('inf')
    
        while max_items and max_items <= max_len:
            # 生成候选集
            ci = generate_new_combinations(freq_sets[-1], max_items)
            # 生成频繁项集和支持度
            li, support = generate_freq_supports(data_set, ci, min_support)
    
            # 如果有频繁项集则进入下个循环
            if li:
                freq_sets.append(li)
                supports.update(support)
                max_items += 1
            else:
                max_items = 0
    
        return freq_sets, supports
    
    # todo:生成关联规则
    def association_rules(freq_sets, supports, min_conf):
        print('生成关联规则')
        rules = []
        max_len = len(freq_sets)
    
        # 筛选符合规则的频繁集计算置信度,满足最小置信度的关联规则添加到列表
        for k in range(max_len - 1):
            for freq_set in freq_sets[k]:
                for sub_set in freq_sets[k + 1]:
                    if freq_set.issubset(sub_set):
                        frq = supports[sub_set]
                        conf = supports[sub_set] / supports[freq_set]
                        rule = (freq_set, sub_set - freq_set, frq, conf)
                        if conf >= min_conf:
                            print(freq_set, "-->", sub_set - freq_set, 'frq:', frq, 'conf:', conf)
                            rules.append(rule)
        return rules
    
    
    if __name__ == '__main__':
        # 读取淘宝用户行为数据
        data = pd.read_csv(r'data/demo4/input/demo.csv')
        data = data[['user_id', 'item_id']]
    
        # 关联规则中不考虑多次购买同一件物品,删除重复数据
        data = data.drop_duplicates()
    
        # 初始化列表
        data_set = []
    
        # 分组聚合,同一用户购买多种商品的合并为一条数据,只有1件商品的没有意义,需要进行过滤
        groups = data.groupby(by='user_id')
        for group in groups:
            if len(group[1]) >= 2:
                data_set.append(group[1]['item_id'].tolist())
    
        # L为频繁项集,support_data为支持度
        L, support_data = apriori(data_set, min_support=0.05)
        association_rules = association_rules(L, support_data, min_conf=0.3)
        print("关联柜规则:----")
        print('关联规则:\n',association_rules)
        for i in association_rules:
            print(i)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146

    采用FP-growth算法实现淘宝用户购物行为分析

    • 数据转换为同一单号包含多个商品的列表
    • 生成关联规则,计算支持度、置信度和提升度
    # -*- coding: utf-8 -*-
    import numpy as np
    import pandas as pd
    from sqlalchemy import create_engine
    import itertools  # itertools用于高效循环的迭代函数集合
    import sys, time
    
    # sys.path.append(r"D:\关联分析\关联分析2")  # 调包失败时,把包所在路径添加到系统路径中
    import fp_growth as fpg  # 导入fp-growth算法
    
    start = time.time()
    
    
    def convertData(data):
        """数据转换为同一单号包含多个商品的列表"""
        # 关联规则中不考虑多次购买同一件物品,删除重复数据
        data = data.drop_duplicates()
        # 初始化列表
        itemSets = []
        it_list = []
        # 分组聚合,同一用户购买多种商品的合并为一条数据,只有1件商品的没有意义,需要进行过滤
        groups = data.groupby(by=['user_id'])
        for group in groups:
            if len(group[1]) >= 2:
                itemSets.append(group[1]['item_id'].tolist())
        return itemSets
    
    
    def generate_association_rules(patterns, total, min_confidence):
        """
        生成关联规则,计算支持度、置信度和提升度
        """
        antecedent_list = []
        consequent_list = []
    
        support_list = []
        confidence_list = []
        lift_list = []
    
        count_antecedent = []
        p_antecedent = []
        count_consequent = []
        p_consequent = []
        count_ant_con = []
    
        for itemset in patterns.keys():
            upper_support = patterns[itemset]  # A & B
    
            for i in range(1, len(itemset)):
                for antecedent in itertools.combinations(itemset, i):
                    """
                    itertools.combinations()用于创建一个迭代器,
                    返回iterable中所有长度为r的子序列,
                    返回的子序列中的项按输入iterable中的顺序排序
                    """
                    antecedent = tuple(sorted(antecedent))
                    consequent = tuple(sorted(set(itemset) - set(antecedent)))
    
                    if antecedent in patterns:
                        lower_support = patterns[antecedent]  # A
                        consequent_support = patterns[consequent]  # B
                        p_lower_support = lower_support / total  # P(A)
                        p_consequent_support = consequent_support / total  # P(B)
                        support = round(float(upper_support) / total, 6)  # 支持度Support = P(A & B)
                        confidence = float(upper_support) / lower_support  # 置信度Confidence = P(A & B)/ P(A)
                        lift = confidence / p_consequent_support  # 提升度Lift = ( P(A & B)/ P(A) ) / P(B) = P(A & B)/ P(A) / P(B)
    
                        if confidence >= min_confidence:
                            antecedent_list.append(list(antecedent))
                            consequent_list.append(list(consequent))
                            support_list.append(support)
                            confidence_list.append(confidence)
                            lift_list.append(lift)
    
                            count_antecedent.append(lower_support)  # count(A)
                            p_antecedent.append(p_lower_support)  # P(A)
                            count_consequent.append(consequent_support)  # count(B)
                            p_consequent.append(p_consequent_support)  # P(B)
                            count_ant_con.append(upper_support)  # count(AB)
    
        rules_col = {'antecedent': antecedent_list,
                     'consequent': consequent_list,
                     'count_antecedent': count_antecedent,
                     'antecedent_support': p_antecedent,
                     'count_consequent': count_consequent,
                     'consequent_support': p_consequent,
                     'count_ant_con': count_ant_con,
                     'support': support_list,
                     'confidence': confidence_list,
                     'lift': lift_list}
    
        rules = pd.DataFrame(rules_col)
        #    col = ['antecedent','consequent','count_antecedent','antecedent_support',
        #           'count_consequent','consequent_support','count_ant_con','support',
        #           'confidence','lift']
        col = ['antecedent', 'consequent', 'support', 'confidence', 'lift']
        rules = rules[col]
        rules.sort_values(by=['support', 'confidence'], ascending=False, inplace=True)
        return rules
    
    
    if __name__ == '__main__':
    
        # 导入数据
        data = pd.read_csv(r'data/demo4/input/tianchi_mobile_recommend_train_user.zip')
        data = data[['user_id', 'item_id']]
        # 转换数据
        dataset = convertData(data)
        total = len(dataset)
        print('总订单数:', total)
    
        '''
        find_frequent_itemsets()调用函数生成频繁项集和频数
        minimum_support表示设置最小支持度(频数),即频数大于等于minimum_support,保存此频繁项,否则删除
        include_support表示返回结果是否包含支持度(频数),若include_support=True,返回结果中包含itemset和support,否则只返回itemset
        '''
        frequent_itemsets = fpg.find_frequent_itemsets(dataset, minimum_support=50, include_support=True)
    
        result = []
        for itemset, support in frequent_itemsets:  # 将generator结果存入list
            result.append((itemset, support))
    
        result = sorted(result, key=lambda i: i[0])  # 排序后输出
    
        item_list = []
        itemset_list = []
        support_list = []
        for itemset, support in result:
            #        print(str(itemset) + ' ' + str(support)) #频繁项集和出现次数
            item_list.append(itemset)  # 保存为列表,用于输出频繁项集结果
    
            itemset = tuple(sorted(itemset))  # 先转换为元组,用于后续生成关联规则
            itemset_list.append(itemset)
            support_list.append(support)
    
        # 构建字典
        patterns = dict(zip(itemset_list, support_list))
        print('频繁项集总数:', len(patterns))
    
        # 生成关联规则,计算支持度、置信度和提升度
        # min_confidence代表最小置信度
        rules = generate_association_rules(patterns, total, min_confidence=0.3)
        print('关联规则:\n', rules.head())
        print('结果总数:', len(rules))
    
        ## 输出结果,输出到同一份excel文件不同的工作表中
        # 输出频繁集
        sup = {'item_id': item_list, 'frequency': support_list}
        sup = pd.DataFrame(sup)
        sup['support'] = round(sup['frequency'] / float(total), 6)
        sup.sort_values(by=['support'], ascending=False, inplace=True)
        sup_col = ['item_id', 'frequency', 'support']
        sup = sup[sup_col]
    
    
        writer = pd.ExcelWriter(r'data/demo4/output/fp-growth-result.xlsx')
        sup.to_excel(excel_writer=writer, sheet_name='support', index=False)
        # 输出关联规则
        rules.to_excel(excel_writer=writer, sheet_name='rules', index=False)
        writer.close()
    
        end = time.time()
        print('Running time: %s Seconds' % (end - start))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163

    在这里插入图片描述
    在这里插入图片描述


    V、结果分析

    • apriori
      在这里插入图片描述
    • fp-growth
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

    VI、完整代码

    • A
    # -*- coding: utf-8 -*-
    import numpy as np
    import pandas as pd
    
    # todo:创建初始数据集,候选项1项集
    def apriori(data_set):
        print('创建初始候选项1项集')
        c1 = set()
        for items in data_set:
            for item in items:
                # frozenset()返回一个冻结的集合,冻结后集合不能再添加或删除任何元素
                item_set = frozenset([item])
                c1.add(item_set)
    
    # todo:从候选项集中选出频繁项集并计算支持度
    def generate_freq_supports(data_set, item_set, min_support):
        print('筛选频繁项集并计算支持度')
        freq_set = set()  # 保存频繁项集元素
        item_count = {}  # 保存元素频次,用于计算支持度
        supports = {}  # 保存支持度
    
        # 如果项集中元素在数据集中则计数
        for record in data_set:
            for item in item_set:
                # issubset()方法用于判断集合的所有元素是否都包含在指定集合中
                if item.issubset(record):
                    if item not in item_count:
                        item_count[item] = 1
                    else:
                        item_count[item] += 1
    
        data_len = float(len(data_set))
    
        # 计算项集支持度
        for item in item_count:
            if (item_count[item] / data_len) >= min_support:
                freq_set.add(item)
                supports[item] = item_count[item] / data_len
    
        return freq_set, supports
    
    # todo:根据频繁项集,生成新的候选项1项集
    # 参数:频繁项集列表 freq_set 与项集元素个数 k
    def generate_new_combinations(freq_set, k):
        print('生成新组合')
        new_combinations = set()  # 保存新组合
        sets_len = len(freq_set)  # 集合含有元素个数,用于遍历求得组合
        freq_set_list = list(freq_set)  # 集合转为列表用于索引
    
        for i in range(sets_len):
            for j in range(i + 1, sets_len):
                l1 = list(freq_set_list[i])
                l2 = list(freq_set_list[j])
                l1.sort()
                l2.sort()
    
                # 若两个集合的前k-2个项相同时,则将两个集合合并
                if l1[0:k - 2] == l2[0:k - 2]:
                    freq_item = freq_set_list[i] | freq_set_list[j]
                    new_combinations.add(freq_item)
    
        return new_combinations
    
    # todo:循环生成候选集并计算其支持度
    def apriori(data_set, min_support, max_len=None):
        print('循环生成候选集')
        max_items = 2  # 初始项集元素个数
        freq_sets = []  # 保存所有频繁项集
        supports = {}  # 保存所有支持度
    
        # 候选项1项集
        c1 = set()
        for items in data_set:
            for item in items:
                item_set = frozenset([item])
                c1.add(item_set)
    
        # 频繁项1项集及其支持度
        l1, support1 = generate_freq_supports(data_set, c1, min_support)
    
        freq_sets.append(l1)
        supports.update(support1)
    
        if max_len is None:
            max_len = float('inf')
    
        while max_items and max_items <= max_len:
            # 生成候选集
            ci = generate_new_combinations(freq_sets[-1], max_items)
            # 生成频繁项集和支持度
            li, support = generate_freq_supports(data_set, ci, min_support)
    
            # 如果有频繁项集则进入下个循环
            if li:
                freq_sets.append(li)
                supports.update(support)
                max_items += 1
            else:
                max_items = 0
    
        return freq_sets, supports
    
    # todo:生成关联规则
    def association_rules(freq_sets, supports, min_conf):
        print('生成关联规则')
        rules = []
        max_len = len(freq_sets)
    
        # 筛选符合规则的频繁集计算置信度,满足最小置信度的关联规则添加到列表
        for k in range(max_len - 1):
            for freq_set in freq_sets[k]:
                for sub_set in freq_sets[k + 1]:
                    if freq_set.issubset(sub_set):
                        frq = supports[sub_set]
                        conf = supports[sub_set] / supports[freq_set]
                        rule = (freq_set, sub_set - freq_set, frq, conf)
                        if conf >= min_conf:
                            print(freq_set, "-->", sub_set - freq_set, 'frq:', frq, 'conf:', conf)
                            rules.append(rule)
        return rules
    
    
    if __name__ == '__main__':
        # 读取淘宝用户行为数据
        data = pd.read_csv(r'data/demo4/input/demo.csv')
        data = data[['user_id', 'item_id']]
    
        # 关联规则中不考虑多次购买同一件物品,删除重复数据
        data = data.drop_duplicates()
    
        # 初始化列表
        data_set = []
    
        # 分组聚合,同一用户购买多种商品的合并为一条数据,只有1件商品的没有意义,需要进行过滤
        groups = data.groupby(by='user_id')
        for group in groups:
            if len(group[1]) >= 2:
                data_set.append(group[1]['item_id'].tolist())
    
        # L为频繁项集,support_data为支持度
        L, support_data = apriori(data_set, min_support=0.05)
        association_rules = association_rules(L, support_data, min_conf=0.3)
        print("关联柜规则:----")
        print('关联规则:\n',association_rules)
        for i in association_rules:
            print(i)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • B
    # -*- coding: utf-8 -*-
    import numpy as np
    import pandas as pd
    from sqlalchemy import create_engine
    import itertools  # itertools用于高效循环的迭代函数集合
    import sys, time
    
    # sys.path.append(r"D:\关联分析\关联分析2")  # 调包失败时,把包所在路径添加到系统路径中
    import fp_growth as fpg  # 导入fp-growth算法
    
    start = time.time()
    
    
    def convertData(data):
        """数据转换为同一单号包含多个商品的列表"""
        # 关联规则中不考虑多次购买同一件物品,删除重复数据
        data = data.drop_duplicates()
        # 初始化列表
        itemSets = []
        it_list = []
        # 分组聚合,同一用户购买多种商品的合并为一条数据,只有1件商品的没有意义,需要进行过滤
        groups = data.groupby(by=['user_id'])
        for group in groups:
            if len(group[1]) >= 2:
                itemSets.append(group[1]['item_id'].tolist())
        return itemSets
    
    
    def generate_association_rules(patterns, total, min_confidence):
        """
        生成关联规则,计算支持度、置信度和提升度
        """
        antecedent_list = []
        consequent_list = []
    
        support_list = []
        confidence_list = []
        lift_list = []
    
        count_antecedent = []
        p_antecedent = []
        count_consequent = []
        p_consequent = []
        count_ant_con = []
    
        for itemset in patterns.keys():
            upper_support = patterns[itemset]  # A & B
    
            for i in range(1, len(itemset)):
                for antecedent in itertools.combinations(itemset, i):
                    """
                    itertools.combinations()用于创建一个迭代器,
                    返回iterable中所有长度为r的子序列,
                    返回的子序列中的项按输入iterable中的顺序排序
                    """
                    antecedent = tuple(sorted(antecedent))
                    consequent = tuple(sorted(set(itemset) - set(antecedent)))
    
                    if antecedent in patterns:
                        lower_support = patterns[antecedent]  # A
                        consequent_support = patterns[consequent]  # B
                        p_lower_support = lower_support / total  # P(A)
                        p_consequent_support = consequent_support / total  # P(B)
                        support = round(float(upper_support) / total, 6)  # 支持度Support = P(A & B)
                        confidence = float(upper_support) / lower_support  # 置信度Confidence = P(A & B)/ P(A)
                        lift = confidence / p_consequent_support  # 提升度Lift = ( P(A & B)/ P(A) ) / P(B) = P(A & B)/ P(A) / P(B)
    
                        if confidence >= min_confidence:
                            antecedent_list.append(list(antecedent))
                            consequent_list.append(list(consequent))
                            support_list.append(support)
                            confidence_list.append(confidence)
                            lift_list.append(lift)
    
                            count_antecedent.append(lower_support)  # count(A)
                            p_antecedent.append(p_lower_support)  # P(A)
                            count_consequent.append(consequent_support)  # count(B)
                            p_consequent.append(p_consequent_support)  # P(B)
                            count_ant_con.append(upper_support)  # count(AB)
    
        rules_col = {'antecedent': antecedent_list,
                     'consequent': consequent_list,
                     'count_antecedent': count_antecedent,
                     'antecedent_support': p_antecedent,
                     'count_consequent': count_consequent,
                     'consequent_support': p_consequent,
                     'count_ant_con': count_ant_con,
                     'support': support_list,
                     'confidence': confidence_list,
                     'lift': lift_list}
    
        rules = pd.DataFrame(rules_col)
        #    col = ['antecedent','consequent','count_antecedent','antecedent_support',
        #           'count_consequent','consequent_support','count_ant_con','support',
        #           'confidence','lift']
        col = ['antecedent', 'consequent', 'support', 'confidence', 'lift']
        rules = rules[col]
        rules.sort_values(by=['support', 'confidence'], ascending=False, inplace=True)
        return rules
    
    
    if __name__ == '__main__':
    
        # 导入数据
        data = pd.read_csv(r'data/demo4/input/tianchi_mobile_recommend_train_user.zip')
        data = data[['user_id', 'item_id']]
        # 转换数据
        dataset = convertData(data)
        total = len(dataset)
        print('总订单数:', total)
    
        '''
        find_frequent_itemsets()调用函数生成频繁项集和频数
        minimum_support表示设置最小支持度(频数),即频数大于等于minimum_support,保存此频繁项,否则删除
        include_support表示返回结果是否包含支持度(频数),若include_support=True,返回结果中包含itemset和support,否则只返回itemset
        '''
        frequent_itemsets = fpg.find_frequent_itemsets(dataset, minimum_support=50, include_support=True)
    
        result = []
        for itemset, support in frequent_itemsets:  # 将generator结果存入list
            result.append((itemset, support))
    
        result = sorted(result, key=lambda i: i[0])  # 排序后输出
    
        item_list = []
        itemset_list = []
        support_list = []
        for itemset, support in result:
            #        print(str(itemset) + ' ' + str(support)) #频繁项集和出现次数
            item_list.append(itemset)  # 保存为列表,用于输出频繁项集结果
    
            itemset = tuple(sorted(itemset))  # 先转换为元组,用于后续生成关联规则
            itemset_list.append(itemset)
            support_list.append(support)
    
        # 构建字典
        patterns = dict(zip(itemset_list, support_list))
        print('频繁项集总数:', len(patterns))
    
        # 生成关联规则,计算支持度、置信度和提升度
        # min_confidence代表最小置信度
        rules = generate_association_rules(patterns, total, min_confidence=0.3)
        print('关联规则:\n', rules.head())
        print('结果总数:', len(rules))
    
        ## 输出结果,输出到同一份excel文件不同的工作表中
        # 输出频繁集
        sup = {'item_id': item_list, 'frequency': support_list}
        sup = pd.DataFrame(sup)
        sup['support'] = round(sup['frequency'] / float(total), 6)
        sup.sort_values(by=['support'], ascending=False, inplace=True)
        sup_col = ['item_id', 'frequency', 'support']
        sup = sup[sup_col]
    
    
        writer = pd.ExcelWriter(r'data/demo4/output/fp-growth-result.xlsx')
        sup.to_excel(excel_writer=writer, sheet_name='support', index=False)
        # 输出关联规则
        rules.to_excel(excel_writer=writer, sheet_name='rules', index=False)
        writer.close()
    
        end = time.time()
        print('Running time: %s Seconds' % (end - start))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163

    完整代码

    import pandas as pd
    from mlxtend.frequent_patterns import apriori, fpgrowth
    from mlxtend.preprocessing import TransactionEncoder
    import time
    import matplotlib.pyplot as plt
    
    # 加载数据集
    data = pd.read_csv('data/demo4/input/tianchi_mobile_recommend_train_user.csv')
    
    # 用户购物频率分析
    user_shopping_frequency = data['user_id'].value_counts().head(10)
    
    # 热门商品分析,选择购买次数最多的前20个商品
    popular_items = data['item_id'].value_counts().head(20)
    
    # 将数据转换为适合关联分析的格式
    transactions = data.groupby('user_id')['item_id'].apply(list).values.tolist()
    
    # 使用TransactionEncoder将数据转换为布尔矩阵
    te = TransactionEncoder()
    te_ary = te.fit(transactions).transform(transactions)
    df = pd.DataFrame(te_ary, columns=te.columns_)
    
    # 使用FP-growth算法进行关联分析
    fpgrowth_result = fpgrowth(df, min_support=0.1, use_colnames=True)
    
    # 使用Apriori算法进行关联分析
    apriori_result = apriori(df, min_support=0.1, use_colnames=True)
    
    # Save results to Excel
    fpgrowth_result.to_excel('data/demo4/input/fpgrowth_result.xlsx', index=False)
    apriori_result.to_excel('data/demo4/input/apriori_result.xlsx', index=False)
    
    # Top 20 itemsets with highest support
    top_20_fpgrowth = fpgrowth_result.nlargest(20, 'support')
    top_20_apriori = apriori_result.nlargest(20, 'support')
    
    
    # 算法性能对比(运行时间)
    fpgrowth_time = time.time()
    fpgrowth(df, min_support=0.01, use_colnames=True)
    fpgrowth_time = time.time() - fpgrowth_time
    
    apriori_time = time.time()
    apriori(df, min_support=0.01, use_colnames=True)
    apriori_time = time.time() - apriori_time
    
    # 兴趣因子(支持度)评估比较
    support_fpgrowth = fpgrowth_result['support']
    support_apriori = apriori_result['support']
    
    # 用户购物偏好分析
    plt.figure(figsize=(12, 6))
    user_shopping_frequency.plot(kind='barh', color='skyblue')
    plt.xlabel('Number of Purchases per User')
    plt.ylabel('User ID')
    plt.title('Top 10 Popular User')
    plt.show()
    
    # 热门商品分析可视化
    plt.figure(figsize=(10, 8))
    popular_items.plot(kind='barh', color='coral')
    plt.xlabel('Number of Purchases')
    plt.ylabel('Item ID')
    plt.title('Top 20 Popular Items')
    plt.gca().invert_yaxis()
    plt.show()
    
    # 两种算法结果比较分析,可视化对比展示
    plt.figure(figsize=(8, 6))
    plt.bar(['FP-growth', 'Apriori'], [fpgrowth_time, apriori_time], color=['blue', 'green'])
    plt.xlabel('Algorithm')
    plt.ylabel('Runtime (seconds)')
    plt.title('Runtime Comparison between FP-growth and Apriori')
    plt.show()
    
    
    plt.figure(figsize=(10, 6))
    plt.scatter(fpgrowth_result['itemsets'].apply(lambda x: len(x)).values, support_fpgrowth, label='FP-growth', color='blue', alpha=0.7)
    plt.scatter(apriori_result['itemsets'].apply(lambda x: len(x)).values, support_apriori, label='Apriori', color='green', alpha=0.7)
    plt.xlabel('Number of Items in Itemset')
    plt.ylabel('Support')
    plt.legend()
    plt.title('Support vs Number of Items in Itemset (Scatter Plot)')
    plt.show()
    
    # todo:修改意见
    # 1. 将输出的结果保存到excel文档(位置:data/demo4/input)
    # 2. suport支持度最高的20个数据进行可视化对比展示(散点图)
    # 2. support分布图
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
  • 相关阅读:
    Spring的注解开发-Spring配置其它注解
    [自用]手推DDPM公式
    Centos系统安装Yapi(传统方式安装)
    【C语言刷题】牛客JZ65——不用四则运算作加法
    vue3 watch 异步方法
    成长在于积累——https 认证失败的学习与思考
    C# 找出两个Rectangle或是矩形的相互重合与非重合部分?
    把图片压缩成指定大小,释放你的内存空间
    【Spring | AOP】日志拦截
    N-128基于springboot,vue酒店管理系统
  • 原文地址:https://blog.csdn.net/Lenhart001/article/details/133918741