微信推文属性的关联分析 by Apriori算法

本文通过Apriori算法来对某公司的微信推文属性的关联分析。

本文的目的

找出可让 [‘阅读量超过1K’] 的因素,以便达到这些因素使微信推文阅读量提升。

本文的结论

若想让微信推文阅读量超过1K,该公司可从[‘公司为信息源’]、[‘文章置顶’] 、[‘公司or厂’] 或综合手段进行。

  • [‘公司为信息源’] —> [‘阅读量超过1K’] ,几率为50%
  • [‘文章置顶’] —> [‘阅读量超过1K’] ,几率为69%
  • [‘公司or厂’] —> [‘阅读量超过1K’] ,几率为64%
  • [‘公司为信息源’, ‘文章置顶’] —> [‘阅读量超过1K’] ,几率为69%
  • [‘公司为信息源’, ‘公司or厂’] —> [‘阅读量超过1K’] ,几率为68%

数据源

从某订阅号下载过去半年的统计数据共计160笔(栏位见下方栏位),并做好受欢迎程度的类型标签,并整理成Excel档案。在这里插入图片描述

分析代码

from numpy import *

# apriori.py
import apriori

# 加载数据

import openpyxl
wb = openpyxl.load_workbook('WeChat20200923_np2.xlsx')
sheet = wb['sheet1']
row = sheet.max_row
column = sheet.max_column
set_for_all_row = []
for i in range(2,row+1):
    set_for_one_row = []
    for j in range(1,column+1):
        values = sheet.cell(row=i, column=j).value
        if values !=0:
            set_for_one_row.append(values)
    if len(set_for_one_row) > 0:
        set_for_all_row.append(set_for_one_row)

# 示范数据打印
print(set_for_all_row[0])
# ['文章置顶', '表彰表扬', '社团活动or员工活动', '公司为信息源', '公司or厂']
            
data_arr = set_for_all_row
# 创建项个数为1 的候选项集
set_0 = apriori.create_set_0(data_arr)
# 扫描项个数为1的候选项集,生成项个数为1 的频繁项集,以及所有候选项集的支持度
set_0_scanned, support_data = apriori.scan_data_set(list(map(set, data_arr)), set_0, 0.3)

print('支持度较高的数据')
print(set_0_scanned)

#Out:
#支持度较高的数据
#[frozenset({'公司or厂'}), frozenset({'公司为信息源'}), frozenset({'文章置顶'}), frozenset({'社团活动or员工活动'}), frozenset({'两周内前后关联'}), frozenset({'新颖吸引'}), frozenset({'阅读量超过1K'})]

print('支持度的数据')
support_data
#Out:
#{frozenset({'公司or厂'}): 0.5174418604651163,
# frozenset({'公司为信息源'}): 0.8372093023255814,
# frozenset({'文章置顶'}): 0.5058139534883721,
# frozenset({'社团活动or员工活动'}): 0.5,
# frozenset({'表彰表扬'}): 0.11627906976744186,
# frozenset({'两周内前后关联'}): 0.3313953488372093,
# frozenset({'内容有视频'}): 0.22093023255813954,
# frozenset({'文章封面吸引'}): 0.12790697674418605,
# frozenset({'新颖吸引'}): 0.3081395348837209,
# frozenset({'阅读量超过1K'}): 0.46511627906976744,
# frozenset({'公司防疫相关or政策相关'}): 0.22674418604651161,
# frozenset({'可点赞、投票、直播'}): 0.06395348837209303}
# 执行程序1--分析支持度:
s, all_support = apriori.apriori(data_arr, 0.3)

print('支持度超过阈值的数据')
s

#Out:
#支持度超过阈值的数据
#[[frozenset({'公司or厂'}),
#  frozenset({'公司为信息源'}),
#  frozenset({'文章置顶'}),
#  frozenset({'社团活动or员工活动'}),
#  frozenset({'两周内前后关联'}),
#  frozenset({'新颖吸引'}),
#  frozenset({'阅读量超过1K'})],
# [frozenset({'公司or厂', '公司为信息源'}),
#  frozenset({'公司or厂', '文章置顶'}),
#  frozenset({'公司为信息源', '文章置顶'}),
#  frozenset({'公司为信息源', '社团活动or员工活动'}),
#  frozenset({'公司为信息源', '新颖吸引'}),
#  frozenset({'公司为信息源', '阅读量超过1K'}),
#  frozenset({'文章置顶', '阅读量超过1K'}),
#  frozenset({'公司or厂', '阅读量超过1K'})],
# [frozenset({'公司or厂', '公司为信息源', '文章置顶'}),
#  frozenset({'公司为信息源', '文章置顶', '阅读量超过1K'}),
#  frozenset({'公司or厂', '公司为信息源', '阅读量超过1K'})],
# []]

