我们的第84篇原创
作者:才哥
☆
大家好,我是才哥。
今天我们简单介绍一个关于亲和性分析的案例,作为后续关联规则分析的启蒙。
以下案例来自《Python数据挖掘入门与实践(第二版)
》第一章1.3亲和性分析的简单示例。
我们先通过本案例了解下关于亲和性的一些概念和工作流程,然后再讨论一些相对更优化的处理方案。
注:该书明确说明为了便于理解,有时更加关注代码和工作流程是否清晰易懂,而不是所采用的方法效率是否最优。
1. 什么是亲和性分析
亲和性分析是一种用于计算样本相似度的数据挖掘方法,这个相似度可以出现在以下几种场景:
- 网站的用户,拓展服务项目或者定向投放广告;
- 销售的商品,推荐电影或其他商品(猜你喜欢)。
关于亲和性分析,大家估计都会看到以下这个经典的例子:
在美国的零售业有着这样一个传奇故事,沃尔玛百货将他们的纸尿裤和啤酒并排摆在一起销售,结果纸尿裤和啤酒的销量双双增长!
在今天的案例中,为了简化代码方便理解,我们仅考虑同时购买2件商品的情况,比如以下简单的规则:
用户如果购买了商品X,那么也倾向于购买商品Y
这里我们给出2个用来评价规则的数据指标概念:支持度
和置信度
。
支持度
是规则在数据集中出现的次数,即匹配规则的样本数,比如同时购买商品X和Y的交易数;
置信度
是衡量匹配规则的准确度的,比如在购买商品X的交易中同时购买商品Y的比例。
2. 案例详解
本节为书中案例介绍,其使用的工具库如下:
numpy
collections
2.1. 加载数据集
数据集后台回复 955
领取,有兴趣的同学也可以使用numpy
自己构建随机数据组。
import numpy as np
dataset_filename = "affinity_dataset.txt"
X = np.loadtxt(dataset_filename)
n_samples, n_features = X.shape
print(f"这份数据集 有 {n_samples} 行 和 {n_features} 列")
print(X[:5])
代码语言:javascript复制这份数据集 有 100 行 和 5 列
[[0. 1. 0. 0. 0.]
[1. 1. 0. 0. 0.]
[0. 0. 1. 0. 1.]
[1. 1. 0. 0. 0.]
[0. 0. 1. 1. 1.]]
这份数据集比较小,一共100行5列数据。这里我们将每行数据看做是一次交易行为,每列代表一种商品,数字1代表有购买,0代表没有购买。
对于这5列,分别代表 面包、牛奶、奶酪、苹果和香蕉。比如第一行[0. 1. 0. 0. 0.]显示首次交易中的商品,消费者只购买了牛奶,而没有购买其它商品。
代码语言:javascript复制features = ["面包", "牛奶", "奶酪", "苹果", "香蕉"]
接下来,我们开始研究支持度和置信度的计算。
2.2. 求苹果->香蕉的亲和性
根据概念,置信度需要知道支持度中某商品交易数,这里我们拿香蕉举例,看看其交易数。
计算规则:遍历苹果列数据,值为1则计数 1
代码语言:javascript复制num_apple_purchases = 0
for sample in X:
if sample[3] == 1: # 第4列
num_apple_purchases = 1
print(f"含苹果的交易数为:{num_apple_purchases}")
代码语言:javascript复制含苹果的交易数为:43
接着,我们计算苹果-香蕉的支持度。
计算规则:如果苹果列为1且香蕉列为1,则计数 1
代码语言:javascript复制rule_valid = 0
for sample in X:
if sample[3] == 1: # 购买了苹果
if sample[4] == 1:
# 同时也购买了香蕉
rule_valid = 1
else:
continue
print(f"同时购买苹果和香蕉的交易数为:{rule_valid}")
代码语言:javascript复制同时购买苹果和香蕉的交易数为:27
以上两个数值都计算出来后,我们可以很方便的获取苹果—>香蕉
的置信度。
计算规则:用苹果-香蕉的支持度/含苹果的交易数
代码语言:javascript复制support = rule_valid # 支持度
confidence = rule_valid / num_apple_purchases # 置信度
print(f"苹果-香蕉的支持度为 {support}n苹果—>香蕉的置信度为 {confidence:.3f}")
# Confidence can be thought of as a percentage using the following:
print(f"苹果—>香蕉的置信度百分比为 {confidence*100:.1f}%.")
代码语言:javascript复制苹果-香蕉的支持度为 27
苹果—>香蕉的置信度为 0.628
苹果—>香蕉的置信度百分比为 62.8%
至此,我们便计算出了苹果-香蕉的支持度为27,也就是同时购买苹果和香蕉的交易数为27;而购买苹果的用户中也购买了香蕉的比例为62.8%,这就是置信度。
接着,我们就可以计算全部组合之间的支持度与置信度数据,然后进行对比分析,接着安排相关策略了。
2.3. 亲和性分析
现在我们需要从数据集中计算所有规则(注意:这里的规则我们还是以2个商品为例,不拓展更多组合)。因此需要创建1个字典用于存储匹配的规则,字典的key是X—>Y,值则是支持度;另外一个字典用于存储对应的X—>Y中X出现的次数。
代码语言:javascript复制from collections import defaultdict
# 初始化2个字典
valid_rules = defaultdict(int)
num_occurences = defaultdict(int)
# 计算支持度及X->Y中X出现次数
for sample in X:
for premise in range(n_features):
if sample[premise] == 0:
continue
# 记录X—>Y中X出现的次数
num_occurences[premise] = 1
for conclusion in range(n_features):
if premise == conclusion: # X—>X是无意义的,跳过
continue
if sample[conclusion] == 1:
# X和Y同时出现,则匹配规则的次数 1
valid_rules[(premise, conclusion)] = 1
else:
continue
support = valid_rules
confidence = defaultdict(float)
# 计算置信度
for premise, conclusion in valid_rules.keys():
confidence[(premise, conclusion)] = valid_rules[(premise, conclusion)] / num_occurences[premise]
#输出结果
for premise, conclusion in confidence:
premise_name = features[premise]
conclusion_name = features[conclusion]
print(f"规则: {premise_name}—>{conclusion_name}")
print(f" - 置信度: {confidence[(premise, conclusion)]*100:.2f}%")
print(f" - 支持度: {support[(premise, conclusion)]}")
print('-'*20)
输出结果如下:
代码语言:javascript复制规则: 面包—>牛奶
- 置信度: 46.43%
- 支持度: 13
--------------------
规则: 牛奶—>面包
- 置信度: 25.00%
- 支持度: 13
--------------------
规则: 奶酪—>香蕉
- 置信度: 51.28%
- 支持度: 20
--------------------
规则: 香蕉—>奶酪
- 置信度: 35.09%
- 支持度: 20
--------------------
规则: 奶酪—>苹果
- 置信度: 56.41%
- 支持度: 22
--------------------
规则: 苹果—>奶酪
- 置信度: 51.16%
- 支持度: 22
--------------------
规则: 苹果—>香蕉
- 置信度: 62.79%
- 支持度: 27
--------------------
规则: 香蕉—>苹果
- 置信度: 47.37%
- 支持度: 27
--------------------
规则: 牛奶—>苹果
- 置信度: 34.62%
- 支持度: 18
--------------------
规则: 苹果—>牛奶
- 置信度: 41.86%
- 支持度: 18
--------------------
规则: 牛奶—>香蕉
- 置信度: 51.92%
- 支持度: 27
--------------------
规则: 香蕉—>牛奶
- 置信度: 47.37%
- 支持度: 27
--------------------
规则: 面包—>奶酪
- 置信度: 17.86%
- 支持度: 5
--------------------
规则: 奶酪—>面包
- 置信度: 12.82%
- 支持度: 5
--------------------
规则: 面包—>香蕉
- 置信度: 57.14%
- 支持度: 16
--------------------
规则: 香蕉—>面包
- 置信度: 28.07%
- 支持度: 16
--------------------
规则: 牛奶—>奶酪
- 置信度: 21.15%
- 支持度: 11
--------------------
规则: 奶酪—>牛奶
- 置信度: 28.21%
- 支持度: 11
--------------------
规则: 面包—>苹果
- 置信度: 32.14%
- 支持度: 9
--------------------
规则: 苹果—>面包
- 置信度: 20.93%
- 支持度: 9
--------------------
我们可以输出置信度前5的规则如下:(大家也可以试着输出支持度前5的规则)
代码语言:javascript复制def print_rule(premise, conclusion, support, confidence, features):
premise_name = features[premise]
conclusion_name = features[conclusion]
print(f"规则: {premise_name}—>{conclusion_name}")
print(f" - 置信度: {confidence[(premise, conclusion)]*100:.2f}%")
print(f" - 支持度: {support[(premise, conclusion)]}")
print('-'*20)
from operator import itemgetter
sorted_support = sorted(support.items(), key=itemgetter(1), reverse=True)
sorted_confidence = sorted(confidence.items(), key=itemgetter(1), reverse=True)
for index in range(5):
print("Rule #{0}".format(index 1))
(premise, conclusion) = sorted_confidence[index][0]
print_rule(premise, conclusion, support, confidence, features)
输出结果如下:
代码语言:javascript复制Rule #1
规则: 苹果—>香蕉
- 置信度: 62.79%
- 支持度: 27
--------------------
Rule #2
规则: 面包—>香蕉
- 置信度: 57.14%
- 支持度: 16
--------------------
Rule #3
规则: 奶酪—>苹果
- 置信度: 56.41%
- 支持度: 22
--------------------
Rule #4
规则: 牛奶—>香蕉
- 置信度: 51.92%
- 支持度: 27
--------------------
Rule #5
规则: 奶酪—>香蕉
- 置信度: 51.28%
- 支持度: 20
--------------------
当我们得出以上数据后,就可以进行下一步的销售策略调整了,简单的比如 购买苹果可以获得购买香蕉折扣之类的。具体这里不深入讨论,我们放在后续 关联规则分析中做深入介绍。
3. 算法优化
关于亲和性分析,是有一些数据挖掘算法如Apriori
算法来处理的,这里也不展开。那么,这里的算法优化其实是指对案例中非常直接的计算方式进行优化,这里用到的是pandas
工具以及我们之前介绍过的itertools
《itertools拼装迭代器与生成器》。
主要是计算支持度的逻辑优化,实现的方式有很多种,大家具体查看代码注释吧。
代码语言:javascript复制import pandas as pd
# 将数据集转化为Dataframe类型
df = pd.DataFrame(X, columns=features)
# 先引入该内置标准库
import itertools
# 求组合(顺序不同组合不同)
it = itertools.permutations(features,2)
rules = list(it)
for rule in rules:
num_occurence = df[rule[0]].sum() # X—>Y中X在整个数据集中出现次数
num_rule = df.query(f"{rule[0]} {rule[1]}==2").shape[0] # 同时购买X和Y的交易次数(支持度),这里用两数相加=2来验证
# df.query(f"{rule[0]}*{rule[1]}==1").shape[0] # 用两数相乘=1 验证
# df[(df[rule[0]]==1) & (df[rule[1]]==1)].shape[0] # 直接用对应值都是1来验证
# df[df[rule[0]]==1][rule[1]].sum() # 用X—>Y中,X购买情况下Y列求和(毕竟购买为1,不购买为0)
# df[list(rule)].all(axis = 'columns').sum() # 由于数据为0和1,适用于all()方法进行bool判断,然后sum求和
confidence = num_rule / num_occurence # 置信度
print(f'规则:{rule[0]}—>{rule[1]}n- 置信度:{confidence*100:.2f}%n- 支持度:{num_rule}n')
输出结果如下:(我们只展示部分)
代码语言:javascript复制规则:面包—>牛奶
- 置信度:46.43%
- 支持度:13
规则:面包—>奶酪
- 置信度:17.86%
- 支持度:5
规则:面包—>苹果
- 置信度:32.14%
- 支持度:9
规则:面包—>香蕉
- 置信度:57.14%
- 支持度:16
规则:牛奶—>面包
- 置信度:25.00%
- 支持度:13
为了更方便做后续的操作,我们可以将以上数据转化为DataFrame
类型,操作如下:
columns=['规则','置信度','支持度']
data = pd.DataFrame(columns=columns)
for rule in rules:
num_occurence = df[rule[0]].sum() # X—>Y中X在整个数据集中出现次数
num_rule = df[df[rule[0]]==1][rule[1]].sum() # 用X—>Y中,X购买情况下Y列求和(毕竟购买为1,不购买为0)
confidence = num_rule / num_occurence # 置信度
data = data.append(pd.DataFrame([[f'{rule[0]}—>{rule[1]}',confidence,num_rule]],columns=columns),ignore_index=True)
data.nlargest(n=5, columns= '置信度', keep='first')
置信度前5
以上就是本文关于亲和性分析的基础介绍,案例来源《Python数据挖掘入门与实践(第二版)
》第一章1.3亲和性分析的简单示例,并没有做太多的展开介绍。
我们后续将会拿实际生活中的具体场景再一次进行更详细的介绍,敬请期待哈。
如果你喜欢本篇介绍,还请点赞、在看给个支持哈!(在看超过10个,咱们分享案例数据集和ipynb笔记)