fp growth java代码_FP-Growth挖掘频繁项,java实现

FP-Growth主要是用来进行挖掘频繁项,使用场景是发现事物之间的相关性,其中用支持度表示相关性的大小,可以通过设置支持度来筛选相关性小的事物的联系。相比较于Apriori算法需要扫描多次数据,严重受到IO的影响。FP-Growth只需要扫描两次数据集,可以提高算法运行效率。下图是论文中的图:

3a5cf686d7cc5171a3dd6784481e8ed8.png

左边表示初始的数据集,表示原始的相关关系。然后遍历左边数据集,统计每个元素的出现次数,然后按照出现次数降序排列。得到中间的表格,设置minSupport = 3,然后删除出现次数小于minSupport的所有元素,然后遍历重构左侧原始元素之间的关系(删除出现次数小于minSupport的所有元素,同时以行为单位按照总出现次数降序重新排列)得到右边数据集(比如左第一行中f出现次数是2 < 3,因此删除f得到新关系[d,a])。(遍历两次,因此扫描了两次数据)。

设置minSupport:

private int minStep = 1;

public int getMinStep() {

return minStep;

}

public void setMinStep(int minStep) {

this.minStep = minStep;

}

然后就是构建一棵FP树,因此需要构建一个节点的结构体,由于使用java实现因此创建了一个FPTreeNode类:

private class FPTreeNode {

int count = 0; //访问次数

int blockAddress = 0;//指的是元素,由于我主要是用来统计blockAddress之间的关系,因此这样取名字

FPTreeNode parent = null;//记录父节点

FPTreeNode nextSimilarNode = null; //记录指向下一个该元素的节点

List childSet = new ArrayList<>();

public FPTreeNode(int blockAddress) {

this.blockAddress = blockAddress;

count = 1;

}

}

构成的图如下图所示(蓝色线指的是:nextSimilarNode,红色线指的是:parent)

2b28aa6ef0eb10cdc1dde33aa3b8a8fb.png

构建上图FP树主要分三步:

1.首先需要遍历数据集,统计元素出现总次数

//计算各基本blockAddress出现的频次。