print('所有的支持度数据')
all_support
#Out[24]:
#所有的支持度数据
#{frozenset({'公司or厂'}): 0.5174418604651163,
# frozenset({'公司为信息源'}): 0.8372093023255814,
# frozenset({'文章置顶'}): 0.5058139534883721,
# frozenset({'社团活动or员工活动'}): 0.5,
# frozenset({'表彰表扬'}): 0.11627906976744186,
# frozenset({'两周内前后关联'}): 0.3313953488372093,
# frozenset({'内容有视频'}): 0.22093023255813954,
# frozenset({'文章封面吸引'}): 0.12790697674418605,
# frozenset({'新颖吸引'}): 0.3081395348837209,
# frozenset({'阅读量超过1K'}): 0.46511627906976744,
# frozenset({'公司防疫相关or政策相关'}): 0.22674418604651161,
# frozenset({'可点赞、投票、直播'}): 0.06395348837209303,
# frozenset({'公司or厂', '公司为信息源'}): 0.4418604651162791,
# frozenset({'公司or厂', '文章置顶'}): 0.3430232558139535,
# frozenset({'公司or厂', '社团活动or员工活动'}): 0.20348837209302326,
# frozenset({'公司为信息源', '文章置顶'}): 0.47093023255813954,
# frozenset({'公司为信息源', '社团活动or员工活动'}): 0.5,
# frozenset({'文章置顶', '社团活动or员工活动'}): 0.29651162790697677,
# frozenset({'两周内前后关联', '公司为信息源'}): 0.2616279069767442,
# frozenset({'公司为信息源', '新颖吸引'}): 0.3023255813953488,
# frozenset({'公司为信息源', '阅读量超过1K'}): 0.4186046511627907,
# frozenset({'两周内前后关联', '文章置顶'}): 0.1569767441860465,
# frozenset({'文章置顶', '新颖吸引'}): 0.2441860465116279,
# frozenset({'文章置顶', '阅读量超过1K'}): 0.3488372093023256,
# frozenset({'两周内前后关联', '社团活动or员工活动'}): 0.19186046511627908,
# frozenset({'新颖吸引', '社团活动or员工活动'}): 0.18023255813953487,
# frozenset({'社团活动or员工活动', '阅读量超过1K'}): 0.20930232558139536,
# frozenset({'两周内前后关联', '新颖吸引'}): 0.13372093023255813,
# frozenset({'两周内前后关联', '阅读量超过1K'}): 0.1569767441860465,
# frozenset({'新颖吸引', '阅读量超过1K'}): 0.27325581395348836,
# frozenset({'公司or厂', '阅读量超过1K'}): 0.3313953488372093,
# frozenset({'公司or厂', '新颖吸引'}): 0.22093023255813954,
# frozenset({'两周内前后关联', '公司or厂'}): 0.16279069767441862,
# frozenset({'公司or厂', '公司为信息源', '文章置顶'}): 0.31976744186046513,
# frozenset({'公司为信息源', '文章置顶', '新颖吸引'}): 0.2441860465116279,
# frozenset({'公司为信息源', '文章置顶', '阅读量超过1K'}): 0.32558139534883723,
# frozenset({'公司or厂', '公司为信息源', '阅读量超过1K'}): 0.3023255813953488,
# frozenset({'公司or厂', '文章置顶', '阅读量超过1K'}): 0.26744186046511625,
# frozenset({'公司or厂', '公司为信息源', '文章置顶', '阅读量超过1K'}): 0.2558139534883721}
# 执行程序2---挖掘关联关系:
L, supportData = apriori.apriori(data_arr)
bigRuleList = apriori.generate_rules(L, supportData, 0.3)

