完整代码在最下面
什么是亲和性分析?
亲和性分析(affinity analysis)是一种用于计算样本(对象)相似度的数据挖掘方法。
说人话就是:寻找样本中内含的关系。
举个例子,它可用于推荐商品。
如果当用户购买了A,那么也倾向于购买B
那么我们就可以把A和B放在一起,以此增加销量。
开始:分析两件商品被同时购买的关系。
- 使用NumPy加载数据集
数据集,用我所学的《Python数据挖掘入门与实战(第2版)》一书中提供的数据集。
以下是资源网址。
数据集文件↓
数据集预览↓
可以看到,这是一个二维数组,
每行代表一次交易,
每列代表每种商品,0和1代表是否被购买。(0代表否,1代表是,这里不考虑购买数量)
在该样本中,我们称商品为特征值
我们可以假设
第一列是bread
第二列是milk
第三列是cheese
第四列是apples
第五列是bananas
这些bread什么的,都是特征值,它们代表样本的五个特征
它们对应的列的索引值分别是0、1、2、3、4
因此,我们可以让索引值充当商品的编号。
小知识:数组的维度
举例子,假如有一个数组array,我们要获取其中的某个元素。
如果要写array[0],那就是一维数组;
如果要写array[0][0],那就是二维数组。
代码
import numpy as np
data = "affinity_dataset.txt"
x = np.loadtxt(data)
# np.loadtxt方法可以返回一个np的数组对象
n_samples, n_features = x.shape
# shape属性会返回包含两个元素的元组
# 两元素是:样本数(行数),特征值的数量(列数)
# 把五种特征值转换成对应单词
features = ["bread", "milk", "cheese", "apples", "bananas"]
接下来涉及到的概念
如果你已经知晓这些概念,请直接跳到第二点 。
规则
本次项目中,
规则:顾客如果购买了商品A,那么也倾向于购买商品B。
前提↑ 结论↑
规则可拆分为前提和结论
前提:购买了商品A
结论:倾向于购买商品B
那么,商品A是什么,商品B又是什么?
要找出这样的规则
评价规则的两种方法
比较两个东西:支持度(support),置信度(confidence)。
支持度:某个项集出现的频率
置信度:规则的可信程度
计算规则支持度的方法:{匹配规则的情况次数} / {样本总数}
计算规则的置信度的方法:支持度{前提,结论}/支持度{前提})
因为计算支持度要除以样本总数,
所以,我们可以简化为
某规则的置信度 = {匹配该规则的次数} / {满足这个规则的前提的次数}
目标
计算各个规则的支持度和置信度。
理清每一对商品之间的关系。
2.计算支持度和置信度
首先,我们要导入collections库的defaultdict方法,定义两个字典变量。
(至于为什么要用defaultdict来定义字典,是为了更好处理找不到对应的键的情况。
collections是个标准库,非常好用,具体用法不赘述)
定义变量
from collections import defaultdict
valid_rules = defaultdict(int)
# 记录匹配规则的样本数
num_occurences = defaultdict(int)
# 记录所有特征值(商品)的被购买次数
遍历数据集,开始统计
for sample in x: # 遍历数据集
for premise in range(n_features):
if sample[premise] == 0:
continue
# 如果不满足前提,则直接跳过,
num_occurences[premise] += 1
# 满足,则记录下来,对应商品被购买的次数+1
for conclusion in range(n_features):
if premise == conclusion:
continue
# 前提购买的商品和结果购买的商品一样的话,统计没有意义
if sample[conclusion] == 1:
valid_rules[(premise, conclusion)] += 1
# 如果结果也满足,匹配该规则的数量+1
else:
invalid_rules[(premise,conclusion)] += 1
# 如果只满足前提,不满足结果,则不匹配该规则次数+1
最终得到的valid_rules包含了所有规则和对应成功匹配次数的键值对。
计算支持度
根据前文公式
某规则的支持度 = {匹配该规则的情况次数} / {样本总数}
可以直接从valid_rules中取出{成功匹配规则的次数},除以 总样本数
support = defaultdict(float)
# 关联规则与对应支持度
for premise_conclusion in valid_rules.keys():
support[premise_conclusion] = valid_rules[premise_conclusion] / n_samples
计算置信度
根据前文的简化公式:
某规则的置信度 = {匹配该规则的次数} / {满足这个规则的前提的次数}
我们可以直接将从valid_rules中取出的{成功匹配规则的次数},除以 从num_occurences中取出的{满足前提次数},得到对应的置信度。
confidence = defaultdict(float)
# 关联规则与对应置信度
for premise, conclusion in valid_rules.keys():
rule = (premise, conclusion)
confidence[rule] = valid_rules[rule] / num_occurences[premise]
# 计算置信度,让 满足前提和结果的数量 除以 只满足前提的数量
定义一个可以输出对应规则的支持度和置信度的函数。
我们可以传入开头说过的商品编号来查看其支持度和置信度。
代码:输出特定结果
def print_rule(premise: int, conclusion: int, support, confidence, features):
premise_name = features[premise]
conclusion_name = features[conclusion]
# 根据所给的数据集中的商品编号,取出对应名称。
print("Rule: If a person buys {0} they will also buy {1}".format(premise_name, conclusion_name))
print("Confidence:{0:.3f}".format(
confidence[(premise, conclusion)]
)
)
print("Support:{0}".format(
support[(premise, conclusion)]
)
)
print("")
代码:输出所有结果
from operator import itemgetter
# 这个库用来选取items函数形成的对象中的元素
for index in range(len(sorted_confidence)):
this_confidence = sorted_confidence[index]
features1 = features[this_confidence[0][0]]
features2 = features[this_confidence[0][1]]
features1_index = features.index(features1)
features2_index = features.index(features2)
this_support = support[features1_index, features2_index]
print("premise:{0:^10} | conclusion:{1:^10} | Confidence is {2:^10.3f} | Support is {3:^10}".format(features1, features2, this_confidence[1], this_support))
测试!
我们来查看以编号1为前提和以编号3为结论的商品
print_rule(1, 3, support, confidence, features)
效果展示
输出特定结果:
输出所有结果:
看起来不错!当然你也可以修改得更好。
完整代码
import numpy as np
from collections import defaultdict
from operator import itemgetter
data = "affinity_dataset.txt"
x = np.loadtxt(data)
features = ["bread", "milk", "cheese", "apples", "bananas"]
n_samples, n_features = x.shape
valid_rules = defaultdict(int)
invalid_rules = defaultdict(int)
num_occurences = defaultdict(int)
for sample in x:
for premise in range(n_features):
if sample[premise] == 0:
continue
num_occurences[premise] += 1
for conclusion in range(n_features):
if premise == conclusion:
continue
if sample[conclusion] == 1:
valid_rules[(premise, conclusion)] += 1
else:
invalid_rules[(premise,conclusion)] += 1
confidence = defaultdict(float)
for premise, conclusion in valid_rules.keys():
rule = (premise, conclusion)
confidence[rule] = valid_rules[rule] / num_occurences[premise]
support = defaultdict(float)
for premise_conclusion in valid_rules.keys():
support[premise_conclusion] = valid_rules[premise_conclusion] / n_samples
def print_rule(premise: int, conclusion: int, support, confidence, features):
premise_name = features[premise]
conclusion_name = features[conclusion]
print("Rule: If a person buys {0} they will also buy {1}".format(premise_name, conclusion_name))
print("Confidence:{0:.3f}".format(
confidence[(premise, conclusion)]
)
)
print("Support:{0}".format(
support[(premise, conclusion)]
)
)
print("")
print_rule(1, 3, support, confidence, features)
sorted_confidence = sorted(confidence.items(), key=itemgetter(1), reverse=True)
for index in range(len(sorted_confidence)):
this_confidence = sorted_confidence[index]
features1 = features[this_confidence[0][0]]
features2 = features[this_confidence[0][1]]
features1_index = features.index(features1)
features2_index = features.index(features2)
this_support = support[features1_index, features2_index]
print("premise:{0:^10} | conclusion:{1:^10} | Confidence is {2:^10.3f} | Support is {3:^10}".format(features1, features2, this_confidence[1], this_support))