序列模式挖掘算法之PrefixSpan

来源:互联网 发布:休眠状态关闭网络 编辑:程序博客网 时间:2024/06/09 19:58

序列模式挖掘算法之PrefixSpan

PrefixSpan 配套代码地址http://download.csdn.net/download/u012202808/9961002

本文从基本的概念和例子入手,最后通过讲解代码来解释PrefixSpan算法:

  • 序列模式挖掘简介
  • 序列模式挖掘的基本概念
  • PrefixSpan的基本概念
  • PrefixSpan算法过程讲解
  • 主要代码块展示和讲解

序列模式挖掘简介

    序列模式挖掘最早的提出是为了找出用户几次购买行为之间的关系。我们也可以理解成找出那些经常出现的序列组合构成的模式。它与关联规则的挖掘是不一样的,序列模式挖掘的对象以及结果都是有序的,即数据集中的项在时间和空间上是有序排列的,这个有序的排列正好可以理解成大多数人的行为序列(例如:购买行为),输出的结果也是有序的,而关联规则的挖掘是不一样的。    关联规则的挖掘容易让我们想到那个"尿布与啤酒"的故事,它主要是为了挖掘出两个事物间的联系,首先这两个事物之间是没有时间可空间的联系的,可以理解成它们之间是无序的。例如:泡面——火腿  在我们的生活中大多数人在买泡面后会选择买火腿,但是每个人购买的顺序是不一样的,就是说这两个在时空上是没有联系的,找到的是搭配规律。这就是关联规则挖掘。(这是我个人的理解,有不同理解的请讨论)    序列模式挖掘的挖掘出来的是有序的。我们考虑一个用户多次在超市购物的情况,那么这些不同时间点的交易记录就构成了一个购买序列,例如:1用户在第一次购买了商品A,第二次购买了商品B和C;那么我们就生成了一个1用户的购物序列A-B,C.当N个用户的购买序列就形成了一个规模为N的数据集。这样我们就可以找到像"尿不湿--婴儿车"这样的存在因果关系的规律。因此序列模式挖掘相对于关联规则挖掘可以挖掘出更加深刻的知识。

序列模式挖掘的基本概念

序列模式挖掘的定义为:给定一个序列数据库和最小支持度,找出所有支持度大于最小支持度的序列模式
我们通过下面的例子来加深我们的理解
DATABASE

序列(Sequence):一个序列就是一个完整的信息流。

例如上面图中的U_ID 1 在8月1号购买了商品A和B,在8月10号的时候购买了商品B,在8月31号的时候购买了商品A和B。因此U_ID 1的序列为:A,B–B–A,B

项(Item):序列中单位最小的。

例如上面的A就是一个项

事件(Event):通常由时间戳标记,标记处事件之间的时间关系。

上图中的T_ID就是表示时间戳,可以看出用户购买的先后顺序。

k频繁序列(k-frequent sequence):如果频繁序列的项目数为k,则成为k频繁序列。
支持度(Support):某个序列的支持度就是指在整个序列集中包含该序列出现的次数。
子序列(Sub-sequence):对于序列x和y,使得x中的每一个事件都被包含于y的某个事件,则称x是y的子序列。

B–AC是序列AB–E–ACD的子序列,但是E–AB不是,因为顺序要相同,因为序列是有顺序的序列。
通过上面的例子我们可以看到 1,2,3 , 4用户都购买过商品A,因此商品A的支持度为4(虽然用户1购买过两次商品A。但是我们在计算支持度的时候该商品只要出现在该用户的数据集中只要大于等于一次,该商品的支持度都会为1)如果它满足最小支持度那它可以成为1阶频繁序列。
只有用户2购买过商品C,因此商品C的支持度为 1
我们看到在买过商品B后下次购买A的用户有用户1,3,4因此序列B–A的支持度为3,因为含有2个项,如果它满足最小支持度那它可以成为2阶频繁序列。
向这样我们可以找到所有的序列以及他们的支持度。我们设置最小支持度为75%,在这个例子里面就是4*75% = 3 。就是找出所有满足支持度为3的序列,我们得到下面的结果:
挖掘后的结果

PrefixSpan的基本概念

PrefixSpan算法思想:采用分治的思想,不断产生序列数据库的多个更小的投影数据库,然后在各个投影数据库上进行序列模式挖掘 
PrefixSpan算法相关定义:

前缀(Prefix):设每个元素中的所有项目按照字典序排列。论文中给出的定义,在此处就不再阐述,

例:序列<(ab)> 是序列<(abd)(acd)> 的一个前缀;序列<(ad)>则不是前缀。我们可以理解成单独的一个括号中定义为前缀时,中间是不可以有间隔的。

