DataMining-FP-Growth算法Java实现

FPTreeApplication类

java 复制代码
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.*;
import java.util.stream.Collectors;

public class FPTreeApplication {
    /**
     * 数据源
     */
    private static final String FILE_PATH = "E:\\UniCourses\\buct\\juniorI\\DataMining\\retail.txt";
    /**
     * 数据项分隔符
     */
    private static final String SEPARATOR = " ";
    /**
     * 最小支持度
     */
    private double minSupport;
    /**
     * 最小支持度项数
     */
    private int minSupportItem;

    /**
     * 结果, Key为项集数,Value为频繁n项集
     */
    private static final Map<Integer,List<List<String>>> resultMap = new HashMap<>();

    public FPTreeApplication(double minSupport){
        this.minSupport = minSupport;
    }
    public Map<Integer,List<List<String>>> getResultMap(){
        return resultMap;
    }
    /**
     * 读取源数据
     * @return
     */
    public List<List<String>> readSrcData(){
        List<List<String>> srcData = new ArrayList<>();
        try(
                FileInputStream fileInputStream = new FileInputStream(FILE_PATH);
                InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

        ){
            String dataLine;
            while((dataLine=bufferedReader.readLine())!=null){
                List<String> itemList = new ArrayList<>(Arrays.asList(dataLine.split(SEPARATOR)));
                srcData.add(itemList);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        // 得到最小支持度项数
        minSupportItem = (int)(minSupport*srcData.size());
        return srcData;
    }

    /**
     * 构建头表
     * @param itemListList
     * @return
     */
    public List<FPTreeNode> buildHeadTableList(List<List<String>> itemListList){
        // 统计所有项出现次数
        Map<String,Integer> itemCountMap = new HashMap<>();
        for (List<String> itemList : itemListList) {

            for (String item : itemList) {
                if(itemCountMap.containsKey(item)){
                    itemCountMap.put(item,itemCountMap.get(item)+1);
                }else{
                    itemCountMap.put(item,1);
                }
            }
        }
        // 统计频繁项
        List<FPTreeNode> frequentItemList = new ArrayList<>();
        for(Map.Entry<String,Integer> entry:itemCountMap.entrySet()){
            if(entry.getValue()>= minSupportItem){
                frequentItemList.add(new FPTreeNode(entry.getKey(),entry.getValue()));
            }
        }
        // 对频繁项降序排序
        Collections.sort(frequentItemList);
        return frequentItemList;
    }

    /**
     * 构建FPTree
     * @param headTableList
     * @param itemListList
     * @return
     */
    public FPTreeNode buildFPTree(List<FPTreeNode> headTableList,List<List<String>> itemListList){
        List<List<String>> frequentItemListList = new ArrayList<>();
        // 筛选出每行数据的频繁项
        for (List<String> itemList : itemListList) {
            List<String> frequentItemList = new ArrayList<>();
            for (FPTreeNode fpTreeNode : headTableList) {
                if(itemList.contains(fpTreeNode.getData())){
                    frequentItemList.add(fpTreeNode.getData());
                }
            }
            frequentItemListList.add(frequentItemList);
        }
        FPTreeNode root = new FPTreeNode();
        // 对每行数据的频繁项去构造一颗子树
        for (List<String> frequentItemList : frequentItemListList) {
            buildSonFPTree(root,headTableList,frequentItemList);
        }
        return root;
    }

    /**
     * 为每行数据的频繁项构造一颗子树
     * @param rootNode 根节点
     * @param headTableList 头表
     * @param frequentItemList 每一行数据的频繁项集(按头表序)
     */
    public void buildSonFPTree(FPTreeNode rootNode,List<FPTreeNode> headTableList,List<String> frequentItemList){
        FPTreeNode tempNode = rootNode;
        for (String frequentItem : frequentItemList) {
            List<FPTreeNode> sonNodeList = tempNode.getSonNodeList();
            // 当前节点没有子节点
            if(null==sonNodeList || sonNodeList.isEmpty()){
                tempNode.setSonNodeList(new ArrayList<>());
                FPTreeNode sonNode = new FPTreeNode(frequentItem,1);
                sonNode.setParentNode(tempNode);
                tempNode.getSonNodeList().add(sonNode);
                // 链接头表
                linkNode(headTableList,sonNode);
                // 移动当前节点,准备插入下一个项
                tempNode = sonNode;
                continue;
            }
            // 当前节点的子节点包含目标项
            boolean existItem = false;
            for (FPTreeNode sonNode : sonNodeList) {
                if(sonNode.getData().equals(frequentItem)){
                    existItem = true;
                    // 累加该子节点的count值
                    sonNode.setCount(sonNode.getCount()+1);
                    // 移动当前节点,准备插入下一个项
                    tempNode = sonNode;
                    break;
                }
            }
            // 当前节点的子节点不包含目标项
            if(!existItem){
                FPTreeNode sonNode = new FPTreeNode(frequentItem,1);
                sonNode.setParentNode(tempNode);
                // 将目标项插入当前节点的子节点
                tempNode.getSonNodeList().add(sonNode);
                // 链接头表
                linkNode(headTableList,sonNode);
                // 移动当前节点,准备插入下一个项
                tempNode = sonNode;
            }
        }
    }

    /**
     * 对新插入FPTree的节点进行与头表或同名节点的链接
     * @param headTableList
     * @param newNode
     */
    public void linkNode(List<FPTreeNode> headTableList,FPTreeNode newNode){
        for (FPTreeNode headNode : headTableList) {
            if(headNode.getData().equals(newNode.getData())){
                // 如果头节点尚未链接任何节点
                if(headNode.getNextNode()==null){
                    headNode.setNextNode(newNode);
                }else{
                    // 如果头节点已经链接过同名节点,则将新节点链接到同名节点尾部
                    FPTreeNode tempNode = headNode;
                    while(tempNode.getNextNode()!=null){
                        tempNode = tempNode.getNextNode();
                    }
                    tempNode.setNextNode(newNode);
                }
            }
        }
    }
    /**
     * 总执行函数
     * @param srcData 待分析数据
     * @param postItem 当前的后缀项
     */
    public void FPGrow(List<List<String>> srcData,List<String> postItem){

        // 根据数据源构建头表
        List<FPTreeNode> headTableList = buildHeadTableList(srcData);
        // 若头表为空,则结束递归
        if(headTableList.isEmpty()){
            return;
        }

        // 如果当前后缀项为null,说明此时的头表就是所有的频繁一项集,加入最终结果
        if(null==postItem){
            List<List<String>> itemListList = new ArrayList<>();
            for (FPTreeNode headNode : headTableList) {
                List<String> itemList = new ArrayList<>();
                itemList.add(headNode.getData());
                itemListList.add(itemList);
            }
            resultMap.put(1,itemListList);
        }else{
            /**
             * 如果当前后缀项不为null,说明已经进入递归
             * 递归时,所谓的头表其实是后缀项的头表
             * 而头表的构建过程,保证了头表的每个头节点值都是频繁项
             * 因此,若后缀项有k项,则此时头表的每一项都能分别与后缀项组成新的频繁(k+1)项集
             */
            Integer itemNum = postItem.size()+1;
            List<List<String>> newListList = new ArrayList<>();
            for (FPTreeNode headNode : headTableList) {
                List<String> newList = new ArrayList<>();
                newList.add(headNode.getData());
                newList.addAll(postItem);
                newListList.add(newList);
            }
            // 加入最终结果
            List<List<String>> originListList = resultMap.get(itemNum);
            if(originListList == null){
                resultMap.put(itemNum,newListList);
            }else{
                originListList.addAll(newListList);
            }
        }

        // 根据头表构建FPTree
        FPTreeNode rootNode = buildFPTree(headTableList, srcData);

        // 对头表每个头节点,得到其所有同值节点的条件模式库,进入递归
        for (FPTreeNode headNode : headTableList) {

            // 当前的条件模式库,是 当前头节点+原后缀=新后缀 的条件模式库
            List<String> newPostItem = new ArrayList<>();
            newPostItem.add(headNode.getData());
            if(null!=postItem){
                newPostItem.addAll(postItem);
            }
            List<List<String>> conditionalPatternBase = new ArrayList<>();

            FPTreeNode bottomNode = headNode.getNextNode();
            // 遍历当前头节点的所有同值节点
            while(null!=bottomNode){
                // 当前条件模式的计数值,为底节点计数值
                int count = bottomNode.getCount();
                LinkedList<String> conditionalPattern = new LinkedList<>();
                FPTreeNode tempNode = bottomNode.getParentNode();
                while(tempNode != (rootNode)) {
                    conditionalPattern.addFirst(tempNode.getData());
                    tempNode = tempNode.getParentNode();
                }
                // 对计数值>1且不为空的条件模式,重复入库
                while(count>0 && !conditionalPattern.isEmpty()){
                    conditionalPatternBase.add(conditionalPattern);
                    count--;
                }
                // 继续查找下一个同值节点
                bottomNode = bottomNode.getNextNode();
            }

            // 带着新后缀与新条件模式库进入递归
            FPGrow(conditionalPatternBase,newPostItem);
        }
    }

    public static void main(String[] args) {
        FPTreeApplication fpTreeApplication = new FPTreeApplication(0.01);
        long start = System.currentTimeMillis();
        // 读取数据集
        List<List<String>> srcData = fpTreeApplication.readSrcData();
        // 执行,初始后缀项为null
        fpTreeApplication.FPGrow(srcData,null);
        // 输出结果
        Map<Integer, List<List<String>>> resultMap = fpTreeApplication.getResultMap();
        for(Map.Entry<Integer,List<List<String>>> entry:resultMap.entrySet()){
            System.out.println("------频繁"+entry.getKey()+"项集------");
            for (List<String> itemList : entry.getValue()) {
                System.out.println(itemList);
            }
            System.out.println("共"+entry.getValue().size()+"个");
        }
        long end = System.currentTimeMillis();
        System.out.println("共耗时"+(end-start)+"ms");
    }
}

FPTreeNode类

java 复制代码
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * 树节点
 */
@Data
@NoArgsConstructor
public class FPTreeNode implements Comparable<FPTreeNode>{
    /**
     * 节点值
     */
    private String data;
    /**
     * 节点值计数
     */
    private Integer count;
    /**
     * 父节点
     */
    private FPTreeNode parentNode;
    /**
     * 下一个同值节点
     */
    private FPTreeNode nextNode;
    /**
     * 子节点
     */
    private List<FPTreeNode> sonNodeList;

    public FPTreeNode(String data,Integer count){
        this.data = data;
        this.count = count;
    }

    @Override
    public String toString() {
        return "FPTreeNode{" +
                "data='" + data + '\'' +
                ", count=" + count +
                '}';
    }

    /**
     * 按出现次数降序排序
     * @param node the object to be compared.
     * @return
     */
    public int compareTo(FPTreeNode node){
        return node.count-count;
    }
}
相关推荐
Ni-Guvara几秒前
函数对象笔记
c++·算法
WaaTong16 分钟前
《重学Java设计模式》之 原型模式
java·设计模式·原型模式
m0_7430484416 分钟前
初识Java EE和Spring Boot
java·java-ee
AskHarries18 分钟前
Java字节码增强库ByteBuddy
java·后端
泉崎24 分钟前
11.7比赛总结
数据结构·算法
你好helloworld26 分钟前
滑动窗口最大值
数据结构·算法·leetcode
小灰灰__38 分钟前
IDEA加载通义灵码插件及使用指南
java·ide·intellij-idea
零意@39 分钟前
ubuntu切换不同版本的python
windows·python·ubuntu
夜雨翦春韭42 分钟前
Java中的动态代理
java·开发语言·aop·动态代理
程序媛小果1 小时前
基于java+SpringBoot+Vue的宠物咖啡馆平台设计与实现
java·vue.js·spring boot