# 导出原始数据
bigRuleList
#Out:
#[(frozenset({'公司为信息源'}), frozenset({'公司or厂'}), 0.5277777777777778),
# (frozenset({'公司or厂'}), frozenset({'公司为信息源'}), 0.8539325842696629),
# (frozenset({'文章置顶'}), frozenset({'公司or厂'}), 0.6781609195402298),
# (frozenset({'公司or厂'}), frozenset({'文章置顶'}), 0.6629213483146067),
# (frozenset({'公司为信息源'}), frozenset({'文章置顶'}), 0.5625),
# (frozenset({'文章置顶'}), frozenset({'公司为信息源'}), 0.9310344827586207),
# (frozenset({'公司为信息源'}), frozenset({'社团活动or员工活动'}), 0.5972222222222222),
# (frozenset({'社团活动or员工活动'}), frozenset({'公司为信息源'}), 1.0),
# (frozenset({'公司为信息源'}), frozenset({'新颖吸引'}), 0.36111111111111105),
# (frozenset({'新颖吸引'}), frozenset({'公司为信息源'}), 0.9811320754716981),
# (frozenset({'公司为信息源'}), frozenset({'阅读量超过1K'}), 0.5),
# (frozenset({'阅读量超过1K'}), frozenset({'公司为信息源'}), 0.9),
# (frozenset({'文章置顶'}), frozenset({'阅读量超过1K'}), 0.6896551724137931),
# (frozenset({'阅读量超过1K'}), frozenset({'文章置顶'}), 0.75),
# (frozenset({'公司or厂'}), frozenset({'阅读量超过1K'}), 0.6404494382022471),
# (frozenset({'阅读量超过1K'}), frozenset({'公司or厂'}), 0.7124999999999999),
# (frozenset({'公司为信息源', '文章置顶'}), frozenset({'公司or厂'}), 0.6790123456790124),
# (frozenset({'公司or厂', '公司为信息源'}), frozenset({'文章置顶'}), 0.7236842105263158),
# (frozenset({'公司or厂', '文章置顶'}), frozenset({'公司为信息源'}), 0.9322033898305085),
# (frozenset({'公司为信息源'}), frozenset({'公司or厂', '文章置顶'}), 0.3819444444444444),
# (frozenset({'文章置顶'}), frozenset({'公司or厂', '公司为信息源'}), 0.632183908045977),
# (frozenset({'公司or厂'}), frozenset({'公司为信息源', '文章置顶'}), 0.6179775280898876),
# (frozenset({'公司为信息源', '文章置顶'}), frozenset({'阅读量超过1K'}), 0.6913580246913581),
# (frozenset({'公司为信息源', '阅读量超过1K'}), frozenset({'文章置顶'}), 0.7777777777777778),
# (frozenset({'文章置顶', '阅读量超过1K'}), frozenset({'公司为信息源'}), 0.9333333333333333),
# (frozenset({'公司为信息源'}), frozenset({'文章置顶', '阅读量超过1K'}), 0.3888888888888889),
# (frozenset({'文章置顶'}), frozenset({'公司为信息源', '阅读量超过1K'}), 0.6436781609195402),
# (frozenset({'阅读量超过1K'}), frozenset({'公司为信息源', '文章置顶'}), 0.7000000000000001),
# (frozenset({'公司or厂', '公司为信息源'}), frozenset({'阅读量超过1K'}), 0.6842105263157894),
# (frozenset({'公司为信息源', '阅读量超过1K'}), frozenset({'公司or厂'}), 0.7222222222222221),
# (frozenset({'公司or厂', '阅读量超过1K'}), frozenset({'公司为信息源'}), 0.912280701754386),
# (frozenset({'公司为信息源'}), frozenset({'公司or厂', '阅读量超过1K'}), 0.36111111111111105),
# (frozenset({'公司or厂'}), frozenset({'公司为信息源', '阅读量超过1K'}), 0.5842696629213483),
# (frozenset({'阅读量超过1K'}), frozenset({'公司or厂', '公司为信息源'}), 0.65)]

# 导出相关数据1
for i in range(len(bigRuleList)):
    print(list(bigRuleList[i][0]),'--->',list(bigRuleList[i][1]),',几率为{:.0%}'.format(bigRuleList[i][2]))

