java fp-growth 算法包_java实现fp-growth算法

本文参考韩家炜《数据挖掘-概念与技术》一书第六章,前提条件要理解 apriori算法。

另外一篇写得较好的文章在此推荐:

0.实验数据集:

user2items.csv

I1,I2,I5

I2,I4

I2,I3

I1,I2,I4

I1,I3

I2,I3

I1,I3

I1,I2,I3,I5

I1,I2,I3

1.算法原理

构造FPTree

1、首先读取数据库中所有种类的项和这些项的支持度计数。存入到itTotal链表中。

2、将itTotal链表按照支持度计数从大到小排序

3、将itTotal链表插入到ItemTb表中

4、第二便读取数据库中的事务,将事务中的项按照支持度计数由大到小的顺序插入到树中。

5、遍历树,将属于同一项的结点通过bnode指针连接起来。

本程序中,FP-tree中存储了所有的项集,没有考虑最小支持度。只是在FP-growth中挖掘频繁项集时考虑最小支持度

/**

*

* @param records 构建树的记录,如I1,I2,I3

* @param header 韩书中介绍的表头

* @return 返回构建好的树

*/

public TreeNode2 builderFpTree(LinkedList> records,List header){

TreeNode2 root;

if(records.size()<=0){

return null;

}

root=new TreeNode2();

for(LinkedList items:records){

itemsort(items,header);

addNode(root,items,header);

}

String dd="dd";

String test=dd;

return root;

}

//当已经有分枝存在的时候,判断新来的节点是否属于该分枝的某个节点,或全部重合,递归

public TreeNode2 addNode(TreeNode2 root,LinkedList items,List header){

if(items.size()<=0)return null;

String item=items.poll();

//当前节点的孩子节点不包含该节点,那么另外创建一支分支。

TreeNode2 node=root.findChild(item);

if(node==null){

node=new TreeNode2();

node.setName(item);

node.setCount(1);

node.setParent(root);

root.addChild(node);

//加将各个同名的节点加到链头中

for(TreeNode2 head:header){

if(head.getName().equals(item)){

while(head.getNextHomonym()!=null){

head=head.getNextHomonym();

}

head.setNextHomonym(node);

break;

}

}

//加将各个节点加到链头中

}else{

node.setCount(node.getCount()+1);

}

addNode(node,items,header);

return root;

}

FP_growth算法:

从一棵FPTree的ItemTb表中取得第一个项I1。如果该项的支持度计数满足最小支持度计数{

1、把该项I1加入到存储挖掘到的频繁项集的数据结构ItemSet中

2、得到该项I1在目前FPTree中的条件模式基,即该项在树中的结点的前缀路径(路径中不再包括该项)。

注意该项I1的条件模式基中各个项的支持度计数相等,等于该项I1的支持度计数

3、每条路径看作一个事务,用这些路径建造该项的条件FPTree,然后递归调用FP_growth算法。

在递归调用FP_growth算法时,那些大于支持度计数的项作为项I1的孩子结点存储在ItemSet中。

}

本人觉得要想更好的理解,或者有不明之处应该参考

这篇文章的这个地方,见下图。

1912305df8e72f45a50ae149e39fb093.png

public void fpgrowth(LinkedList> records,String item){

//保存新的条件模式基的各个记录,以重新构造FP-tree

LinkedList> newrecords=new LinkedList>();

//构建链头

LinkedList header=buildHeaderLink(records);

//创建FP-Tree

TreeNode2 fptree= builderFpTree(records,header);

//结束递归的条件

if(header.size()<=0||fptree==null){

System.out.println("-----------------");

return;

}

//打印结果,输出频繁项集

if(item!=null){

//寻找条件模式基,从链尾开始

for(int i=header.size()-1;i>=0;i--){

TreeNode2 head=header.get(i);

String itemname=head.getName();

Integer count=0;

while(head.getNextHomonym()!=null){

head=head.getNextHomonym();

//叶子count等于多少,就算多少条记录

count=count+head.getCount();

}

//打印频繁项集

System.out.println(head.getName()+","+item+"\t"+count);

}

}

//寻找条件模式基,从链尾开始

for(int i=header.size()-1;i>=0;i--){

TreeNode2 head=header.get(i);

String itemname;

//再组合

if(item==null){

itemname=head.getName();

}else{

itemname=head.getName()+","+item;

}

while(head.getNextHomonym()!=null){

head=head.getNextHomonym();

//叶子count等于多少,就算多少条记录

Integer count=head.getCount();

for(int n=0;n

LinkedList record=new LinkedList();

toroot(head.getParent(),record);

newrecords.add(record);

}

}

//System.out.println("-----------------");

//递归之,以求子FP-Tree

fpgrowth(newrecords,itemname);

}

}

2.tree的结构

private String name; // 节点名称

private Integer count; // 计数

private TreeNode2 parent; // 父节点

private List children; // 子节点

private TreeNode2 nextHomonym; // 下一个同名节点

