博主初次接触数据挖掘方面的研究,从最经典最基础的Apriori算法编起,不过这是博主前几个月写的了,所以现在也是凭印象写的,有些粗糙,还请谅解。
下面讲解部分为转载
1 Apriori介绍
Apriori算法使用频繁项集的先验知识,使用一种称作逐层搜索的迭代方法,k项集用于探索(k+1)项集。首先,通过扫描事务(交易)记录,找出所有的频繁1项集,该集合记做L1,然后利用L1找频繁2项集的集合L2,L2找L3,如此下去,直到不能再找到任何频繁k项集。最后再在所有的频繁集中找出强规则,即产生用户感兴趣的关联规则。
其中,Apriori算法具有这样一条性质:任一频繁项集的所有非空子集也必须是频繁的。因为假如P(I)< 最小支持度阈值,当有元素A添加到I中时,结果项集(A∩I)不可能比I出现次数更多。因此A∩I也不是频繁的。
2 连接步和剪枝步
在上述的关联规则挖掘过程的两个步骤中,第一步往往是总体性能的瓶颈。Apriori算法采用连接步和剪枝步两种方式来找出所有的频繁项集。
1) 连接步
为找出Lk(所有的频繁k项集的集合),通过将Lk-1(所有的频繁k-1项集的集合)与自身连接产生候选k项集的集合。候选集合记作Ck。设l1和l2是Lk-1中的成员。记li[j]表示li中的第j项。假设Apriori算法对事务或项集中的项按字典次序排序,即对于(k-1)项集li,li[1] 小于li[2]<……….li[k-1]。将Lk-1与自身连接,如果(l1[1]=l2[1])&&( l1[2]=l2[2])&&……..&& (l1[k-2]=l2[k-2])&&(l1[k-1]小于l2[k-1]),那认为l1和l2是可连接。连接l1和l2 产生的结果是{l1[1],l1[2],……,l1[k-1],l2[k-1]}。
2) 剪枝步
CK是LK的超集,也就是说,CK的成员可能是也可能不是频繁的。通过扫描所有的事务(交易),确定CK中每个候选的计数,判断是否小于最小支持度计数,如果不是,则认为该候选是频繁的。为了压缩Ck,可以利用Apriori性质:任一频繁项集的所有非空子集也必须是频繁的,反之,如果某个候选的非空子集不是频繁的,那么该候选肯定不是频繁的,从而可以将其从CK中删除。
(Tip:为什么要压缩CK呢?因为实际情况下事务记录往往是保存在外存储上,比如数据库或者其他格式的文件上,在每次计算候选计数时都需要将候选与所有事务进行比对,众所周知,访问外存的效率往往都比较低,因此Apriori加入了所谓的剪枝步,事先对候选集进行过滤,以减少访问外存的次数。)
3 Apriori算法实例
交易ID 商品ID列表
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
上图为某商场的交易记录,共有9个事务,利用Apriori算法寻找所有的频繁项集的过程如下:
详细介绍下候选3项集的集合C3的产生过程:从连接步,首先C3={{I1,I2,I3},{I1,I2,I5},{I1,I3,I5},{I2,I3,I4},{I2,I3,I5},{I2,I4,I5}}(C3是由L2与自身连接产生)。根据Apriori性质,频繁项集的所有子集也必须频繁的,可以确定有4个候选集{I1,I3,I5},{I2,I3,I4},{I2,I3,I5},{I2,I4,I5}}不可能时频繁的,因为它们存在子集不属于频繁集,因此将它们从C3中删除。注意,由于Apriori算法使用逐层搜索技术,给定候选k项集后,只需检查它们的(k-1)个子集是否频繁。
3. Apriori伪代码
算法:Apriori
输入:D - 事务数据库;min_sup - 最小支持度计数阈值
输出:L - D中的频繁项集
方法:
L1=find_frequent_1-itemsets(D);
For(k=2;Lk-1!=null;k++)
Lk=
}
Return L=所有的频繁集;
Procedure apriori_gen(Lk-1:frequent(k-1)-itemsets)
For each项集l1属于Lk-1
For each项集 l2属于Lk-1
If((l1[1]=l2[1])&&( l1[2]=l2[2])&&……..
&& (l1[k-2]=l2[k-2])&&(l1[k-1]<l2[k-1])) then
Return Ck;
Procedure has_infrequent_sub(c:candidate k-itemset; Lk-1:frequent(k-1)-itemsets)
For each(k-1)-subset s of c
If s不属于Lk-1 then
Return true;
Return false;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
4. 由频繁项集产生关联规则
Confidence(A->B)=P(B|A)=support_count(AB)/support_count(A)
关联规则产生步骤如下:
1) 对于每个频繁项集l,产生其所有非空真子集;
2) 对于每个非空真子集s,如果support_count(l)/support_count(s)>=min_conf,则输出 s->(l-s),其中,min_conf是最小置信度阈值。
例如,在上述例子中,针对频繁集{I1,I2,I5}。可以产生哪些关联规则?该频繁集的非空真子集有{I1,I2},{I1,I5},{I2,I5},{I1 },{I2}和{I5},对应置信度如下:
I1&&I2->I5 confidence=2/4=50%
I1&&I5->I2 confidence=2/2=100%
I2&&I5->I1 confidence=2/2=100%
I1 ->I2&&I5 confidence=2/6=33%
I2 ->I1&&I5 confidence=2/7=29%
I5 ->I1&&I2 confidence=2/2=100%
如果min_conf=70%,则强规则有I1&&I5->I2,I2&&I5->I1,I5 ->I1&&I2。
JAVA代码原创,不过写的时候也是参照了部分前辈的代码,所以可能会有相似的地方,附带注释,希望大家能看懂
package test;
import java.util.*;
import java.util.Map.Entry;
public class Apriori_data {
private int countDatabase;
private Integer minSup;
private Float minCon;
private Map<Integer, Set<String>> database;
private Map<Set<String>, Integer> frequItemSets;
private Map<Integer,Map<Set<String>, Integer>> freshFrequItemSets;
private HashMap<Set<String>, Set<Set<String>>> associationRules;
public Apriori_data( Map<Integer, Set<String>> database,
Integer minSup,
Float minCon ) {
this.minSup = minSup;
this.minCon = minCon;
this.database = database;
countDatabase = database.size();
frequItemSets = new HashMap<Set<String>, Integer>();
associationRules = new HashMap<Set<String>, Set<Set<String>>>();
freshFrequItemSets = new HashMap<Integer, Map<Set<String>, Integer>>();
}
public HashMap<Set<String>, Integer> genFrequItemSets1(){
HashMap<Set<String>, Integer>frequItemSet1 = new HashMap<Set<String>, Integer>();
HashMap<Set<String>, Integer>candiItemSet1 = new HashMap<Set<String>, Integer>();
candiItemSet1 = genCandiFrequ1();
Iterator<Map.Entry<Set<String>,Integer>>it = candiItemSet1.entrySet().iterator();
while(it.hasNext()){
Entry<Set<String>, Integer> entry=it.next();
Integer v = entry.getValue();
if(v>=minSup){
frequItemSet1.put(entry.getKey(), v);
}
}
return frequItemSet1;
}
public HashMap<Set<String>, Integer> genCandiFrequ1(){
HashMap<Set<String>,Integer>candiItemSet1 = new HashMap<Set<String>, Integer>();
Iterator<Map.Entry<Integer,Set<String>>>it = database.entrySet().iterator();
while(it.hasNext()){
Map.Entry<Integer, Set<String>>s = it.next();
Set<String>item = s.getValue();
for(String key:item){
Set<String>value = new HashSet<String>();
value.add(key);
if(!candiItemSet1.containsKey(value)){
Integer k=1;
candiItemSet1.put(value, k);
}
else if(candiItemSet1.containsKey(value)){
Integer k=1+candiItemSet1.get(value);
candiItemSet1.put(value,k);
}
}
}
return candiItemSet1;
}
public Set<Set<String>> genCandiFrequen(int m, Map<Set<String>, Integer> frequItemSets2)
{
Set<Set<String>>candiItemSet =new HashSet<Set<String>>();
Iterator<Map.Entry<Set<String>, Integer>>originIt = frequItemSets2.entrySet().iterator();
while(originIt.hasNext()){
Set<String> item1 = originIt.next().getKey();
Iterator<Map.Entry<Set<String>, Integer>>currentIt = getIteratorF(item1,frequItemSets2);
while(currentIt.hasNext()){
Set<String> item2 = currentIt.next().getKey();
Set<String> symmetriSet = new HashSet<String>();
symmetriSet.addAll(item1);
symmetriSet.retainAll(item2);
if(symmetriSet.size()==m-1){
Set<String> differentSet = new HashSet<String>();
differentSet.addAll(item1);
differentSet.removeAll(item2);
differentSet.addAll(item2);
if(!candiItemSet.contains(differentSet)){
candiItemSet.add(differentSet);
}
}
}
}
return candiItemSet;
}
public boolean judgeForInvolve(Set<String> judgedItem, Set<Set<String>> frequItem)
{
Set<String> temp = new HashSet<String>();
temp.addAll(judgedItem);
for(String item:judgedItem){
temp.remove(item);
if(frequItem.contains(temp)){
temp.add(item);
}
else {
return true;
}
}
return false;
}
public Set<Set<String>> pruneForCandiItem(Set<Set<String>>candiItem, Set<Set<String>>frequItem)
{
Set<Set<String>> tempSet = new HashSet<Set<String>>();
tempSet.addAll(candiItem);
Iterator<Set<String>>it = candiItem.iterator();
while(it.hasNext()){
Set<String>set = it.next();
boolean flag = judgeForInvolve(set, frequItem);
if(flag)
tempSet.remove(set);
}
return tempSet;
}
public Map<Set<String>, Integer> caculateSupport(Set<Set<String>>candiItem)
{
HashMap<Set<String>, Integer>candiItemMap=new HashMap<Set<String>, Integer>();
Iterator<Set<String>>itForSet = candiItem.iterator();
while(itForSet.hasNext()){
Iterator<Set<String>>itForMap = database.values().iterator();
Set<String>itemForSet = itForSet.next();
Integer value=0;
while(itForMap.hasNext()){
if(itForMap.next().containsAll(itemForSet))
value++;
}
candiItemMap.put(itemForSet, value);
}
return candiItemMap;
}
public Map<Set<String>, Integer> genFrequItemK(int m, Map<Set<String>, Integer> frequItemSets2)
{
Map<Set<String>, Integer>frequItemk = new HashMap<Set<String>, Integer>();
Set<Set<String>> item = frequItemSets2.keySet();
Set<Set<String>> candiItem = genCandiFrequen(m,frequItemSets2);
Set<Set<String>> newCandiItem=pruneForCandiItem(candiItem,item);
Map<Set<String>, Integer> freshCandiItem= caculateSupport(newCandiItem);
Iterator<Map.Entry<Set<String>, Integer>>it = freshCandiItem.entrySet().iterator();
while(it.hasNext()){
Entry<Set<String>,Integer>entry = it.next();
Set<String> set = entry.getKey();
Integer value = entry.getValue();
if(value>=minSup)
frequItemk.put(set,value);
}
return frequItemk;
}
public Iterator<Map.Entry<Set<String>, Integer>> getIteratorF(Set<String> Item,Map<Set<String>, Integer> frequItemSets2)
{
Iterator<Map.Entry<Set<String>, Integer>>it = frequItemSets2.entrySet().iterator();
while(it.hasNext()){
if(Item.equals(it.next().getKey()))
break;
}
return it;
}
public void miningAllFreque(){
Map<Set<String>, Integer>frequ=genFrequItemSets1();
int k=1;
boolean flag = true;
while(flag){
frequItemSets=frequ;
freshFrequItemSets.put(k,frequItemSets);
frequ=genFrequItemK(k,frequItemSets);
k++;
if(frequ.isEmpty())
flag = false;
}
}
public void mineWholeAssociation()
{
freshFrequItemSets.remove(1);
Iterator<Map.Entry<Integer, Map<Set<String>, Integer>>>itForMap = freshFrequItemSets.entrySet().iterator();
while(itForMap.hasNext())
{
Entry<Integer,Map<Set<String>, Integer>> entry = itForMap.next();
Iterator<Map.Entry<Set<String>, Integer>>itForIterate =entry.getValue().entrySet().iterator();
while(itForIterate.hasNext())
{
mineSingleAssociation(itForIterate.next());
}
}
}
public void mineSingleAssociation(Entry<Set<String>, Integer> factor)
{
Set<String> frequentSet = factor.getKey();
Integer support = factor.getValue();
Map<Set<String>,Set<String>> subset =divergeToSubsets(frequentSet);
Iterator<Map.Entry<Set<String>, Set<String>>> it = subset.entrySet().iterator();
while(it.hasNext()){
Integer value = 0;
Entry<Set<String>, Set<String>> entry = it.next();
Set<String> subsetPart1 = entry.getKey();
Set<String> subsetPart2 = entry.getValue();
Iterator<Set<String>> itForSet = database.values().iterator();
while(itForSet.hasNext()){
Set<String> temp = itForSet.next();
if(temp.containsAll(subsetPart1))
{
value++;
}
}
if((support.floatValue()/value.floatValue())>=minCon)
{
if(!(associationRules.containsKey(subsetPart1))){
Set<Set<String>> subsetPart2Set = new HashSet<Set<String>>();
subsetPart2Set.add(subsetPart2);
associationRules.put(subsetPart1, subsetPart2Set);
}else{
associationRules.get(subsetPart1).add(subsetPart2);
}
}
}
}
public Map<Set<String>, Set<String>> divergeToSubsets(Set<String> item)
{
Map<Set<String>, Set<String>>subsets = new HashMap<Set<String>, Set<String>>();
Integer count = item.size();
Integer in=count/2;
Integer k=1;
QueueL<Set<String>> queue = new QueueL<Set<String>>();
Set<Set<String>> temp = new HashSet<Set<String>>();
for(String tempIt:item){
Set<String> tempSet = new HashSet<String>();
tempSet.add(tempIt);
queue.push(tempSet);
temp.add(tempSet);
}
while(k<in){
Set<String> tempSet = new HashSet<String>();
tempSet.addAll(queue.pop());
for(String iterate:item){
if(!(tempSet.contains(iterate)))
{
tempSet.add(iterate);
temp.add(tempSet);
queue.push(tempSet);
tempSet.remove(iterate);
}
}
System.out.println(queue.top());
k=queue.top().size();
}
Iterator<Set<String>> itForCombine = temp.iterator();
while(itForCombine.hasNext()){
Set<String> setPart2 = new HashSet<String>();
Set<String> setPart1 = new HashSet<String>();
setPart2.addAll(item);
setPart1.addAll(itForCombine.next());
setPart2.removeAll(setPart1);
subsets.put(setPart1, setPart2);
subsets.put(setPart2, setPart1);
}
return subsets;
}
public Map<Integer, Map<Set<String>, Integer>> getFrequentSets()
{
return freshFrequItemSets;
}
public Map<Set<String>, Set<Set<String>>> getAssociationRules()
{
return associationRules;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
package test;
import java.util.LinkedList;
class QueueL<T> {
private LinkedList<T> list = new LinkedList();
public void push(T o) {
list.addLast(o);
}
public T top() {
return list.getFirst();
}
public T pop() {
return list.removeFirst();
}
}
//测试文件
package test
import java.util.HashMap
import java.util.HashSet
import java.util.Map
import java.util.Set
public class Apriori_test {
private Apriori_data apriori
private Map<Integer,Set<String>> database
private Integer minSup = 2
private Float minCon = new Float("0.5")
public static void main(String []args){
Apriori_test test = new Apriori_test()
//test.genFrequSet1()
//test.genFrequSet2()
test.genFrequSet()
test.genAssociation()
}
Apriori_test(){
database = new HashMap<Integer, Set<String>>()
Set<String> set1 = new HashSet<String>()
set1.add("A")
set1.add("B")
set1.add("C")
set1.add("D")
set1.add("E")
database.put(1, set1)
Set<String> set2 = new HashSet<String>()
set2.add("A")
set2.add("B")
set2.add("F")
database.put(2, set2)
Set<String> set3 = new HashSet<String>()
set3.add("C")
set3.add("D")
set3.add("E")
database.put(3, set3)
Set<String> set4 = new HashSet<String>()
set4.add("B")
set4.add("C")
set4.add("D")
set4.add("E")
set4.add("F")
database.put(4, set4)
Set<String> set5 = new HashSet<String>()
set4.add("C")
set4.add("D")
set4.add("E")
set4.add("F")
database.put(5, set5)
apriori = new Apriori_data(database, minSup, minCon)
}
public void genFrequSet1()
{
//System.out.println(this.database)
System.out.println("频繁项集1-"+apriori.genFrequItemSets1())
}
public void genFrequSet2()
{
System.out.println("频繁项集2-"+apriori.genFrequItemK(1, apriori.genFrequItemSets1()))
}
public void genFrequSet()
{
apriori.miningAllFreque()
System.out.println("频繁项集"+apriori.getFrequentSets())
}
public void genAssociation()
{
apriori.miningAllFreque()
apriori.mineWholeAssociation()
System.out.println("关联规则"+apriori.getAssociationRules())
}
}