Apriori算法是数据挖掘中十分经典的算法,在使用MapReduce 对其进行之前,先试着用java写一个简单的程序。
1.算法流程及伪代码描述
1.1 从数据文件data.txt 中按照文件的格式读入数据
data.txt:
T100 I1 I2 I5
T200 I2 I4
T300 I2 I3
T400 I1 I2 I4
T500 I1 I3
T600 I2 I3
T700 I1 I3
T800 I1 I2 I3 I5
T900 I1 I2 I3
1.2 将每一个Item 作为一个项集,并 统计出它在所有 输入数据文件中出现的次数
即得到:
I1 : 6 , I2 : 6, I3 : 6 , I4 : 2 , I5 : 2
上面的数据相当于 是 C(k-1) 即 , 候选集 C k-1 :此处仅仅是抽象理解,以为这个是 第一次读入数据 ,
不过要是泛化了思考的话,可以理解为 在多次迭代中的第 C k-1 次,
这样的话,后续的步骤 就是 从 C k-1 -> L k-1 -> C k-> L k
其中C 代表的是候选集的描述, 即 candidate ,
而L表示的是 频繁项集 。
1.3 然后,设定绝对支持度为 3,
这样的话,就可以将 I4 ,I5 它们在整个 数据集中出现的次数是 2 要小于最小支持度,
所以在 Ck-1 -> Lk-1 (Lk-1 为第 k-1 次 ,筛选出来的频繁项集) 的时候,I4 , I5 是被排除的。
得到 Lk-1 :
I1: 6 , I2 : 6 , I3: 6
1.4
这一步骤中要进行的是,从Lk-1 -> Ck ,也就是 对Lk-1 中的数据进行 连接
然后连接后的集合就是 第K次的候选项集了
但是这里的连接需要满足下面的条件才可以的。
比如说,将 位于 集合 Lk-1 中的两个 集合 l1 , l2 进行 连接的话,
l1 ,l2 必须满足下面的条件:
1. Length(l1 ) = length (l2)
2. differentElementNumber( l1, l2 ) = 1
3. l1 + x => l3 (对这个操作的解释是: 讲 l2 中唯一一个不同于 l1 的元素 归并到 l1 中之后 得到的新的集合 l3)
任意l3 的子集 都必须属于 Lk-1 对应的集合中
这个地方举个例子说明一下:
就是 假定 Lk-1 中的记录如下:
{I1, I2} ->l1
{I1,I3}->l2
{I1,I4}->l3
{I2,I3}->l4
l1 and l2 => l5:{l1,l2,l3}
l5 的所有子集集合为 {{l1}, {l2}, {l3},{l1,l2},{l2,l3},{l2,l3} } 它们都是Lk-1 中的 子集
当然 l5 中还有子集 {l1,l2,l3}这种情况我们不要考虑。
但是 l2 and l3 => l6:{ l1,l3,l4}
l6 中的所有子集的集合为(全集){{l1},{l2},{l3}, {l1,l3}, {l1,l4} ,{l3,l4} }
l6 就不能够将其归纳入到 Ck 中, 因为{l3,l4} 在 Lk-1 中是不存在的。
在这个地方用到的是 先验规则,就是说: 出现在Lk-1 中的所有 itemset 都是 k-1次,
筛选出来的 频繁相机,如果在Ck 中的 itemset 中的子集不在这个 k-1次 的频繁itemset 中的话,
那么他一定不是频繁itemset ,因为子集不是 frequent set 的话,它的任意 super set 都不可能是
frequent set . 即便 在Lk-1 到 Ck 这一步 该itemset 会被保留下来,但是,
Ck 到 Lk 这一步,也会 和 原始的数据集 进行比较 由于 支持度 小于最小支持度而被 删除,
提前一步删除的话,会降低
1. 生成过多的候选集合,
2, 减小与原始数据连接而浪费的时间
这样的话,我们就得到了 Ck, 然后再根据Ck中的项集 在最初数据源中
出现的次数进行统计,统计出来结果之后,对比最小支持度进行 记录的赛选就得到了
Lk,
按照上面的步骤一次迭代下去,直到求出的 满足 支持度的集合数目 为0 程序停止。
根据老师共享的 <数据挖掘导论> 这本书中的介绍,伪代码描述如下
record = getDataSet ( data.txt ) ;
record\'s content :
I1 I2 I5
I2 I4
I2 I3
I1 I2 I4
I1 I3
I2 I3
I1 I3
I1 I2 I3 I5
I1 I2 I3
cItemset = getFirstCandidate () ; ----> get Ck-1
lItemset = getSupportedItemset( cItemset ) ; -----> get Lk-1 from Ck-1
while ( cItemset not null )
{
ckItemset = getNextCandidate ( lItemset) ; -----> get Ck from Lk-1
lkItemset = getSupportedItemset ( ckItemset) ; -----> get Lk from Ck
cItemset = ckItemset ;
lItemset = lkItemset ; //for next loop
}
2.Apriori类中的各个模块方法描述
我将 Ck-1 Ck 也就是 相应的 候选集使用数据结构
List<List<String>> 来对其进行表示,
这样的话 对于一个 {I1, I2 ,I5} {I1, I3} 就可以存储成 : List<<<I1>, <I2> ,<I5>>, <<I1>,<I3>>的数据格式了。
将频繁itemset 使用 Map<List<String>, Integer> 来对其进行表示,
这样, itemset {I1, I2 , I5 } 在record 出现的次数 为 4 次的话,就可以表示成:
<<<I1>,<I2>,<I5>> , 4> 这样的数据类型了。
List<List<String>> : getFirstCandidate () : 用于直接从record中读取 1项集 对应出现的次数 以及 项集对应的名字
Map<List<String>, Integer> :getSupportedItemset( List<List<String>> cItemset) :
这个方法 是从 Ck-1 中获取 支持度 满足最小支持度 的 集合,
List<List<String>> : getNextCandidate( Map<List<String>,Integer>)
这个方法, 是从Lk-1 中获取 Ck 的方法。
//reader.java
myApriori.zip
3.出处: 这个算法的源代码是 来自: http://www.cnblogs.com/fengfenggirl/p/associate_apriori.html#2752667
LZ在拜读他的代码之后,对其中的一些地方进行了修改得出的这个算法的代码,
通过阅读他的 github 上面的代码,学习到了很多东西,博主的很多关于数据挖掘的算法文章都是相当好的,极力推荐一下。
本算法,不是十分的严谨与完善,没有涉及到关于置信度那个地方的知识,
也希望起到一个抛砖引玉的作用,
有同学实现了的话,可以将代码贴上一起分享一下。
1.算法流程及伪代码描述
1.1 从数据文件data.txt 中按照文件的格式读入数据
data.txt:
T100 I1 I2 I5
T200 I2 I4
T300 I2 I3
T400 I1 I2 I4
T500 I1 I3
T600 I2 I3
T700 I1 I3
T800 I1 I2 I3 I5
T900 I1 I2 I3
1.2 将每一个Item 作为一个项集,并 统计出它在所有 输入数据文件中出现的次数
即得到:
I1 : 6 , I2 : 6, I3 : 6 , I4 : 2 , I5 : 2
上面的数据相当于 是 C(k-1) 即 , 候选集 C k-1 :此处仅仅是抽象理解,以为这个是 第一次读入数据 ,
不过要是泛化了思考的话,可以理解为 在多次迭代中的第 C k-1 次,
这样的话,后续的步骤 就是 从 C k-1 -> L k-1 -> C k-> L k
其中C 代表的是候选集的描述, 即 candidate ,
而L表示的是 频繁项集 。
1.3 然后,设定绝对支持度为 3,
这样的话,就可以将 I4 ,I5 它们在整个 数据集中出现的次数是 2 要小于最小支持度,
所以在 Ck-1 -> Lk-1 (Lk-1 为第 k-1 次 ,筛选出来的频繁项集) 的时候,I4 , I5 是被排除的。
得到 Lk-1 :
I1: 6 , I2 : 6 , I3: 6
1.4
这一步骤中要进行的是,从Lk-1 -> Ck ,也就是 对Lk-1 中的数据进行 连接
然后连接后的集合就是 第K次的候选项集了
但是这里的连接需要满足下面的条件才可以的。
比如说,将 位于 集合 Lk-1 中的两个 集合 l1 , l2 进行 连接的话,
l1 ,l2 必须满足下面的条件:
1. Length(l1 ) = length (l2)
2. differentElementNumber( l1, l2 ) = 1
3. l1 + x => l3 (对这个操作的解释是: 讲 l2 中唯一一个不同于 l1 的元素 归并到 l1 中之后 得到的新的集合 l3)
任意l3 的子集 都必须属于 Lk-1 对应的集合中
这个地方举个例子说明一下:
就是 假定 Lk-1 中的记录如下:
{I1, I2} ->l1
{I1,I3}->l2
{I1,I4}->l3
{I2,I3}->l4
l1 and l2 => l5:{l1,l2,l3}
l5 的所有子集集合为 {{l1}, {l2}, {l3},{l1,l2},{l2,l3},{l2,l3} } 它们都是Lk-1 中的 子集
当然 l5 中还有子集 {l1,l2,l3}这种情况我们不要考虑。
但是 l2 and l3 => l6:{ l1,l3,l4}
l6 中的所有子集的集合为(全集){{l1},{l2},{l3}, {l1,l3}, {l1,l4} ,{l3,l4} }
l6 就不能够将其归纳入到 Ck 中, 因为{l3,l4} 在 Lk-1 中是不存在的。
在这个地方用到的是 先验规则,就是说: 出现在Lk-1 中的所有 itemset 都是 k-1次,
筛选出来的 频繁相机,如果在Ck 中的 itemset 中的子集不在这个 k-1次 的频繁itemset 中的话,
那么他一定不是频繁itemset ,因为子集不是 frequent set 的话,它的任意 super set 都不可能是
frequent set . 即便 在Lk-1 到 Ck 这一步 该itemset 会被保留下来,但是,
Ck 到 Lk 这一步,也会 和 原始的数据集 进行比较 由于 支持度 小于最小支持度而被 删除,
提前一步删除的话,会降低
1. 生成过多的候选集合,
2, 减小与原始数据连接而浪费的时间
这样的话,我们就得到了 Ck, 然后再根据Ck中的项集 在最初数据源中
出现的次数进行统计,统计出来结果之后,对比最小支持度进行 记录的赛选就得到了
Lk,
按照上面的步骤一次迭代下去,直到求出的 满足 支持度的集合数目 为0 程序停止。
根据老师共享的 <数据挖掘导论> 这本书中的介绍,伪代码描述如下
record = getDataSet ( data.txt ) ;
record\'s content :
I1 I2 I5
I2 I4
I2 I3
I1 I2 I4
I1 I3
I2 I3
I1 I3
I1 I2 I3 I5
I1 I2 I3
cItemset = getFirstCandidate () ; ----> get Ck-1
lItemset = getSupportedItemset( cItemset ) ; -----> get Lk-1 from Ck-1
while ( cItemset not null )
{
ckItemset = getNextCandidate ( lItemset) ; -----> get Ck from Lk-1
lkItemset = getSupportedItemset ( ckItemset) ; -----> get Lk from Ck
cItemset = ckItemset ;
lItemset = lkItemset ; //for next loop
}
2.Apriori类中的各个模块方法描述
我将 Ck-1 Ck 也就是 相应的 候选集使用数据结构
List<List<String>> 来对其进行表示,
这样的话 对于一个 {I1, I2 ,I5} {I1, I3} 就可以存储成 : List<<<I1>, <I2> ,<I5>>, <<I1>,<I3>>的数据格式了。
将频繁itemset 使用 Map<List<String>, Integer> 来对其进行表示,
这样, itemset {I1, I2 , I5 } 在record 出现的次数 为 4 次的话,就可以表示成:
<<<I1>,<I2>,<I5>> , 4> 这样的数据类型了。
List<List<String>> : getFirstCandidate () : 用于直接从record中读取 1项集 对应出现的次数 以及 项集对应的名字
Map<List<String>, Integer> :getSupportedItemset( List<List<String>> cItemset) :
这个方法 是从 Ck-1 中获取 支持度 满足最小支持度 的 集合,
List<List<String>> : getNextCandidate( Map<List<String>,Integer>)
这个方法, 是从Lk-1 中获取 Ck 的方法。
//reader.java
myApriori.zip
3.出处: 这个算法的源代码是 来自: http://www.cnblogs.com/fengfenggirl/p/associate_apriori.html#2752667
LZ在拜读他的代码之后,对其中的一些地方进行了修改得出的这个算法的代码,
通过阅读他的 github 上面的代码,学习到了很多东西,博主的很多关于数据挖掘的算法文章都是相当好的,极力推荐一下。
本算法,不是十分的严谨与完善,没有涉及到关于置信度那个地方的知识,
也希望起到一个抛砖引玉的作用,
有同学实现了的话,可以将代码贴上一起分享一下。