#Out:
#['公司为信息源'] ---> ['公司or厂'] ,几率为53%
#['公司or厂'] ---> ['公司为信息源'] ,几率为85%
#['文章置顶'] ---> ['公司or厂'] ,几率为68%
#['公司or厂'] ---> ['文章置顶'] ,几率为66%
#['文章置顶'] ---> ['公司为信息源'] ,几率为93%
#['公司为信息源'] ---> ['文章置顶'] ,几率为56%
#['公司为信息源'] ---> ['社团活动or员工活动'] ,几率为60%
#['社团活动or员工活动'] ---> ['公司为信息源'] ,几率为100%
#['新颖吸引'] ---> ['公司为信息源'] ,几率为98%
#['公司为信息源'] ---> ['新颖吸引'] ,几率为36%
#['公司为信息源'] ---> ['阅读量超过1K'] ,几率为50%
#['阅读量超过1K'] ---> ['公司为信息源'] ,几率为90%
#['文章置顶'] ---> ['阅读量超过1K'] ,几率为69%
#['阅读量超过1K'] ---> ['文章置顶'] ,几率为75%
#['公司or厂'] ---> ['阅读量超过1K'] ,几率为64%
#['阅读量超过1K'] ---> ['公司or厂'] ,几率为71%
#['公司为信息源', '文章置顶'] ---> ['公司or厂'] ,几率为68%
#['公司or厂', '公司为信息源'] ---> ['文章置顶'] ,几率为72%
#['公司or厂', '文章置顶'] ---> ['公司为信息源'] ,几率为93%
#['公司为信息源'] ---> ['公司or厂', '文章置顶'] ,几率为38%
#['文章置顶'] ---> ['公司or厂', '公司为信息源'] ,几率为63%
#['公司or厂'] ---> ['公司为信息源', '文章置顶'] ,几率为62%
#['公司为信息源', '文章置顶'] ---> ['阅读量超过1K'] ,几率为69%
#['阅读量超过1K', '文章置顶'] ---> ['公司为信息源'] ,几率为93%
#['阅读量超过1K', '公司为信息源'] ---> ['文章置顶'] ,几率为78%
#['文章置顶'] ---> ['阅读量超过1K', '公司为信息源'] ,几率为64%
#['公司为信息源'] ---> ['阅读量超过1K', '文章置顶'] ,几率为39%
#['阅读量超过1K'] ---> ['公司为信息源', '文章置顶'] ,几率为70%
#['公司为信息源', '公司or厂'] ---> ['阅读量超过1K'] ,几率为68%
#['阅读量超过1K', '公司or厂'] ---> ['公司为信息源'] ,几率为91%
#['阅读量超过1K', '公司为信息源'] ---> ['公司or厂'] ,几率为72%
#['公司or厂'] ---> ['阅读量超过1K', '公司为信息源'] ,几率为58%
#['公司为信息源'] ---> ['阅读量超过1K', '公司or厂'] ,几率为36%
#['阅读量超过1K'] ---> ['公司为信息源', '公司or厂'] ,几率为65%

# 导出相关数据2
for i in range(len(bigRuleList)):
    if list(bigRuleList[i][1]) == ['阅读量超过1K']:
        print(list(bigRuleList[i][0]),'--->',list(bigRuleList[i][1]),',几率为{:.0%}'.format(bigRuleList[i][2]))
#Out:
#['公司为信息源'] ---> ['阅读量超过1K'] ,几率为50%
#['文章置顶'] ---> ['阅读量超过1K'] ,几率为69%
#['公司or厂'] ---> ['阅读量超过1K'] ,几率为64%
#['公司为信息源', '文章置顶'] ---> ['阅读量超过1K'] ,几率为69%
#['公司为信息源', '公司or厂'] ---> ['阅读量超过1K'] ,几率为68%

apriori.py

from numpy import *

# 加载数据集
def load_data_arr():
    return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]


# 初始化候选项集,创建元素个数为1的候选项集
def create_set_0(data_arr):
    # 数组
    set_0 = []
    # 对每一条交易记录
    for transaction in data_arr:
        # 对交易记录中的每件物品
        for item in transaction:
            # 如果该物品没有出现在候选项集中,则添加
            if not [item] in set_0:
                set_0.append([item])
    set_0.sort()
    # 返回一个冻结的集合,集合冻结后不能再添加或者删除元素
    return map(frozenset, set_0)


