FP-growth 算法- 机器学习

前言:

       上面Apiori 频繁集里面,在训练的时候,每次调用ScanD,就需要遍历整个数据集。

如果数据集特别庞大,训练的速度会很慢。

      FP-growth 是一种速度更快的发现频繁集的算法,完成相同的任务采用不同的算法。

      应用: 挖掘常用词,从另一个网民网页浏览行为挖掘常见模式

      FP:(Frequent Pattern): 频繁模式

 

目录

  1.         简介
  2.         FP树构建
  3.         频繁项挖掘
  4.         代码实现

一  简介

      Fp-growth 只会扫描数据集两次,发现频繁集流程如下:

       1.1 构建FP 树

       1.2  抽取条件模式基

        1.3  根据条件模式基挖掘频繁项

 

      一个元素可以在FP中多次出现,FP树会存储项集的出现频率,

      每个项集回忆路径方式存储在树中

      相似项之间的连接(同一个频繁项): 节点链接,用于快速发现相似项

 


二  FP树构建

   

           2.1   第一遍 对所有的元素项出现的频率,去掉不满足最小支持度的选项。

                 原理同Aprior

                   

事务ID事件元素过滤后的事务
001r,z,h,j,pz,r
002z,y,x,w,v,u,t,sz,x,y.s,t
003zz
004r,x,n,o,sx,s,r
005y,r,x,z,q,t,pz,x,y.r,t
006y,z,x,e,q,s,t,mz,x,y,s,t
   

 

 

                  第二遍  只考虑过滤后的频繁集元素

                           从空集\phi开始,不断添加频繁集选项,如果树中已经存在现有元素,则增加现有元素的值

                      如果元素不存在,则向树添加一个分支。

                    


         例子:

   

       第一次遍历: 生成headerTable以及retTree

       headerTable: 生成头指针表,【count, 指针链表】

freqSetCount指针链表
r3None 
z5None
t3None
y3None
s3None
x4None

 

 

 

 

 

 

 

 

     retTree树: 一颗空树

  

  第二次遍历

        

         1  遍历数据项: ['r','z','h','j','p']

    

             获取频繁集                  localD  {'r': 3, 'z': 5}

              支持度排序                 curItems  ['z', 'r']

            生成一个按照当前分支生成一个tree,并且更新头指针表里面的指针headerTable

          

        2  遍历数据项 ['z','x','y','w','v','u','t','s'],

               

                 频繁集: localD  {'z': 5, 't': 3, 'y': 3, 's': 3, 'x': 4}

                 按支持度排序

      curItems  ['z', 'x', 't', 'y', 's']

  3 数据集 ['z']

                     

                    频繁度  localD  {'z': 5}

                    支持度排序   curItems  ['z']

                    

  4: 数据集  ['r','x','n','o','s']

         

            频繁集:  localD  {'r': 3, 's': 3, 'x': 4}

             排序:   curItems  ['x', 'r', 's']

            

    5: 数据集['y','r','x','z','q','t','p'],

         

              localD  {'r': 3, 'z': 5, 't': 3, 'y': 3, 'x': 4}

              curItems  ['z', 'x', 'r', 't', 'y']

             

   6 数据集 ['y','z','x','e','q','s','t','m']]

    

      localD  {'z': 5, 't': 3, 'y': 3, 's': 3, 'x': 4}

        curItems  ['z', 'x', 't', 'y', 's']

       


三: 频繁项挖掘

        主要分为3个步骤:

        3.1    从FP树中获得条件模式基

        3.2    利用条件模式基作为数据集,构建一个条件FP树

        3.3     迭代重复步骤1 步骤2 ,直到树包含一个元素项为止 

 

        A 抽取条件模式基:

          从头指针表中的单个频繁项元素开始

                     获取对应的条件模式基: 以查找元素项为结尾的路径集合。每个路径都是一条前缀路径(prefix path)

           一条前缀路径是介于所查找元素项与树根节点之间的所有内容[路径是前面nodeLink 头指针表保存的路径]

                    

头指针表中频繁项前缀路径
z{}: 5
r{x,s}1,{z,x,y}1,{z}1
x{z}3,{}1
y{z,x}3
s{z,x,y}2,{x}1
t: 3{z,x,y,s}2,{z,x,y,r}1

       

      B: 创建条件FP树

                       根据头指针表中,对应的条件模式基

                         

 

             

分析:

    step1 频繁项:r,其条件模式基如下:

    

   由条件模式基创建的头指针列表如下

   

   当minSup=3 时,此刻myHead  is None ,freqItemList [{'r'},]

 

  step2  频繁项t:  条件模式基

    

      头指针表如下:

     

     此刻频繁列表为: freqItemList [{'r'}, {'t'}], 因为头指针表不为空,递归建立MineTree

 

先递归到Z:

    freqItemList 变成 [{'r'}, {'t'} ,{t,z}]

    因为  Z的prePath is None ,所以继续下一个X

    

 

     此刻频繁集为:

freqItemList [{'r'}, {'t'}, {'t', 'z'}, {'t', 'x'}]

 

   递归preFix 为{'t', 'x'}  的MinTree

    freqItemList [{'r'}, {'t'}, {'t', 'z'}, {'t', 'x'}, {'t', 'z', 'x'}]

     

依次不断的递归头指针表中的频繁项

 

四 代码实现:

    

# -*- coding: utf-8 -*-
"""
Created on Tue Dec 24 10:47:11 2019

@author: chengxf2
"""

import numpy as np


