association_rules: 从频繁项集生成关联规则
从频繁项集生成关联规则的函数
from mlxtend.frequent_patterns import association_rules
概述
规则生成是频繁模式挖掘中的常见任务。关联规则是形如 的蕴涵表达式,其中 和 是不相交的项集 [1]。一个更具体的基于消费者行为的例子是表明购买尿布的人也很可能购买啤酒。为了评估这种关联规则的“兴趣度”,已经开发了不同的度量标准。当前的实现使用了 confidence
(置信度)和 lift
(提升度)度量。
度量标准
下面列出了当前支持的用于评估关联规则和设置选择阈值的度量标准。给定规则 "A -> C",A 代表前项,C 代表后项。
'支持度'
- 引入于 [3]
支持度度量标准是为项集定义的,而不是关联规则。关联规则挖掘算法生成的表包含三种不同的支持度度量标准:“antecedent support”(前项支持度)、“consequent support”(后项支持度)和“support”(支持度)。在这里,“antecedent support”计算包含前项 A 的事务比例,“consequent support”计算包含后项 C 项集的支持度。“support”度量标准则计算组合项集 AC 的支持度。
通常,支持度用于衡量项集在数据库中的丰度或频率(通常解释为意义或重要性)。如果项集的支持度大于指定的最小支持度阈值,我们将其称为“频繁项集”。请注意,一般来说,由于向下闭合属性,频繁项集的所有子集也是频繁的。
'置信度'
- 引入于 [3]
规则 A->C 的置信度是在给定事务包含前项 A 的情况下,事务也包含后项 C 的概率。请注意,此度量标准不是对称或有方向的;例如,A->C 的置信度与 C->A 的置信度不同。如果后项和前项总是同时出现,则规则 A->C 的置信度为 1(最大值)。
'提升度'
- 引入于 [4]
提升度度量标准通常用于衡量规则 A->C 的前项和后项一起出现的频率,与如果它们统计独立时我们所期望的频率相比高多少。如果 A 和 C 是独立的,则提升度分数恰好为 1。
'杠杆率'
- 引入于 [5]
杠杆率计算 A 和 C 一起出现的观测频率与如果 A 和 C 独立时所期望频率之间的差值。杠杆率为 0 表示独立性。
'确信度'
- 引入于 [6]
高确信度值意味着后项高度依赖于前项。例如,在完美置信度分数的情况下,分母变为 0(因为 1 - 1),此时确信度分数为 'inf'。与提升度类似,如果项是独立的,则确信度为 1。
'Zhang's 度量'
- 引入于 [7]
衡量关联和分离。取值范围在 -1 到 1 之间。正值(>0)表示关联,负值表示分离。
参考文献
[1] Tan, Steinbach, Kumar. Introduction to Data Mining. Pearson New International Edition. Harlow: Pearson Education Ltd., 2014. (pp. 327-414)。
[2] Michael Hahsler, https://michael.hahsler.net/research/association_rules/measures.html
[3] R. Agrawal, T. Imielinski, and A. Swami. Mining associations between sets of items in large databases. In Proc. of the ACM SIGMOD Int'l Conference on Management of Data, pages 207-216, Washington D.C., May 1993
[4] S. Brin, R. Motwani, J. D. Ullman, and S. Tsur. Dynamic itemset counting and implication rules for market basket data
[5] Piatetsky-Shapiro, G., Discovery, analysis, and presentation of strong rules. Knowledge Discovery in Databases, 1991: p. 229-248。
[6] Sergey Brin, Rajeev Motwani, Jeffrey D. Ullman, and Shalom Turk. Dynamic itemset counting and implication rules for market basket data. In SIGMOD 1997, Proceedings ACM SIGMOD International Conference on Management of Data, pages 255-264, Tucson, Arizona, USA, May 1997
[7] Xiaowei Yan , Chengqi Zhang & Shichao Zhang (2009) CONFIDENCE METRICS FOR ASSOCIATION RULE MINING, Applied Artificial Intelligence, 23:8, 713-737 https://www.tandfonline.com/doi/pdf/10.1080/08839510903208062。
示例 1 -- 从频繁项集生成关联规则
generate_rules
函数接受由 mlxtend.association 中的 apriori
、fpgrowth
或 fpmax
函数生成的频繁项集的 dataframes。为了演示 generate_rules
方法的使用,我们首先创建一个由 fpgrowth
函数生成的频繁项集 pandas DataFrame
import pandas as pd
from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import apriori, fpmax, fpgrowth
dataset = [['Milk', 'Onion', 'Nutmeg', 'Kidney Beans', 'Eggs', 'Yogurt'],
['Dill', 'Onion', 'Nutmeg', 'Kidney Beans', 'Eggs', 'Yogurt'],
['Milk', 'Apple', 'Kidney Beans', 'Eggs'],
['Milk', 'Unicorn', 'Corn', 'Kidney Beans', 'Yogurt'],
['Corn', 'Onion', 'Onion', 'Kidney Beans', 'Ice cream', 'Eggs']]
te = TransactionEncoder()
te_ary = te.fit(dataset).transform(dataset)
df = pd.DataFrame(te_ary, columns=te.columns_)
frequent_itemsets = fpgrowth(df, min_support=0.6, use_colnames=True)
### alternatively:
#frequent_itemsets = apriori(df, min_support=0.6, use_colnames=True)
#frequent_itemsets = fpmax(df, min_support=0.6, use_colnames=True)
frequent_itemsets
支持度 | 项集 | |
---|---|---|
0 | 1.0 | (Kidney Beans) |
1 | 0.8 | (Eggs) |
2 | 0.6 | (Yogurt) |
3 | 0.6 | (Onion) |
4 | 0.6 | (Milk) |
5 | 0.8 | (Kidney Beans, Eggs) |
6 | 0.6 | (Kidney Beans, Yogurt) |
7 | 0.6 | (Eggs, Onion) |
8 | 0.6 | (Kidney Beans, Onion) |
9 | 0.6 | (Eggs, Kidney Beans, Onion) |
10 | 0.6 | (Kidney Beans, Milk) |
generate_rules()
函数允许您 (1) 指定您感兴趣的度量标准和 (2) 相应的阈值。当前实现的度量标准是置信度和提升度。假设您只对置信度水平高于 70% 阈值(min_threshold=0.7
)的频繁项集派生规则感兴趣
from mlxtend.frequent_patterns import association_rules
association_rules(frequent_itemsets, metric="confidence", min_threshold=0.7)
前项 | 后项 | 前项支持度 | 后项支持度 | 支持度 | 置信度 | 提升度 | 杠杆率 | 确信度 | Zhang's 度量 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | (Kidney Beans) | (Eggs) | 1.0 | 0.8 | 0.8 | 0.80 | 1.00 | 0.00 | 1.0 | 0.0 |
1 | (Eggs) | (Kidney Beans) | 0.8 | 1.0 | 0.8 | 1.00 | 1.00 | 0.00 | 无穷大 | 0.0 |
2 | (Yogurt) | (Kidney Beans) | 0.6 | 1.0 | 0.6 | 1.00 | 1.00 | 0.00 | 无穷大 | 0.0 |
3 | (Eggs) | (Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 |
4 | (Onion) | (Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 |
5 | (Onion) | (Kidney Beans) | 0.6 | 1.0 | 0.6 | 1.00 | 1.00 | 0.00 | 无穷大 | 0.0 |
6 | (Kidney Beans, Eggs) | (Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 |
7 | (Onion, Eggs) | (Kidney Beans) | 0.6 | 1.0 | 0.6 | 1.00 | 1.00 | 0.00 | 无穷大 | 0.0 |
8 | (Kidney Beans, Onion) | (Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 |
9 | (Eggs) | (Kidney Beans, Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 |
10 | (Onion) | (Kidney Beans, Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 |
11 | (Milk) | (Kidney Beans) | 0.6 | 1.0 | 0.6 | 1.00 | 1.00 | 0.00 | 无穷大 | 0.0 |
示例 2 -- 规则生成和选择标准
如果您对基于不同感兴趣度量标准的规则感兴趣,只需调整 metric
和 min_threshold
参数即可。例如,如果您只对提升度分数 >= 1.2 的规则感兴趣,您可以这样做
rules = association_rules(frequent_itemsets, metric="lift", min_threshold=1.2)
rules
前项 | 后项 | 前项支持度 | 后项支持度 | 支持度 | 置信度 | 提升度 | 杠杆率 | 确信度 | Zhang's 度量 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | (Eggs) | (Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 |
1 | (Onion) | (Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 |
2 | (Kidney Beans, Eggs) | (Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 |
3 | (Kidney Beans, Onion) | (Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 |
4 | (Eggs) | (Kidney Beans, Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 |
5 | (Onion) | (Kidney Beans, Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 |
Pandas DataFrame
使进一步筛选结果变得容易。假设我们只对满足以下标准的规则感兴趣
- 至少 2 个前项
- 置信度 > 0.75
- 提升度分数 > 1.2
我们可以按如下方式计算前项长度
rules["antecedent_len"] = rules["antecedents"].apply(lambda x: len(x))
rules
前项 | 后项 | 前项支持度 | 后项支持度 | 支持度 | 置信度 | 提升度 | 杠杆率 | 确信度 | Zhang's 度量 | 前项长度 | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | (Eggs) | (Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 | 1 |
1 | (Onion) | (Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 | 1 |
2 | (Kidney Beans, Eggs) | (Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 | 2 |
3 | (Kidney Beans, Onion) | (Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 | 2 |
4 | (Eggs) | (Kidney Beans, Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 | 1 |
5 | (Onion) | (Kidney Beans, Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 | 1 |
然后,我们可以使用如下所示的 pandas 选择语法
rules[ (rules['antecedent_len'] >= 2) &
(rules['confidence'] > 0.75) &
(rules['lift'] > 1.2) ]
前项 | 后项 | 前项支持度 | 后项支持度 | 支持度 | 置信度 | 提升度 | 杠杆率 | 确信度 | Zhang's 度量 | 前项长度 | |
---|---|---|---|---|---|---|---|---|---|---|---|
3 | (Kidney Beans, Onion) | (Eggs) | 0.6 | 0.8 | 0.6 | 1.0 | 1.25 | 0.12 | 无穷大 | 0.5 | 2 |
类似地,使用 Pandas API,我们可以根据“antecedents”(前项)或“consequents”(后项)列选择条目
rules[rules['antecedents'] == {'Eggs', 'Kidney Beans'}]
前项 | 后项 | 前项支持度 | 后项支持度 | 支持度 | 置信度 | 提升度 | 杠杆率 | 确信度 | Zhang's 度量 | 前项长度 | |
---|---|---|---|---|---|---|---|---|---|---|---|
2 | (Kidney Beans, Eggs) | (Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 | 2 |
Frozensets
请注意,“itemsets”列中的条目类型是 frozenset
,这是一种 Python 内置类型,类似于 Python set
,但它是不可变的,这使得它在某些查询或比较操作中更有效率(https://docs.pythonlang.cn/3.6/library/stdtypes.html#frozenset)。由于 frozenset
是集合,项的顺序无关紧要。也就是说,查询
rules[rules['antecedents'] == {'Eggs', 'Kidney Beans'}]
与以下任何三个查询是等价的
rules[rules['antecedents'] == {'Kidney Beans', 'Eggs'}]
rules[rules['antecedents'] == frozenset(('Eggs', 'Kidney Beans'))]
rules[rules['antecedents'] == frozenset(('Kidney Beans', 'Eggs'))]
示例 3 -- 前项和后项信息不完整的频繁项集
association_rules
计算的大多数度量标准都取决于频繁项集输入 DataFrame 中提供的给定规则的后项和前项支持度分数。考虑以下示例
import pandas as pd
dict = {'itemsets': [['177', '176'], ['177', '179'],
['176', '178'], ['176', '179'],
['93', '100'], ['177', '178'],
['177', '176', '178']],
'support':[0.253623, 0.253623, 0.217391,
0.217391, 0.181159, 0.108696, 0.108696]}
freq_itemsets = pd.DataFrame(dict)
freq_itemsets
项集 | 支持度 | |
---|---|---|
0 | [177, 176] | 0.253623 |
1 | [177, 179] | 0.253623 |
2 | [176, 178] | 0.217391 |
3 | [176, 179] | 0.217391 |
4 | [93, 100] | 0.181159 |
5 | [177, 178] | 0.108696 |
6 | [177, 176, 178] | 0.108696 |
请注意,这是一个“裁剪”的 DataFrame,不包含项子集的支持度值。如果我们想计算关联规则 176 => 177
的度量标准,这会造成问题。
例如,置信度的计算公式是
但我们没有。我们对“A”的支持度所知的是它至少为 0.253623。
在这种情况下,由于输入 DataFrame 不完整导致并非所有度量标准都能计算,您可以使用 support_only=True
选项,它将仅计算给定规则中不需要那么多信息的支持度列
所有其他度量标准列将被赋值为 "NaN"
from mlxtend.frequent_patterns import association_rules
res = association_rules(freq_itemsets, support_only=True, min_threshold=0.1)
res
前项 | 后项 | 前项支持度 | 后项支持度 | 支持度 | 置信度 | 提升度 | 杠杆率 | 确信度 | Zhang's 度量 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | (176) | (177) | NaN | NaN | 0.253623 | NaN | NaN | NaN | NaN | NaN |
1 | (177) | (176) | NaN | NaN | 0.253623 | NaN | NaN | NaN | NaN | NaN |
2 | (179) | (177) | NaN | NaN | 0.253623 | NaN | NaN | NaN | NaN | NaN |
3 | (177) | (179) | NaN | NaN | 0.253623 | NaN | NaN | NaN | NaN | NaN |
4 | (178) | (176) | NaN | NaN | 0.217391 | NaN | NaN | NaN | NaN | NaN |
5 | (176) | (178) | NaN | NaN | 0.217391 | NaN | NaN | NaN | NaN | NaN |
6 | (179) | (176) | NaN | NaN | 0.217391 | NaN | NaN | NaN | NaN | NaN |
7 | (176) | (179) | NaN | NaN | 0.217391 | NaN | NaN | NaN | NaN | NaN |
8 | (100) | (93) | NaN | NaN | 0.181159 | NaN | NaN | NaN | NaN | NaN |
9 | (93) | (100) | NaN | NaN | 0.181159 | NaN | NaN | NaN | NaN | NaN |
10 | (178) | (177) | NaN | NaN | 0.108696 | NaN | NaN | NaN | NaN | NaN |
11 | (177) | (178) | NaN | NaN | 0.108696 | NaN | NaN | NaN | NaN | NaN |
12 | (178, 176) | (177) | NaN | NaN | 0.108696 | NaN | NaN | NaN | NaN | NaN |
13 | (178, 177) | (176) | NaN | NaN | 0.108696 | NaN | NaN | NaN | NaN | NaN |
14 | (177, 176) | (178) | NaN | NaN | 0.108696 | NaN | NaN | NaN | NaN | NaN |
15 | (178) | (177, 176) | NaN | NaN | 0.108696 | NaN | NaN | NaN | NaN | NaN |
16 | (176) | (178, 177) | NaN | NaN | 0.108696 | NaN | NaN | NaN | NaN | NaN |
17 | (177) | (178, 176) | NaN | NaN | 0.108696 | NaN | NaN | NaN | NaN | NaN |
为了使表示更清晰,您可能希望执行以下操作
res = res[['antecedents', 'consequents', 'support']]
res
前项 | 后项 | 支持度 | |
---|---|---|---|
0 | (176) | (177) | 0.253623 |
1 | (177) | (176) | 0.253623 |
2 | (179) | (177) | 0.253623 |
3 | (177) | (179) | 0.253623 |
4 | (178) | (176) | 0.217391 |
5 | (176) | (178) | 0.217391 |
6 | (179) | (176) | 0.217391 |
7 | (176) | (179) | 0.217391 |
8 | (100) | (93) | 0.181159 |
9 | (93) | (100) | 0.181159 |
10 | (178) | (177) | 0.108696 |
11 | (177) | (178) | 0.108696 |
12 | (178, 176) | (177) | 0.108696 |
13 | (178, 177) | (176) | 0.108696 |
14 | (177, 176) | (178) | 0.108696 |
15 | (178) | (177, 176) | 0.108696 |
16 | (176) | (178, 177) | 0.108696 |
17 | (177) | (178, 176) | 0.108696 |
示例 4 -- 关联规则剪枝
没有特定的剪枝 API。相反,可以使用 pandas API 对结果数据框进行操作以删除单个行。例如,假设我们有以下规则
import pandas as pd
from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import apriori, fpmax, fpgrowth
from mlxtend.frequent_patterns import association_rules
dataset = [['Milk', 'Onion', 'Nutmeg', 'Kidney Beans', 'Eggs', 'Yogurt'],
['Dill', 'Onion', 'Nutmeg', 'Kidney Beans', 'Eggs', 'Yogurt'],
['Milk', 'Apple', 'Kidney Beans', 'Eggs'],
['Milk', 'Unicorn', 'Corn', 'Kidney Beans', 'Yogurt'],
['Corn', 'Onion', 'Onion', 'Kidney Beans', 'Ice cream', 'Eggs']]
te = TransactionEncoder()
te_ary = te.fit(dataset).transform(dataset)
df = pd.DataFrame(te_ary, columns=te.columns_)
frequent_itemsets = fpgrowth(df, min_support=0.6, use_colnames=True)
rules = association_rules(frequent_itemsets, metric="lift", min_threshold=1.2)
rules
前项 | 后项 | 前项支持度 | 后项支持度 | 支持度 | 置信度 | 提升度 | 杠杆率 | 确信度 | Zhang's 度量 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | (Eggs) | (Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 |
1 | (Onion) | (Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 |
2 | (Kidney Beans, Eggs) | (Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 |
3 | (Kidney Beans, Onion) | (Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 |
4 | (Eggs) | (Kidney Beans, Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 |
5 | (Onion) | (Kidney Beans, Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 |
并且我们想删除规则 "(Onion, Kidney Beans) -> (Eggs)"。为了做到这一点,我们可以定义选择掩码并按如下方式删除此行
antecedent_sele = rules['antecedents'] == frozenset({'Onion', 'Kidney Beans'}) # or frozenset({'Kidney Beans', 'Onion'})
consequent_sele = rules['consequents'] == frozenset({'Eggs'})
final_sele = (antecedent_sele & consequent_sele)
rules.loc[ ~final_sele ]
前项 | 后项 | 前项支持度 | 后项支持度 | 支持度 | 置信度 | 提升度 | 杠杆率 | 确信度 | Zhang's 度量 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | (Eggs) | (Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 |
1 | (Onion) | (Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 |
2 | (Kidney Beans, Eggs) | (Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 |
4 | (Eggs) | (Kidney Beans, Onion) | 0.8 | 0.6 | 0.6 | 0.75 | 1.25 | 0.12 | 1.6 | 1.0 |
5 | (Onion) | (Kidney Beans, Eggs) | 0.6 | 0.8 | 0.6 | 1.00 | 1.25 | 0.12 | 无穷大 | 0.5 |