public List> init(File file) {

List> lists = new ArrayList<>();

try {

BufferedReader bufferedReader = new BufferedReader(new FileReader(file));

String string = "";

double start = -1.0;

List list = new ArrayList<>();

List listCount = new ArrayList<>();

double timePeroid = 60.0;

while((string = bufferedReader.readLine()) != null) {

//time peroid, start block, access count

String[] s = string.split(",");

if (start == -1.0) {

start = Double.valueOf(s[0]) + timePeroid;

}

if (start > Double.valueOf(s[0])) {

if (!list.contains(Integer.valueOf(s[1]))) {

list.add(Integer.valueOf(s[1]));

listCount.add(Integer.valueOf(s[2]));

}

} else {

lists.add(new ArrayList<>(list));

listsCount.add(new ArrayList<>(listCount));

start = Double.valueOf(s[0]) + timePeroid;

list.clear();

listCount.clear();

list.add(Integer.valueOf(s[1]));

listCount.add(Integer.valueOf(s[2]));

}

}

if (list.size() > 0) {

lists.add(new ArrayList<>(list));

listsCount.add(new ArrayList<>(listCount));

}

bufferedReader.close();

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

return lists;

}

2. 根据minSupport进行筛选生成项头表,同时按出现频次降序排列。

public List buildTable(List> lists) {

List trees = new ArrayList(); //获得频繁项表头,删除了小于minSupport的。

if (lists.size() == 0) {

return null;

}

HashMap hashMap = new HashMap<>();

for (int i = 0; i < lists.size(); i++) {

List tmp = lists.get(i);

for (int j = 0; j < tmp.size(); j++) {

int val = tmp.get(j);

if (hashMap.containsKey(val)) {

hashMap.get(val).count++;

} else {

hashMap.put(val, new FPTreeNode(val));

}

}

}

Iterator> iterator = hashMap.entrySet().iterator();

while(iterator.hasNext()) {

Map.Entry entry = iterator.next();

if (entry.getValue().count >= minStep) {

trees.add(entry.getValue());

}

}

//将频繁项进行降序排列

Collections.sort(trees, new Comparator() {

@Override

public int compare(FPTreeNode o1, FPTreeNode o2) {

if (o1.count < o2.count) {

return 1;

} else {

if (o1.count > o2.count) {

return -1;

}

}

return 0;

}

});

return trees;

}

3.通过递归,构建FP树。自底向上。具体流程如下图:(红色箭头表示处理流程,蓝色“阴影” FP树为创建的投影。)

0fc30e74e3952d70e968e84b046e224a.png

/**

* 返回一个降序且满足频繁项的list

* @param list

* @return

*/

public List sortbyTrees(List list, List trees) {

List tmp = new ArrayList<>();//返回一个降序且满足频繁项的list

for (int i = 0; i < trees.size(); i++) {

int block = trees.get(i).blockAddress;

if (list.contains(block)) {

tmp.add(block);

}

}

return tmp;

}

public FPTreeNode findChild(FPTreeNode root, int node) {

for (FPTreeNode treeNode : root.childSet) {

if (treeNode.blockAddress == node) {

return treeNode;

}

}

return null;

}

public void addNode(FPTreeNode node, List list, List trees) {

if (list.size() > 0) {

int val = list.remove(0);

FPTreeNode node1 = new FPTreeNode(val);

node1.parent = node;

node.childSet.add(node1);

for (FPTreeNode treeNode : trees) {

if (treeNode.blockAddress == val) {

while (treeNode.nextSimilarNode != null) {

treeNode = treeNode.nextSimilarNode;

}

treeNode.nextSimilarNode = node1;

break;

}

}

addNode(node1, list, trees);

}

}

public FPTreeNode buildFPTree(List> lists, List trees) {

FPTreeNode root = new FPTreeNode(0);

for (int i = 0; i < lists.size(); i++) {

List tmp = sortbyTrees(lists.get(i), trees);//得到一个降序且满足频繁项的list

FPTreeNode subRoot = root;

FPTreeNode tmpRoot = root;

if (root.childSet.size() > 0) {

while (tmp.size() > 0 && (tmpRoot = findChild(subRoot, tmp.get(0))) != null) {

tmpRoot.count++;

subRoot = tmpRoot;

tmp.remove(0);

}

}

addNode(subRoot, tmp, trees);

}

return root;

}

4.按照FP-Growth算法挖掘频繁项,从底向上。

public void FPGrowth(List> transRecords, List postPattern) {

List trees = buildTable(transRecords);// 构建项头表,同时也是频繁1项集

// 构建FP-Tree

FPTreeNode root1 = buildFPTree(transRecords, trees);

if (root1.childSet.size() == 0) {

return;

}

if (postPattern.size() > 0) {

for (FPTreeNode node : trees) {

System.out.print(node.count + ":" + node.blockAddress);

for (int val: postPattern) {

System.out.print(" " + val);

}

System.out.println();

}

}

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

FPTreeNode node = trees.get(i);

List tmp = new ArrayList<>();

tmp.add(node.blockAddress);

if (postPattern.size() > 0) {

tmp.addAll(postPattern);

}

// 寻找header的条件模式基,放入records中

List> records = new ArrayList<>();

FPTreeNode nextNode = node.nextSimilarNode;

while (nextNode != null) {

int cnt = nextNode.count;

List prenodes = new ArrayList();

FPTreeNode parent = nextNode;

while ((parent = parent.parent) != null && parent.blockAddress != 0) {

prenodes.add(parent.blockAddress);

}

while (cnt > 0) {

cnt--;

records.add(prenodes);

}

nextNode = nextNode.nextSimilarNode;

}

FPGrowth(records, tmp);

}

}

亲测是正确的,数据集格式是:(主要是为了判断第二列之间的相关性,按照第一列表示秒,每180s所包含第二列元素表示为一个关系序列)

60,2104409088,1486

120,2104409088,667

120,2104410112,783

180,2104410112,1467

240,2104410112,1152

240,2104411136,301

300,2104411136,1447

360,2104411136,1429

420,2104411136,225

420,2104412160,1209

480,2104412160,1470

540,2104412160,722

540,2104413184,715

600,2104413184,1455

生成关系序列为:

[[2104409088, 2104410112], [2104410112, 2104411136], [2104411136, 2104412160, 2104413184], [2104413184]]

最后得到的频繁项为:(由于数据量小,频繁项表现不明显)

1:2104413184 2104412160

1:2104411136 2104412160

1:2104413184 2104411136 2104412160

1:2104410112 2104409088

1:2104411136 2104413184

1:2104410112 2104411136

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值