class treeNode():
    
    def __init__(self, name, count, parentNode):
        self.name = name
        self.count = count
        self.nodeLink = None
        self.parent = parentNode
        self.children ={}
    
    """
    增加节点计数
    Args
      num: 当前的数量
    return
       None
    """
    def Inc(self, num):
        self.count +=num
        
    """
    显示树
    Args
       Id: 标签
    return 
       None
    
    """
    def Disp(self, Id=1):
        #print("   "*Id, self.name, ":",self.count)
        for child in self.children.values():
            child.Disp(Id+1)
"""
加载数据集
Args
   None
return
   dataSet: tran: 交易, count
"""
def LoadDataSet():
    dataList = [['r','z','h','j','p'],
                ['z','x','y','w','v','u','t','s'],
                ['z'],
                ['r','x','n','o','s'],
                ['y','r','x','z','q','t','p'],
                ['y','z','x','e','q','s','t','m']]
    

    
    dataSet ={}
    for trans in dataList:
        dataSet[frozenset(trans)]=1
    return dataSet

"""
生成Tree
Args
   dataSet: 生成数据集
   minSup: 最小支持度
return
    retTree: 树结构
    headerTable: 头指针表
"""
def FpTree(dataSet, minSup):
    headerTable = {}
    
    #print("\n ************第1次遍历整个数据集*****************\n")
    
    ###获得支持度
    for trans in dataSet:
        for item in trans:
           headerTable [item]= headerTable.get(item, 0)+dataSet[trans]
   

    ##去掉低支持度的选项
    keys = list(headerTable.keys())
    for key in keys:
        if headerTable[key]<minSup :
            headerTable.pop(key)
            

    ###获得频繁集
    freqSet = set(headerTable.keys())
   
    if 0 == len(freqSet):
        return None , None
    
    for key in headerTable : ##首先置空
        headerTable[key] =[headerTable[key], None]
        
        
    #print("\n headerTable",headerTable)
   # print("\n ************第2次遍历整个数据集*****************\n")
    retTree = treeNode("Root",1,None) ##创建树
    
    for tranSet, count in dataSet.items():  ##第二次遍历整个数据集,开始默认是1
        localD ={}
        #print("\n tranSet ",tranSet)
        for item in tranSet:
            if item in freqSet: ##如果是频繁集
                localD[item]=headerTable[item][0]  ##返回分支 指针
       # print("\n localD ",localD)   
        if len(localD)>0:
            curItems = [v[0] for v in sorted(localD.items(), key = lambda p:p[1], reverse= True)]  ##排序,从大到小
           # print("\n curItems ",curItems)   
            updateTree(curItems, retTree,   headerTable,   count)#将排序后的item集合填充的树中
        #print("\n ====================\n")
        #retTree.Disp()
        #print("\n headerTable",headerTable)
    return retTree, headerTable  

"""
FP生长
Args
   items: 项集
   inTree: 当前的Tree: 
   headerTable: 头指针表
   count: 计数
   
"""
def updateTree(items, inTree, headerTable, count):
    
   # print("items[0] ",items[0])
    node = items[0]
    if node in inTree.children: ##第一个元素是否是子节点,增加计数
        
        inTree.children[items[0]].Inc(count)
    else:  ##创建一个新的节点,加入到 头指针表中
        inTree.children[node]= treeNode(node, count, inTree)  ##生成一个节点
        if headerTable[node][1] == None: ##更新头指针   
            headerTable[node][1] = inTree.children[node]
        else:  ##
            updateHeader(headerTable[node][1], inTree.children[node])
            
    if len(items)>1: ##删掉表中第一个元素
        updateTree(items[1::], inTree.children[node],headerTable, count)

"""
链表链接指向书中该元素的每一个实例
延着链表开始,一直到达链表结尾
Args
  nodeLink:
  targetNode: 
"""
def updateHeader(node, targetNode):
  
    while (not node.nodeLink is  None):
             node = node.nodeLink
             
    node.nodeLink = targetNode
    
    
"""
向上回溯整个树到根节点
Args
  leafNode:当前节点
   path:当前的路径
return
    None
"""
def AscendTree(leafNode, path):
    
    if leafNode.parent is not None:
        path.append(leafNode.name)
        AscendTree(leafNode.parent, path)
        
"""

"""
def FindPrefixPath(key, headerTable):
    
    treeNode = headerTable[key][1]
    
    condParent ={}
    
    while treeNode is not None:
        path = []
        AscendTree(treeNode, path)
        
        if len(path)>1:
            condParent[frozenset(path[1:])]= treeNode.count
        treeNode = treeNode.nodeLink
    return condParent
        
def MinTree( headerTable, minSup, preSet, freqItemList):
    
    KeySort = [v[0] for v in sorted(headerTable.items(), key=lambda p:p[1][0])] # 根据频繁项的count 从小到大排序
    #print("bigL ",bigL)
    
    for key in KeySort:
        newFreqSet = preSet.copy()
        newFreqSet.add(key)
        
        freqItemList.append(newFreqSet)
        conBase = FindPrefixPath(key,headerTable)  ##获取条件模式基
        
        myCondTree, myHead = FpTree(conBase,minSup) ##把条件模式基当作样本,建立FP树
        
        if myHead is not None:
            MinTree( myHead, minSup, newFreqSet, freqItemList) ##递归挖掘FP树

def FP():
    
    ##先构建FP树
    print("\n **********构建FP树结束****************\n")
    dataSet =LoadDataSet()
    retTree, headerTable =FpTree(dataSet,3)
    """
    print("\n **********抽取条件模式基****************\n")
    for key in headerTable:
      
        condParent= FindPrefixPath(key ,headerTable)
        print("\n key: ",key,"\t conParent: ",condParent)
        
    print("\n **********创建条件FP树****************\n")
    """
    freqItems =[]
    MinTree(headerTable,3, set([]), freqItems)
    
    for item in freqItems:
        print("\n item: \t ",item)
    
    
FP()

    

    参考文档:

     《机器学习实战》

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值