Transcript Lecture3

频繁模式与关联规则挖掘
林琛
博士、副教授
数据挖掘领域的十大经典算法
• Apriori: Rakesh Agrawal and Ramakrishnan Srikant. Fast Algorithms
for Mining Association Rules. In VLDB ‘94.
– #4 (52 votes)
• FP-Tree: Han, J., Pei, J., and Yin, Y. 2000. Mining frequent patterns
without candidate generation. In SIGMOD '00.
– 他引超过3000次
• GSP: Srikant, R. and Agrawal, R. 1996. Mining Sequential Patterns:
Generalizations and Performance Improvements. In Proceedings of
the 5th International Conference on Extending Database Technology,
1996.
• PrefixSpan: J. Pei, J. Han, B. Mortazavi-Asl, H. Pinto, Q. Chen, U.
Dayal and M-C. Hsu. PrefixSpan: Mining Sequential Patterns
Efficiently by Prefix-Projected Pattern Growth. In ICDE '01.
• gSpan: Yan, X. and Han, J. 2002. gSpan: Graph-Based Substructure
Pattern Mining. In ICDM '02.
大纲
• 频繁项集与关联规则
–
–
–
–
–
形式定义
Apriori算法
FP-tree算法
关联规则挖掘
关联规则的评估
• 序列模式挖掘(简略)
– GSP
– PrefixSpan
• 频繁子图挖掘(简略)
– gSpan
频繁项集的形式定义
Tid
Items bought
10
Beer, Nuts, Diaper
20
Beer, Coffee, Diaper
30
Beer, Diaper, Eggs
40
Nuts, Eggs, Milk
50
Nuts, Coffee, Diaper, Eggs, Milk
Support({Beer})= 3/60%
Support({Nuts})=3/60%
Support({Diaper})=4/80%
Support({Eggs})=3/60%
Support({Beer, Diaper})=3/60%
Support({Nuts,Diaper})=2/40%
如果min_support=50%
• 项集: 项目的集合。
– k-项集 X = {x1, …, xk}
• 绝对支持度(支持度计数): 项集
X的出现次数(频率),即包含项
集的事务数
– 相对支持度, s:事务集中包含项集
的事务的百分比
• 频繁项集 :如果项集X的相对支
持度满足某个给定的阈值
频繁k项集 Lk
– 闭频繁项集X:如果不存在X的真超
频繁1项集–
集Y,具有和X相同的支持度计数
闭的,– 极大频繁项集X:如果X是频繁的,
闭的,且不存在频繁项集Y是X的超
非极大的
集
频繁2项集
不是闭的
极大频繁项集
4
关联规则的形式定义
Tid
Items bought
10
Beer, Nuts, Diaper
20
Beer, Coffee, Diaper
30
Beer, Diaper, Eggs
40
Nuts, Eggs, Milk
50
Nuts, Coffee, Diaper, Eggs, Milk
同时购买beer和diaper: 3/60%
• 关联规则是形如A → B的蕴涵式
– A,B是项集
– 具有支持度s
s=P(A B)
– 具有置信度c
c=P(B|A)
– 强规则:同时满足最小支持度阈值
和满足最小置信度阈值
给定 min_sup = 50%, min_conf = 50%
找出关联强规则
Beer  Diaper (60%, 100%)
Diaper  Beer (60%, 75%)
购买beer: 3/60%
购买diaper: 4/80%
5
关联规则的挖掘过程
• 找出所有的频繁项集
• 由频繁项集产生强关联规则
– 或者其他的有价值的关联规则
• 挖掘关联规则的性能由挖掘频繁项集决定
• 考虑一个简单枚举的算法
– 假设样本数(记录数)为N,维度(项目数)
为D,每条记录的长度为w
– 算法复杂度O(2dNw)
Apriori算法
Apriori性质
算法伪代码
• 频繁项集的所有非空子集
也必须是频繁的
Ck: Candidate itemset of size k//候选集
Lk : frequent itemset of size k//频繁项集
L1 = {frequent items};
//由底向上生成候选集
for (k = 1; Lk !=; k++) do
//产生步
Ck+1 = apriori_gen
//测试步
Lk+1 = count(Ck+1 )>= min_support
end
end
return k Lk;
ABCD
ABC
AB
ABD
AC
A
ACD
AD
BC
B
C
D
{}
Itemset lattice
BCD
BD
CD
Apriori算法的产生步
Ck+1 = apriori_gen
Ck+1 = join(L1…Lk);//连接步
Ck+1 =pruning(Ck+1 );//剪枝步
Apriori性质
Apriori算法的例子
购物篮记录 min_support = 2
Tid
Items
10
C1
A, C, D
20
B, C, E
30
A, B, C, E
40
B, E
扫描计数
Itemset
{A, C}
{B, C}
{B, E}
{C, E}
{A, B, C}
{B, C, A}
连接
{B, C, E}
{B, E, A}
{B, E, C}
{C, E, A}
{C, E, B}
C3
sup
{A}
2
{B}
3
{C}
3
{D}
1
{E}
3
L2
Itemset
{A, C, E}
Itemset
sup
2
2
3
2
剪枝
Itemset
sup
{A}
2
{B}
3
{C}
3
{E}
3
L1
C2
Itemset
{A, B}
{A, C}
{A, E}
{B, C}
{B, E}
{C, E}
连接+剪枝
sup
1
2
1
2
3
2
{B, C, E}
测试
{A, B}
{A, C}
C2
{A, E}
{B, C}
{B, E}
{C, E}
C3
Itemset
Itemset
扫描计数 L3
Itemset
sup
{B, C, E}
2
9
连接步策略
• 对项编码
– 项按字典序存储
– 项集中的项排序
•
Itemset
L1
Ck+1 = L1×Lk
– 一个频繁k项集和一个不属
于频繁k项集的频繁项
– 且频繁项比频繁k项集中的
所有项都大
• Ck+1 = Lk-1×Lk-1
– 一个频繁k项集和一个频繁
k项集
– 且两个频繁k项集的前k-1
项相等
• 哪一个策略产生的重复项集
多?
• 哪一个策略产生的不必要的
候选项集多?
sup
{A}
2
{B}
3
{C}
3
{E}
3
L2
sup
2
2
3
2
策略2
策略1
C3
Itemset
{A, C}
{B, C}
{B, E}
{C, E}
Itemset
Itemset
{A, C, E}
{B, C, E}
{B, C, E}
剪枝
Itemset
{B, C, E}
剪枝
Apriori算法的测试步
• Lk+1 = count(Ck+1 )>= min_support
– 策略1:比较每个记录与每个候选项集
– 策略2:枚举每个记录所包含的项集,与每个候
选项集比较
散列树的数据结构与构造
)
count(Ck+1
construct(HTree);
traversal(Htree,T)
struct HashTreeNode
{
bool leaf;
//叶节点标志
int level;
//该节点层级
itemset* candidate;
//指向候选项集
struct node * child[m];
//指向下一层子节点
}
Foreach (l in Ck+1) do //插入
current=root;
while(!current.leaf) do
k=current.level;
n=h(l[k]);
current=current.child[n];
end
current.candidate.insert(l);
if (current.candidate.size>max_leafsize) //分裂
current.leaf=false;
current.level=++k;
foreach (s in current.candidate) do
n=h(s[k]);
current.child[n].candidate.insert(s);
end
end
end
哈希函数
max_leafsize=3
3,6,9
1,4,7
2,5,8
散列树的构造:例子
C3
{124,125,136,145,159,234,345,356,357,367,368,457,458,567,689}
1
2
2
234
567
124
1 235
145
124
457
12
34
6
1
12
45
5
159
4 15 27 5
458
136
159
345
345
356
357
367
356
357
689
367
368
基于散列树的支持度计数
Input: data set T, k, HashTree
W-K+1
for t in T
Recursivetraverse (1,HashTree.root,t);
t:
1 2 3 5 6 10
end
Recursivetraverse (int level, HashTreeNode node, Transaction t)
Level=1
K-1
if (node.leaf)
compare(t,node.candidate);
t’=trim(t): 2 + 3 5 6 10
return;
else
for (int b=level~w-k+level) do
node=node.child[h(t[b])];
t=trim(t);
Recursivetraverse(level+1,node,t);
end
end
基于散列树的支持度计数:例子
哈希函数
3,6,9
1,4,7
t: 1 2 3 5 6
2,5,8
2+ 356
1+2356
3+ 56
234
567
13+56
145
136
12+356
124
457
比较5个叶子节点中的9个候选项集
而不需要比较总共15个候选项集
125
458
159
345
356
357
689
367
368
减少扫描代价的其他方法
• 数据压缩
– 已经得到频繁k项集
– 测试候选k+1项集
• 删除/标记不包含任何频繁k项集的记录
• 抽样
– 在原始数据的样本上挖掘频繁项集
– 牺牲精度
Apriori算法复杂度分析
• 影响Apriori算法效率的因素
–
–
–
–
支持度阈值
维度D
样本数N
平均记录长度w
• Apriori算法复杂度
– 频繁1项集(第一次扫描)O(Nw)
– 对于每个k
•
•
•
•
候选项集连接O(| Lk-1 | 2(k-2))
构造散列树k|Ck|
剪枝O((k-2)(k-1) |Ck|)
测试O(NCwk)
FP增长算法
• 不产生候选
• 有限的扫描次数
• 索引全数据集
– FP-tree
– 挖掘频繁项集在索引结构上进行
FP树构造
• 扫描数据集:第一次
– 频繁项支持度计数
– 频繁项排序
– 记录改写
Input: data set T
root=new FPnode;
foreach (Transaction t in T) do
insert(t[1],t-t[1],root);
end
insert (item m, itemset ms, FPnode node)
构造FP树
branch=node.children.seek(m)
if (!branch)
• 每个节点包含
count(branch)++;
–项
else
– 计数
branch=new Fpnode;
– 指向孩子节点的指针
count(branch)=1;
*itemtable[m].link=&branch;
构造项头表
end
insert (ms[1],ms-ms[1],branch);
• 扫描数据集:第二次
–
–
min_support = 3
1.
FP树构造
Tid
Items
Tid
Items
100
f, a, c, d, g, i, m, p
100
f, c, a, m, p
200
a, b, c, f, l, m, o
200
f, c, a, b, m
300
b, f, h, j, o, w
300
f, b
400
b, c, k, s, p
400
c, b, p
500
a, f, c, e, l, p, m, n
500
f, c, a, m, p
扫描第一遍
• 计算支持度计数
• 得到频繁1项集
• 按照支持度递减排序
• 重写记录,只包含频繁项并排序
频繁1项集
sup
f
4
c
4
a
3
b
3
m
3
p
3
2. 扫描第二遍
•
构造FP树的根节点
•
每条记录
•增加分支
•增加项头表
{}
f:1432
项头表
项
f
c
a
b
m
p
频率 指针
4
4
3
3
3
3
□
□
□
□
□
□
c:1
c:1
32 b:1 b:1
a:132
m:12 b:1
p:12
m:1
p:1
FP树挖掘频繁模式
• 从频繁1项集(初始后缀模式)开始由底向
上
– 分治地对后缀模式
• 生成条件FP树
–
–
–
–
删除不与后缀模式一起出现的分支
删除后缀
更新支持度计数
删除非频繁项
• 条件模式基
– FP树中的与后缀模式一起出现的前缀路径集
• 递归挖掘条件FP树
FP树挖掘频繁模式:例子
{}
min_support = 3
f:4
项头表
项
f
c
a
b
m
p
频率 指针
4
4
3
3
3
3
1,自底向上
□
□
□
□
□
□
c:3
2,以p为初始后缀模式
生成p的条件FP树
•删除不与后缀模式一起出现的分支
•删除后缀
•更新支持度计数
•删除非频繁项
c:1
b:1 b:1
a:3
p:1
m:2
b:1
p:2
m:1
•包含p
•不包含p,含m
•不包含p/m,含b
•不包含p/m/b,含a
•不包含p/m/b/a,含c
•只包含f
条件模式基
p
c:3
f:2
项头表
项
f
c
a
b
m
{}
频繁项集
cp
频率 指针
2
3
2
1
2
□
□
□
□
□
c:1
c:2
b:1
a:2
m:2
{}
c:3
FP树挖掘频繁模式:例子(2)
min_support = 3
f:4
项头表
项
f
c
a
b
m
p
频率 指针
4
4
3
3
3
3
c:3
•删除不与后缀模式一起出现的分支
•删除后缀
{}
•更新支持度计数
•删除非频繁项
c:1
b:1 b:1
f:3
项头表
a:3
p:1
m:2
b:1
p:2
m:1
f
c
a
b
c:3
频率 指针
□
□
□
□
3
3
3
1
{}
条
件
条
件
树
FP
f:3
am
条件模式基
m
fca:3
分治更长的后缀模式
fm, cm, am, fcm, fam,fcam
a:3
FP
•包含p
•不包含p,含m
•不包含p/m,含b
•不包含p/m/b,含a
•不包含p/m/b/a,含c
•只包含f
项
cm
1,自底向上
□
□
□
□
□
□
2,以p为初始后缀模式
生成p的条件FP树
{}
树
b:1
{}
f:3
c:3
关联规则
• 枚举的方法
– 给定频繁项集 L, 非空子集 f  L ,测试f  L – f
是否满足置信度 阈值
– 如果 {A,B,C,D} 是频繁的, 候选规则包括:
ABC D,
A BCD,
AB CD,
BD AC,
ABD C,
B ACD,
AC  BD,
CD AB,
ACD B,
C ABD,
AD  BC,
BCD A,
D ABC
BC AD,
– 对于频繁k项集 |L| = k, 有2k – 2 条候选规则 (即
忽略 L   and   L)
基于置信度的剪枝
ABCD=>{ }
BCD=>A
CD=>AB
BD=>AC
D=>ABC
ACD=>B
BC=>AD
C=>ABD
ABD=>C
AD=>BC
B=>ACD
ABC=>D
AC=>BD
AB=>CD
A=>BCD
如果形如X->Y-X的规则不满足置信度阈值,那么形如X’->Y-X’的规则也一定不满
足置信度阈值,其中X’是X的子集
关联规则产生算法
for (k=1~K) do
//频繁k项集
for (H1in Lk) do
//从1项后件开始
rulegen (H1,Lk);
end
end
rulegen (Hm ,L)
if (|L|>|Hm|)
apriori_gen (Hm+1);
foreach (hm+1 in Hm+1) do
if (conf>min_conf)
output “L-hm+1 hm+1”;
else
delete hm+1 from Hm+1;
end
end
rulegen (Hm+1 ,L);
end
数据挖掘的基本流程
数据
数据 挖掘
预处
数据 理
获取
模式
评估
用户
界面
兴趣度度量: 提升度
• 强关联规则不一定有趣
– 打篮球 吃麦片 [支持度40%, 置信度66.7%] 是一个误导的强关联规则
– 如果吃麦片占所有学生的75% (> 66.7%)
– 打篮球 与吃麦片负相关,即打篮球  不吃麦片 [20%, 33.3%]
• 扩充关联规则框架:A B [支持度,置信度,相关度]
P( A B)
lift 
P( A) P( B)
lift (篮球 , 麦片) 
2000 / 5000
 0.89
3000 / 5000 * 3750 / 5000
篮球
非篮球
Sum (row)
麦片
2000
1750
3750
非麦片
1000
250
1250
Sum(col.)
3000
2000
5000
打篮球 吃麦片 [支持度40%, 置信度66.7%,相关度0.89]
lift (篮球, 非麦片 ) 
1000 / 5000
 1.33
3000 / 5000 *1250 / 5000
打篮球  不吃麦片 [20%, 33.3%,1.33]
时间序列数据
股票
时间序列数据集由不同时间重复测量
得到的值或事件的序列组成。
序列数据集是由事件序列组成,不一
定有具体的时间概念。
GPS
网络点击流
序列模式的形式定义
• 事件=项集
• 序列=事件的有序列表
– 序列的长度是序列中包含的事件/项个数
• L-序列是序列中的项数目为l的序列
• 子序列和超序列
– 序列α=<a1a2an>是序列β=<b1b2…bm>的子序列, β 是α的超序
列 
– 如果存在整数1≤j1<j2…jn≤m,使得 a  b ,..a  b
1
j1
n
jm
• 序列数据集(库)S是序列的集合
• 序列模式=频繁序列
– 序列α在序列数据集S中的支持度=序列数据集中包含序列α的
记录数 |   s, s  S |
– 一个序列α是频繁的,如果α的支持度满足最小支持度阈值
序列模式的形式定义:例子
序列数据集S
SID
10
20
30
40
4,找到S中包含的所有频繁2-序列
sequence
<a(abc)(ac)d(cf)>
<(ad)c(bc)(ae)>
<(ef)(ab)(df)cb>
<eg(af)cbc>
1,说明序列10,20,30,40的事件数和项数?
5/9,4/7,5/8,6/7
2,<a(bc)dc> 是哪个序列的子序列
<a(abc)(ac)d(cf)>
3,给定min_sup = 2, <(ab)c>是序列模式吗?
是。因为<(ab)c>的支持度为2
<aa>,<ab>,<ac>,<ad>,<af>,
<ba>,<bc>,<bd>,<bf>,
<ca>,<cb>,<cc>,
<db>,<dc>,
<ea>,<eb>,<ec>,<ef>,
<fb>,<fc>,
<(ab)>
序列模式挖掘:GSP算法
• GSP算法(Generalized Sequential Patterns)
– 利用了Apriori性质,即任何序列模式的非空子
序列也是序列模式
– 算法框架
1. 扫描第一遍,得到频繁1项,即频繁1-序列
2. 扫描第k遍,得到频繁k-序列
1.
2.
3.
由频繁k-1-序列连接得到候选k-序列
剪枝得到更小的候选k-序列集合
计算支持度计数,得到频繁k-序列
产生
测试
候选产生的方法
• 首先,序列本身有序。事件无序,但按照
(字典)序对事件中的项目排序
• 候选k-序列s由合并两个频繁k-1序列s1和s2
– 当且仅当s1去掉第一个项后的子序列等于s2去掉
最后一个项之后的子序列
– 合并后等于s1加上
• 如果s2的最后一项在s2中是一个独立的事件,则作为
独立的一个事件加到s的最后
• 否则,在s中的最后一个事件里加上
候选产生的方法:例子
频繁3-序列
<1 5 3>
<5 (3 4)>
第一个序列去掉第一个项目,
第二个序列去掉最后一个项目
子序列
<5 3> = <5 3>
子序列
<2 3> = <2 3>
频繁3-序列
<1 2 3>
<2 3 4>
合并第一个序列与最后一个项目
如果最后一个项目
在第二个序列中
是独立事件
则作为独立事件加入
候选4-序列
<1 5 (3 4)>
否则,作为
最后一个事件的一项
加入
候选4-序列
<1 2 3 4>
这个方案是完备的吗?即,这样产生的候选k-序列没有遗漏任何可能的频繁k-序列吗?
PrefixSpan算法:形式定义
• 给定一个序列 α=<a1a2an>
序列:<a(abc)(ac)d(cf)>
– β= <b1b2…bm >是α的前缀,如果
前缀
<a>
• m≤n
• 对于所有的i <m,bi=ai
<aa>
• bm  am
<ab>
• am-bm的所有频繁项按字典序排在bm后
– γ= <rmrm+1…rn >是α关于前缀β的后缀
• rm=am-bm,如果rm不为空,一般写成(_...)
• 对于所有的i >m,ri=ai
关于前缀的后缀
<(abc)(ac)d(cf)>
<(_bc)(ac)d(cf)>
<(_c)(ac)d(cf)>
PrefixSpan算法思想
• 分治
– 以α为前缀的序列模式挖掘问题可以拆分为若
干个互不相交的以α β为前缀的序列模式挖掘问
题
• 扫描数据集,得到频繁1项
– 挖掘以频繁1项为前缀的序列模式
– 对于每个k前缀
• 递归的挖掘k+1前缀
PrefixSpan算法:例子
SID
10
20
30
40
sequence
<a(abc)(ac)d(cf)>
<(ad)c(bc)(ae)>
<(ef)(ab)(df)cb>
<eg(af)cbc>
序列数据集S
min_support =2
扫描,得到频繁1项集
L1
频率
a
4
b
4
c
4
d
2
E
3
f
3
g
1
分治
SID
10
20
30
40
sequence
<(abc)(ac)d(cf)>
<(_d)c(bc)(ae)>
<(_b)(df)cb>
<(_f)cbc>
前缀a的投影数据集
每条记录包含<a>
且是原记录中以<a>的第一次出现
为前缀的子序列
•挖掘前缀<a>序列模式
•挖掘前缀<b>序列模式
•…
•挖掘前缀<f>序列模式
扫描
局部
频繁
项
L1
频率
a
2
b
4
_b
2
c
4
_c
1
d
2
_d
1
e
1
_e
1
f
2
_f
1
递归挖掘前缀<aa>, <ab>, <(ab)>, <ac>, <ad>, <af>的序列模式
频繁子图挖掘的意义: AIDS
Compounds are active, inactive or moderately
active (CA, CI, CM)
频繁子图定义
• 给定一个图数据集D={G0,G1,…GN} ,其中每个图
是标号图,即图中各顶点和边带有标号
– 图g的支持度计数是 D中包含 g 为子图的图数目
– g是频繁[连通] 子图如果图数据集D中包含g作为子
图的图数目 support(g)≥minSup
–
–
–
分子结构图,节点V,点的标号N(V)={O,H,S,N…},边E,边的标号L(E)={-,=…}
–
min_support =2
频繁子图
Apriori算法
minSup=2
1. 从只包含1条边的子图开始
2. for
1. 由{K-1}-边频繁子图生成K-边子图候选集合
2. 剪枝
3. 计算支持度
end
同构
• 图G和G’同构
– 图 G和图 G′同构,如果存在双射f:V↔V’
(1)v V , N (v)  N ( f (v))
(2)(u, v)  E, L( E )  L(( f (u), f (v)))
• 子图同构
– G的子图和g同构
这两图一样吗?
gSpan算法基本思想
• 不产生候选
• 分治
– 递归
• 模式增长
– 子图同构检验是算法瓶颈
– DFS编码
DFS编码
• 对图进行深度优先遍历
– 所有节点根据发现时间排序
• 最后发现的节点叫做最右节点
• 从第一个节点到最右节点的直线路径叫做最右路径
– 所有边表示为五元组(i,j,ni,lij,nj)
• 前向边i<j
• 后向边i>j
• 边的排序:e1<e2, iff
–
–
–
–
同是前向边,且j1<j2
同是后向边,且i1<i2或者i1=i2&& j1<j2
e1是前向边,e2是后向边,且j1<=i2
e1是后向边,e2是前向边,且i1<j2
– 根据边的次序得到的边序列是图的DFS编码
DFS编码:例子
同一个图的不同DFS编码
确定唯一DFS code
• 一个图可能有多个DFS code
• 选择最小的DFS code=唯一编码
– 因为有label,所以考虑字典序
– 对于两个序列
边排序
• 序列a,长度为m v.s. 序列b,长度n
• a≤b
– 如果b比a长(n≥m),每个元素相等
• 如果有某个位置
– 这个位置之前的
较大点
较小的点
边label
最小DFS编码:例子
同一个图的不同DFS编码
次小
最小
最大
DFS 编码树
• 思想:用树结构的增长寻找/计数频繁同构
子图
– 树每个节点代表一个DFS编码
– 一棵树代表了所有可能的频繁子图
• DFS编码增长
– 最右节点+后向边
– 最右路径+前向边
– 考虑字典序
DFS编码树的剪枝
Min_support=2
红>绿>蓝
gSpan算法