详见下面的TreeNode2类

3.完整的源码:

共两份.java文件,直接贴到eclipse中即可以执行。

package mysequence.machineleaning.association.fpgrowth;

import java.io.BufferedReader;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStreamReader;

import java.util.ArrayList;

import java.util.Collections;

import java.util.HashMap;

import java.util.LinkedList;

import java.util.List;

import java.util.Map;

import java.util.Set;

public class Myfptree2 {

public static final int support = 2; // 设定最小支持频次为2

//保存第一次的次序

public Map ordermap=new HashMap();

public LinkedList> readF1() throws IOException {

LinkedList> records=new LinkedList>();

//String filePath="scripts/clustering/canopy/canopy.dat";

String filePath="datafile/association/user2items.csv";

BufferedReader br = new BufferedReader(new InputStreamReader(

new FileInputStream(filePath)));

for (String line = br.readLine(); line != null; line = br.readLine()) {

if(line.length()==0||"".equals(line))continue;

String[] str=line.split(",");

LinkedList litm=new LinkedList();

for(int i=0;i

litm.add(str[i].trim());

}

records.add(litm);

}

br.close();

return records;

}

//创建表头链

public LinkedList buildHeaderLink(LinkedList> records){

LinkedList header=null;

if(records.size()>0){

header=new LinkedList();

}else{

return null;

}

Map map = new HashMap();

for(LinkedList items:records){

for(String item:items){

//如果存在数量增1,不存在则新增

if(map.containsKey(item)){

map.get(item).Sum(1);

}else{

TreeNode2 node=new TreeNode2();

node.setName(item);

node.setCount(1);

map.put(item, node);

}

}

}

// 把支持度大于(或等于)minSup的项加入到F1中

Set names = map.keySet();

for (String name : names) {

TreeNode2 tnode = map.get(name);

if (tnode.getCount() >= support) {

header.add(tnode);

}

}

sort(header);

String test="ddd";

return header;

}

//选择法排序,如果次数相等,则按名字排序,字典顺序,先小写后大写

public List sort(List list){

int len=list.size();

for(int i=0;i

for(int j=i+1;j

TreeNode2 node1=list.get(i);

TreeNode2 node2=list.get(j);

if(node1.getCount()

TreeNode2 tmp=new TreeNode2();

tmp=node2;

list.remove(j);

//list指定位置插入,原来的>=j元素都会往下移,不会删除,所以插入前要删除掉原来的元素

list.add(j,node1);

list.remove(i);

list.add(i,tmp);

}

//如果次数相等,则按名字排序,字典顺序,先小写后大写

if(node1.getCount()==node2.getCount()){

String name1=node1.getName();

String name2=node2.getName();

int flag=name1.compareTo(name2);

if(flag>0){

TreeNode2 tmp=new TreeNode2();

tmp=node2;

list.remove(j);

//list指定位置插入,原来的>=j元素都会往下移,不会删除,所以插入前要删除掉原来的元素

list.add(j,node1);

list.remove(i);

list.add(i,tmp);

}

}

}

}

return list;

}

//选择法排序,降序,如果同名按L 中的次序排序

public List itemsort(LinkedList lis,List header){

//List list=new ArrayList();

//选择法排序

int len=lis.size();

for(int i=0;i

for(int j=i+1;j

String key1=lis.get(i);

String key2=lis.get(j);

Integer value1=findcountByname(key1,header);

if(value1==-1)continue;

Integer value2=findcountByname(key2,header);

if(value2==-1)continue;

if(value1

String tmp=key2;

lis.remove(j);

lis.add(j,key1);

lis.remove(i);

lis.add(i,tmp);

}

if(value1==value2){

int v1=ordermap.get(key1);

int v2=ordermap.get(key2);

if(v1>v2){

String tmp=key2;

lis.remove(j);

lis.add(j,key1);

lis.remove(i);

lis.add(i,tmp);

}

}

}

}

return lis;

}

public Integer findcountByname(String itemname,List header){

Integer count=-1;

for(TreeNode2 node:header){

if(node.getName().equals(itemname)){

count= node.getCount();

}

}

return count;

}

/**

*

* @param records 构建树的记录,如I1,I2,I3

* @param header 韩书中介绍的表头

* @return 返回构建好的树

*/

public TreeNode2 builderFpTree(LinkedList> records,List header){

TreeNode2 root;

if(records.size()<=0){

return null;

}

root=new TreeNode2();

for(LinkedList items:records){

itemsort(items,header);

addNode(root,items,header);

}

String dd="dd";

String test=dd;

return root;

}

//当已经有分枝存在的时候,判断新来的节点是否属于该分枝的某个节点,或全部重合,递归

public TreeNode2 addNode(TreeNode2 root,LinkedList items,List header){

if(items.size()<=0)return null;

String item=items.poll();

//当前节点的孩子节点不包含该节点,那么另外创建一支分支。

TreeNode2 node=root.findChild(item);

if(node==null){

node=new TreeNode2();

node.setName(item);

node.setCount(1);

node.setParent(root);

root.addChild(node);

//加将各个节点加到链头中

for(TreeNode2 head:header){

if(head.getName().equals(item)){

while(head.getNextHomonym()!=null){

head=head.getNextHomonym();

}

head.setNextHomonym(node);

break;

}

}

//加将各个节点加到链头中

}else{

node.setCount(node.getCount()+1);

}

addNode(node,items,header);

return root;

}

//从叶子找到根节点,递归之

public void toroot(TreeNode2 node,LinkedList newrecord){

if(node.getParent()==null)return;

String name=node.getName();

newrecord.add(name);

toroot(node.getParent(),newrecord);

}

//对条件FP-tree树进行组合,以求出频繁项集

public void combineItem(TreeNode2 node,LinkedList newrecord,String Item){

if(node.getParent()==null)return;

String name=node.getName();

newrecord.add(name);

toroot(node.getParent(),newrecord);

}

//fp-growth

public void fpgrowth(LinkedList> records,String item){

//保存新的条件模式基的各个记录,以重新构造FP-tree

LinkedList> newrecords=new LinkedList>();

//构建链头

LinkedList header=buildHeaderLink(records);

//创建FP-Tree

TreeNode2 fptree= builderFpTree(records,header);

//结束递归的条件

if(header.size()<=0||fptree==null){

System.out.println("-----------------");

return;

}

//打印结果,输出频繁项集

if(item!=null){

//寻找条件模式基,从链尾开始

for(int i=header.size()-1;i>=0;i--){

TreeNode2 head=header.get(i);

String itemname=head.getName();

Integer count=0;

while(head.getNextHomonym()!=null){

head=head.getNextHomonym();

//叶子count等于多少,就算多少条记录

count=count+head.getCount();

}

//打印频繁项集

System.out.println(head.getName()+","+item+"\t"+count);

}

}

//寻找条件模式基,从链尾开始

for(int i=header.size()-1;i>=0;i--){

TreeNode2 head=header.get(i);

String itemname;

//再组合

if(item==null){

itemname=head.getName();

}else{

itemname=head.getName()+","+item;

}

while(head.getNextHomonym()!=null){

head=head.getNextHomonym();

//叶子count等于多少,就算多少条记录

Integer count=head.getCount();

for(int n=0;n

LinkedList record=new LinkedList();

toroot(head.getParent(),record);

newrecords.add(record);

}

}

//System.out.println("-----------------");

//递归之,以求子FP-Tree

fpgrowth(newrecords,itemname);

}

}

//保存次序,此步也可以省略,为了减少再加工结果的麻烦而加

public void orderF1(LinkedList orderheader){

for(int i=0;i

TreeNode2 node=orderheader.get(i);

ordermap.put(node.getName(), i);

}

}

public static void main(String[] args) throws IOException {

// TODO Auto-generated method stub

/*String s1="i1";

int flag=s1.compareTo("I1");

System.out.println(flag);*/

//读取数据

Myfptree2 fpg=new Myfptree2();

LinkedList> records=fpg.readF1();

LinkedList orderheader=fpg.buildHeaderLink(records);

fpg.orderF1(orderheader);

fpg.fpgrowth(records,null);

}

}