# 扫描交易记录集,计算每个候选项集的支持度,返回满足条件的频繁项集以及所有候选项集的支持度
def scan_data_set(data_set_list, set_k, min_support):
    set_k_list = list(set_k)
    # 候选项集计数
    items_cnt = {}
    for transaction in data_set_list:
        for items in set_k_list:
            if items.issubset(transaction):
                if items not in items_cnt:
                    items_cnt[items] = 1
                else:
                    items_cnt[items] += 1
    num_transaction = len(data_set_list)
    # 数组
    return_set_k = []
    # 字典
    support_data = {}
    for items in items_cnt.keys():
        # 计算每个候选项集的支持度
        support = items_cnt[items]/num_transaction
        # 判断项集的支持度是否满足最小支持度
        if support >= min_support:
            return_set_k.append(items)
        # 保存每个候选项集的支持度
        support_data[items] = support
    return return_set_k, support_data


# 根据项个数为k+1的频繁项集set_k,生成项个数为k+2的候选项集set_k_plus
def apriori_gen(set_k, k):
    return_set_k_plus = []
    num_set_k = len(set_k)
    for i in range(num_set_k):
        for j in range(i+1, num_set_k):
            l1 = list(set_k[i])[:k]
            l2 = list(set_k[j])[:k]
            l1.sort()
            l2.sort()
            if l1 == l2:
                return_set_k_plus.append(set_k[i] | set_k[j])    #set union
    return return_set_k_plus


def apriori(data_arr, min_support=0.3):
    # 创建项个数为1的候选项集
    set_0 = create_set_0(data_arr)
    data_set_list = list(map(set, data_arr))
    # 计算项个数为1的频繁项集
    set_0_scanned, all_support = scan_data_set(data_set_list, set_0, min_support)
    # 将项个数为1的频繁项集放入到总的频繁项集中,下标为0
    s = [set_0_scanned]
    k = 0
    while len(s[k]) > 0:
        # 根据项个数为k+1的频繁项集set_k,生成项个数为k+2的候选项集set_k_plus
        set_k_plus = apriori_gen(s[k], k)
        # 计算项个数为k+2的频繁项集set_k_plus_scanned
        set_k_plus_scanned, k_plus_support = scan_data_set(data_set_list, set_k_plus, min_support)
        # 更新
        all_support.update(k_plus_support)
        s.append(set_k_plus_scanned)
        k += 1
    return s, all_support


# 计算规则的可信度
def calculate_conf(freq_item, H, support_data, big_rules_list, min_conf=0.3):
    pruned_H = []
    for consequence in H:
        # 通过支持度计算可信度
        # 规则的左侧通过作差求得
        conf = support_data[freq_item]/support_data[freq_item - consequence]
        if conf >= min_conf:
            big_rules_list.append((freq_item - consequence, consequence, conf))
            # 需要返回可信的规则的右侧,以便再次进行合并,同时抛弃不可信规则的右侧
            pruned_H.append(consequence)
    return pruned_H


# 从序列中提取规则
# H是规则的右侧
def rules_from_consequence(freq_item, H, support_data, big_rules_list, min_conf=0.3):
    m = len(H[0])
    # 原书代码中此处没有等号,是不对的,读者可以结合前面给出的结束条件,判断此处是否需要添加等号
    if len(freq_item) >= (m+1):
        # 下面的两行代码,原书给出的顺序是错误的,应该先计算可信度,再合并
        # 读者可以根据计算出的频繁项集和支持度手动计算一下,可以发现原执行顺序会漏掉一部分规则
        hmp1 = calculate_conf(freq_item, H, support_data, big_rules_list, min_conf)
        hmp1 = apriori_gen(hmp1, m - 1)
        # 下面这行代码使没有用的,因为合并右侧后,肯定是需要去提取规则并计算规则可信度的。
        # if len(hmp1) > 1:
        rules_from_consequence(freq_item, hmp1, support_data, big_rules_list, min_conf)


# 生成关联规则
def generate_rules(s, support_data, min_conf=0.3):
    big_rules_list = []
    for i in range(1, len(s)):
        for freq_set in s[i]:
            h1 = [frozenset([item]) for item in freq_set]
            if i > 1:
                # 项数大于2,至少为3,可以组合项,提取规则
                rules_from_consequence(freq_set, h1, support_data, big_rules_list, min_conf)
            else:
                calculate_conf(freq_set, h1, support_data, big_rules_list, min_conf)
    return big_rules_list
            

部分代码源自于https://blog.csdn.net/dzjin1234/article/details/105799974

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值