后缀(Postfix):每一个序列对于它的前缀都含有一个它的后缀,如果该序列不包含这个前缀,那么它对应的后缀为空集

例:对于 序列<(ab)(acd)>,其子序列<(b)>的后缀为<(acd)>。我们可以理解成后缀是不包含前缀,原序列中从前缀最后一项第一次出现的位置之后的项所组成的序列。(这样说其实不太严谨,但是便于理解。)

投影(Projection):给定序列α和β,如果β是α的子序列,则α关于β的投影α’必须满足: β是α’的前缀,α’是β的满足上述条件的最大子序列

例:对于 序列α =<(ab)(acd)>, 其子序列β = <(b)>的投影是α’= <(b)(acd)>(我们也可以表示为α’= <(_b)(acd)>); <(ab)>的投影是原序列<(ab)(acd)>。我们可以理解成投影是包含前缀的和后缀所组成的。(这样说其实不太严谨,但是便于理解。)

投影数据库(Projection database):设α为序列数据库S中的一个序列模式,则α的投影数据库为S中所有以α为前缀的序列相对于α的后缀,记为S|α。

这是论文中给我们的定义,但是在实际的运用当中,大多数人喜欢将后缀所组成的数据库当做投影数据库。这和它原本的定义是有一些小出入的,但是其算法的本质是没有任何影响的。(个人的观点,有错误的欢迎指出。)在后续中我们提到的投影数据库,就是后缀数据库。

PrefixSpan算法过程讲解

PrefixSpan算法描述: 
Step1:扫描序列数据库,生成所有满足min_sup长度为1的序列模式
Step2:根据长度为1的序列模式,生成相应的投影(后缀)数据库
Step3:在相应的投影数据库上重复上述步骤,直到在相应的投影数据库上不能产生长度为1的序列模式为止
Step4:分别对不同的投影数据库重复上述过程,直到没有新的长度为1的序列模式产生为止

算法描述

例子:
我们需要挖出满足最小支持度为2的数据集

Sid Sequence c1 <(1, 2) (1,3)> c2 <(3,4) (5, 6, 7)> c3 <(1,3) (8) (7)> c4 <(1,4)(8)>

我们可以找到所有满足min_sup的频繁单项集单项所对应的支持度:

Item Support 1 3 3 2 4 2 7 2 8 2

然后我们在原数据库中将非频繁的单项去掉,因此原数据库将会变成:

Sid Sequence c1 <(1) (1,3)> c2 <(3,4) (7)> c3 <(1,3) (8) (7)> c4 <(1,4)(8)>

由频繁单项作为前缀生成的投影数据库:

Prefix Postfix database Frequent length-2 sequential <1> <(1,3)><><(_3),8,7><(_4),8> <(1,3)>:2, <1,8>:2 <3> <><(_4),7><8,7><> <3,7>:2 <4> <><7><><8> <> <7> <><><><> <> <8> <><><7><> <>

我们在上面的投影数据库中继续寻找满足最小支持度的频繁单项集与前面的前缀构成了长度为2的频繁序列,由此作为前缀生成新的投影数据库:

Prefix Postfix database Frequent length-2 sequential <(1,3)> <><><8,7><> <> <(1,8)> <><><7><> <> <(3,7)> <><><><> <>

当由长度为2的频繁序列作为前缀生成的投影数据库中没有了频繁单项集,则算法结束。
从而也可以得到所有长度为2且满足最小支持度的序列模式。

下面的例子是论文中出现的例子:
这里写图片描述

这里写图片描述
通过对a-projected database的扫描,我们可以找到所有含有前缀a的长度为2且满足最小支持度的序列模式:{a,a}:2,{a,b}:4,{(a,b)}:2,{a,c}:4,{a,d}:2,{a,f}:2
需要注意的就是(_b)接收(_b)或者<前缀>b

主要代码块展示和讲解

代码采用的语言是python

def prefixSpan(pattern, S, threshold):    patterns = []    f_list = frequent_items(S, pattern, threshold)    for i in f_list:        p = SequencePattern(pattern.squence, pattern.support)        p.append(i)        patterns.append(p)        p_S = build_projected_database(S, p)        p_patterns = prefixSpan(p, p_S, threshold)        patterns.extend(p_patterns)    return patterns

该代码块表示出了整个PrefixSpan算法的主函数。主要的是可以理解为我们先找到数据集中的频繁单项集f_list,对于每一个f_list中的频繁单项集我们需要去构建他们的投影数据库(函数名为build_projected_database),然后在投影数据库p_S下去寻找他们的频繁单项集。
SequencePattern表示为我们自己定义的一个类。可以表示为频繁项集和它的支持度。

原创粉丝点击