树的结构:

package mysequence.machineleaning.association.fpgrowth;

import java.util.ArrayList;

import java.util.List;

public class TreeNode2 implements Comparable{

private String name; // 节点名称

private Integer count; // 计数

private TreeNode2 parent; // 父节点

private List children; // 子节点

private TreeNode2 nextHomonym; // 下一个同名节点

public TreeNode2() {

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Integer getCount() {

return count;

}

public void setCount(Integer count) {

this.count = count;

}

public void Sum(Integer count) {

this.count =this.count+count;

}

public TreeNode2 getParent() {

return parent;

}

public void setParent(TreeNode2 parent) {

this.parent = parent;

}

public List getChildren() {

return children;

}

public void setChildren(List children) {

this.children = children;

}

public TreeNode2 getNextHomonym() {

return nextHomonym;

}

public void setNextHomonym(TreeNode2 nextHomonym) {

this.nextHomonym = nextHomonym;

}

/**

* 添加一个节点

* @param child

*/

public void addChild(TreeNode2 child) {

if (this.getChildren() == null) {

List list = new ArrayList();

list.add(child);

this.setChildren(list);

} else {

this.getChildren().add(child);

}

}

/**

* 是否存在着该节点,存在返回该节点,不存在返回空

* @param name

* @return

*/

public TreeNode2 findChild(String name) {

List children = this.getChildren();

if (children != null) {

for (TreeNode2 child : children) {

if (child.getName().equals(name)) {

return child;

}

}

}

return null;

}

@Override

public int compareTo(TreeNode2 arg0) {

// TODO Auto-generated method stub

int count0 = arg0.getCount();

// 跟默认的比较大小相反,导致调用Arrays.sort()时是按降序排列

return count0 - this.count;

}

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值