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

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

http://hi.baidu.com/nefzpohtpndhovr/item/9d5c371ba2dbdc0ed1d66dca

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<LinkedList<String>> records,List<TreeNode2> header){ TreeNode2 root;
if(records.size()<=){
return null;
}
root=new TreeNode2();
for(LinkedList<String> items:records){
itemsort(items,header);
addNode(root,items,header);
}
String dd="dd";
String test=dd;
return root;
}
//当已经有分枝存在的时候,判断新来的节点是否属于该分枝的某个节点,或全部重合,递归
public TreeNode2 addNode(TreeNode2 root,LinkedList<String> items,List<TreeNode2> header){
if(items.size()<=)return null;
String item=items.poll();
//当前节点的孩子节点不包含该节点,那么另外创建一支分支。
TreeNode2 node=root.findChild(item);
if(node==null){
node=new TreeNode2();
node.setName(item);
node.setCount();
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()+);
} 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中。
   }
本人觉得要想更好的理解,或者有不明之处应该参考
这篇文章的这个地方,见下图。

public void fpgrowth(LinkedList<LinkedList<String>> records,String item){
//保存新的条件模式基的各个记录,以重新构造FP-tree
LinkedList<LinkedList<String>> newrecords=new LinkedList<LinkedList<String>>();
//构建链头
LinkedList<TreeNode2> header=buildHeaderLink(records);
//创建FP-Tree
TreeNode2 fptree= builderFpTree(records,header);
//结束递归的条件
if(header.size()<=||fptree==null){
System.out.println("-----------------");
return;
}
//打印结果,输出频繁项集
if(item!=null){
//寻找条件模式基,从链尾开始
for(int i=header.size()-;i>=;i--){
TreeNode2 head=header.get(i);
String itemname=head.getName();
Integer count=;
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()-;i>=;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=;n<count;n++){
LinkedList<String> record=new LinkedList<String>();
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<TreeNode2> 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
//保存第一次的次序
public Map<String,Integer> ordermap=new HashMap<String,Integer>();
public LinkedList<LinkedList<String>> readF1() throws IOException {
LinkedList<LinkedList<String>> records=new LinkedList<LinkedList<String>>();
//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()==||"".equals(line))continue;
String[] str=line.split(",");
LinkedList<String> litm=new LinkedList<String>();
for(int i=;i<str.length;i++){
litm.add(str[i].trim());
}
records.add(litm);
}
br.close();
return records;
}
//创建表头链
public LinkedList<TreeNode2> buildHeaderLink(LinkedList<LinkedList<String>> records){
LinkedList<TreeNode2> header=null;
if(records.size()>){
header=new LinkedList<TreeNode2>();
}else{
return null;
}
Map<String, TreeNode2> map = new HashMap<String, TreeNode2>();
for(LinkedList<String> items:records){ for(String item:items){
//如果存在数量增1,不存在则新增
if(map.containsKey(item)){
map.get(item).Sum();
}else{
TreeNode2 node=new TreeNode2();
node.setName(item);
node.setCount();
map.put(item, node);
}
}
}
// 把支持度大于(或等于)minSup的项加入到F1中
Set<String> 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<TreeNode2> sort(List<TreeNode2> list){
int len=list.size();
for(int i=;i<len;i++){ for(int j=i+;j<len;j++){
TreeNode2 node1=list.get(i);
TreeNode2 node2=list.get(j);
if(node1.getCount()<node2.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>){
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<String> itemsort(LinkedList<String> lis,List<TreeNode2> header){
//List<String> list=new ArrayList<String>();
//选择法排序
int len=lis.size();
for(int i=;i<len;i++){
for(int j=i+;j<len;j++){
String key1=lis.get(i);
String key2=lis.get(j);
Integer value1=findcountByname(key1,header);
if(value1==-)continue;
Integer value2=findcountByname(key2,header);
if(value2==-)continue;
if(value1<value2){
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<TreeNode2> header){
Integer count=-;
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<LinkedList<String>> records,List<TreeNode2> header){ TreeNode2 root;
if(records.size()<=){
return null;
}
root=new TreeNode2();
for(LinkedList<String> items:records){
itemsort(items,header);
addNode(root,items,header);
}
String dd="dd";
String test=dd;
return root;
}
//当已经有分枝存在的时候,判断新来的节点是否属于该分枝的某个节点,或全部重合,递归
public TreeNode2 addNode(TreeNode2 root,LinkedList<String> items,List<TreeNode2> header){
if(items.size()<=)return null;
String item=items.poll();
//当前节点的孩子节点不包含该节点,那么另外创建一支分支。
TreeNode2 node=root.findChild(item);
if(node==null){
node=new TreeNode2();
node.setName(item);
node.setCount();
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()+);
} addNode(node,items,header);
return root;
}
//从叶子找到根节点,递归之
public void toroot(TreeNode2 node,LinkedList<String> 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<String> 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<LinkedList<String>> records,String item){
//保存新的条件模式基的各个记录,以重新构造FP-tree
LinkedList<LinkedList<String>> newrecords=new LinkedList<LinkedList<String>>();
//构建链头
LinkedList<TreeNode2> header=buildHeaderLink(records);
//创建FP-Tree
TreeNode2 fptree= builderFpTree(records,header);
//结束递归的条件
if(header.size()<=||fptree==null){
System.out.println("-----------------");
return;
}
//打印结果,输出频繁项集
if(item!=null){
//寻找条件模式基,从链尾开始
for(int i=header.size()-;i>=;i--){
TreeNode2 head=header.get(i);
String itemname=head.getName();
Integer count=;
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()-;i>=;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=;n<count;n++){
LinkedList<String> record=new LinkedList<String>();
toroot(head.getParent(),record);
newrecords.add(record);
}
}
//System.out.println("-----------------");
//递归之,以求子FP-Tree
fpgrowth(newrecords,itemname);
}
}
//保存次序,此步也可以省略,为了减少再加工结果的麻烦而加
public void orderF1(LinkedList<TreeNode2> orderheader){
for(int i=;i<orderheader.size();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<LinkedList<String>> records=fpg.readF1();
LinkedList<TreeNode2> 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<TreeNode2>{ private String name; // 节点名称
private Integer count; // 计数
private TreeNode2 parent; // 父节点
private List<TreeNode2> 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<TreeNode2> getChildren() {
return children;
} public void setChildren(List<TreeNode2> 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<TreeNode2> list = new ArrayList<TreeNode2>();
list.add(child);
this.setChildren(list);
} else {
this.getChildren().add(child);
}
}
/**
* 是否存在着该节点,存在返回该节点,不存在返回空
* @param name
* @return
*/
public TreeNode2 findChild(String name) {
List<TreeNode2> 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;
}
}
 

java实现fp-growth算法的更多相关文章

  1. FP—Growth算法

    FP_growth算法是韩家炜老师在2000年提出的关联分析算法,该算法和Apriori算法最大的不同有两点: 第一,不产生候选集,第二,只需要两次遍历数据库,大大提高了效率,用31646条测试记录, ...

  2. Frequent Pattern 挖掘之二(FP Growth算法)(转)

    FP树构造 FP Growth算法利用了巧妙的数据结构,大大降低了Aproir挖掘算法的代价,他不需要不断得生成候选项目队列和不断得扫描整个数据库进行比对.为了达到这样的效果,它采用了一种简洁的数据结 ...

  3. 关联规则算法之FP growth算法

    FP树构造 FP Growth算法利用了巧妙的数据结构,大大降低了Aproir挖掘算法的代价,他不需要不断得生成候选项目队列和不断得扫描整个数据库进行比对.为了达到这样的效果,它采用了一种简洁的数据结 ...

  4. Frequent Pattern (FP Growth算法)

    FP树构造 FP Growth算法利用了巧妙的数据结构,大大降低了Aproir挖掘算法的代价,他不需要不断得生成候选项目队列和不断得扫描整个数据库进行比对.为了达 到这样的效果,它采用了一种简洁的数据 ...

  5. 机器学习(十五)— Apriori算法、FP Growth算法

    1.Apriori算法 Apriori算法是常用的用于挖掘出数据关联规则的算法,它用来找出数据值中频繁出现的数据集合,找出这些集合的模式有助于我们做一些决策. Apriori算法采用了迭代的方法,先搜 ...

  6. Frequent Pattern 挖掘之二(FP Growth算法)

    Frequent Pattern 挖掘之二(FP Growth算法) FP树构造 FP Growth算法利用了巧妙的数据结构,大大降低了Aproir挖掘算法的代价,他不需要不断得生成候选项目队列和不断 ...

  7. FP Tree算法原理总结

    在Apriori算法原理总结中,我们对Apriori算法的原理做了总结.作为一个挖掘频繁项集的算法,Apriori算法需要多次扫描数据,I/O是很大的瓶颈.为了解决这个问题,FP Tree算法(也称F ...

  8. FP Tree算法原理总结(转载)

    FP Tree算法原理总结 在Apriori算法原理总结中,我们对Apriori算法的原理做了总结.作为一个挖掘频繁项集的算法,Apriori算法需要多次扫描数据,I/O是很大的瓶颈.为了解决这个问题 ...

  9. FP - growth 发现频繁项集

    FP - growth是一种比Apriori更高效的发现频繁项集的方法.FP是frequent pattern的简称,即常在一块儿出现的元素项的集合的模型.通过将数据集存储在一个特定的FP树上,然后发 ...

  10. Java中的经典算法之冒泡排序(Bubble Sort)

    Java中的经典算法之冒泡排序(Bubble Sort) 神话丿小王子的博客主页 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一 ...

随机推荐

  1. _GET_

    _GET_:读取属性,没有自动创建

  2. Debian 采用 iso 镜像作为 apt 源

    1.将N个debian-506-amd64-DVD-N.iso存放于本地或其他媒介内,本例是放在本机/iso/目录下2.创建N个挂载点目录 如下: debian:~#mkdir –r /media/d ...

  3. MVC--SSM和SSH简介

  4. SEO方式之HTTPS 访问优化详解

    SEO到底要不要做HTTPS?HTTPS对SEO的重要性 正方观点 1.HTTPS具有更好的加密性能,避免用户信息泄露: 2.HTTPS复杂的传输方式,降低网站被劫持的风险: 3.搜索引擎已经全面支持 ...

  5. Django入门与实践 1-16章总结

    注意事项:随时备份.随时记录.从宏观到微观 不闻不若闻之,闻之不若见之,见之不若知之,知之不若行之:学至于行之止矣 安装 Python 3.6.2 pip install django==1.11.4 ...

  6. win10 新增删除文件不刷新

    实际上是桌面图标缓存出问题,以下是一个简单动作即可解决问题. 按Win+R键打开“运行”窗口,输入如下命令后按回车键执行: ie4uinit -show 立竿见影,效果同360,魔方等工具软件,可参考 ...

  7. spring3 hibernate4整合后无法查询数据库

    spring3和hibernate4整合后无法查询数据库,一方面是因为已经spring3中没有对hibernate4 HibernateTemplate的支持,另外一个就是需要在hibernate的配 ...

  8. 20、docker swarm

      Swarm是Docker官方提供的一款集群管理工具,其主要作用是把若干台Docker主机抽象为一个整体,并且通过一个入口统一管理这些Docker主机上的各种Docker资源.Swarm和Kuber ...

  9. java web前端easyui(layout+tree+双tabs)布局+树+2个选项卡tabs

    1.列出要实现的样式: 2.实现的代码: 分三大部分: 1):页面主体部分:mian.vm <html> <head> <title>Ks UI</title ...

  10. Hibernate与Jpa的关系

    JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中. JPA的总体思想和现有Hibernate.T ...