目录

  • 1 第一章 数据仓库概述
    • 1.1 授课安排
    • 1.2 数据仓库及其历史
      • 1.2.1 数据仓库的概念
        • 1.2.1.1 本节视频
      • 1.2.2 数据仓库特征
        • 1.2.2.1 本节视频
    • 1.3 数据仓库系统结构
      • 1.3.1 数据仓库系统的组成
        • 1.3.1.1 本节视频
      • 1.3.2 ETL
        • 1.3.2.1 本节视频
      • 1.3.3 数据仓库和数据集市的关系
      • 1.3.4 元数据及其管理
      • 1.3.5 数据集市和元数据管理视频
    • 1.4 数据仓库系统开发工具
    • 1.5 数据仓库与操作型数据库的关系
      • 1.5.1 本节视频内容
  • 2 第二章 数据仓库设计
    • 2.1 授课安排
    • 2.2 数据仓库设计概述
    • 2.3 数据仓库的规划和需求分析
    • 2.4 数据仓库的建模
    • 2.5 数据仓库的物理模型设计
    • 2.6 数据仓库的部署和维护
  • 3 第三章 OLAP技术
    • 3.1 授课安排
    • 3.2 OLAP概述
    • 3.3 OLAP的多维数据模型
    • 3.4 OLAP实现
  • 4 第四章 数据
    • 4.1 课程资料
  • 5 第五章 数据挖掘概述
    • 5.1 授课安排
    • 5.2 什么是数据挖掘?
    • 5.3 数据挖掘系统
    • 5.4 视频
    • 5.5 数据挖掘过程
  • 6 第六章 关联分析
    • 6.1 授课安排
    • 6.2 关联分析概念
    • 6.3 Apriori算法
    • 6.4 FP-growth树
    • 6.5 多层关联规则
    • 6.6 【扩充知识】机器学习——关联规则——支持度(support)、置信度(confidence)、提升度(Lift)
  • 7 第七章 序列模式挖掘
    • 7.1 序列模式挖掘概述
    • 7.2 AprioriAll算法
    • 7.3 AprioriSome算法
    • 7.4 FreeSpan算法
    • 7.5 PrefixSpan算法
  • 8 第八章 聚类分析
    • 8.1 聚类概述
  • 9 分类算法
    • 9.1 课件
  • 10 实验1 python基础
    • 10.1 讲解文本内容
    • 10.2 课程PDF
    • 10.3 实验代码
    • 10.4 实验报告封皮
  • 11 实验2-python
    • 11.1 讲解文本内容
    • 11.2 实验代码
    • 11.3 实验报告封面
  • 12 实验3--python
    • 12.1 讲解文本内容
    • 12.2 实验代码
    • 12.3 实验报告封面
  • 13 实验4--python
    • 13.1 讲解文本内容
    • 13.2 21.1实验代码
    • 13.3 实验内容2
    • 13.4 实验内容3
    • 13.5 实验报告封面
  • 14 实验5--python
    • 14.1 文本内容-NumPy模块
    • 14.2 第三方可视化数据分析图表
    • 14.3 数据
    • 14.4 思考题
    • 14.5 实验报告封面
  • 15 实验6--python
    • 15.1 实验 NumPy矩阵的基本操作
    • 15.2 实验 关联规则算法
    • 15.3 实验 商品零售购物篮分析
    • 15.4 实验报告封面
  • 16 实验7--python
    • 16.1 实验1 用关联规则分析方法推荐电影
    • 16.2 实验2 FP-growth算法
    • 16.3 实验3 教育平台的线上课程推荐策略
    • 16.4 实验报告封面
  • 17 实验8-python
    • 17.1 实验1 购物车分析
    • 17.2 实验2 基于关联规则的文本分析
  • 18 实验9--python
    • 18.1 实验1 聚类分析
    • 18.2 实验2 航空公司客户价值分析
    • 18.3 实验3 运输车辆安全驾驶行为分析
    • 18.4 实验报告封面
实验2 FP-growth算法

FP-growth(Frequent Pattern Tree, 频繁模式树),是韩家炜老师提出的挖掘频繁项集的方法,是将数据集存储在一个特定的称作FP树的结构之后发现频繁项集或频繁项对,即常在一块出现的元素项的集合FP树。 

FP-growth算法比Apriori算法效率更高,在整个算法执行过程中,只需遍历数据集2次,就能够完成频繁模式发现,其发现频繁项集的基本过程如下: 

(1)构建FP树 

(2)从FP树中挖掘频繁项集

FP-growth的一般流程如下: 

1:先扫描一遍数据集,得到频繁项为1的项目集,定义最小支持度(项目出现最少次数),删除那些小于最小支持度的项目,然后将原始数据集中的条目按项目集中降序进行排列。 

2:第二次扫描,创建项头表(从上往下降序),以及FP树。 

3:对于每个项目(可以按照从下往上的顺序)找到其条件模式基(CPB,conditional patten base),递归调用树结构,删除小于最小支持度的项。如果最终呈现单一路径的树结构,则直接列举所有组合;非单一路径的则继续调用树结构,直到形成单一路径即可。 

示例说明 

如下表所示数据清单(第一列为购买id,第二列为物品项目):

TidItems
1I1, I2, I5
2I2, I4
3I2, I3
4I1, I2, I4
5I1, I3
6I2, I3
7I1, I3
8I1, I2, I3, I5
9I1, I2, I3

第一步:构建FP树 

1. 扫描数据集,对每个物品进行计数:

I1

I2

I3

I4

I5

6

7

6

2

2

2. 设定最小支持度(即物品最少出现的次数)为2 

3. 按降序重新排列物品集(如果出现计数小于2的物品则需删除)

I2I1I3I4I5
76622

4. 根据项目(物品)出现的次数重新调整物品清单

TidItems
1I2, I1, I5
2I2, I4
3I2, I3
4I2, I1, I4
5I1, I3
6I2, I3
7I1, I3
8I2, I1, I3, I5
9I2, I1, I3

5. 构建FP树 

加入第一条清单(I2, I1, I5): 

加入第二条清单(I2, I4): 

出现相同的节点进行累加(I2) 

下面依次加入第3-9条清单,得到FP树: 

第二步:挖掘频繁项集 

对于每一个元素项,获取其对应的条件模式基(conditional pattern base)。条件模式基是以所查找元素项为结尾的路径集合。每一条路径其实都是一条前缀路径。 

按照从下往上的顺序,考虑两个例子。 

(1)考虑I5,得到条件模式基{(I2 I1:1), (I2 I1 I3)}, 构造条件FP树如下,然后递归调用FP-growth,模式后缀为I5。这个条件FP树是单路径的,在FP-growth中直接列举{I2:2,I1:2,I3:1}的所有组合,之后和模式后缀I5取并集得到支持度大于2的所有模式:{ I2 I5:2, I1 I5:2, I2 I1 I5:2}

(2)I5的情况是比较简单的,因为I5对应的条件FP-树是单路径的。下面考虑I3,I3的条件模式基是{(I2 I1:2), (I2:2), (I1:2)},生成的条件FP-树如左下图,然后递归调用FP-growth,模式前缀为I3。I3的条件FP-树仍然是一个多路径树,首先把模式后缀I3和条件FP树中的项头表中的每一项取并集,得到一组模式{I2 I3:4, I1 I3:4},但是这一组模式不是后缀为I3的所有模式。还需要递归调用FP-growth,模式后缀为{I1,I3},{I1,I3}的条件模式基为{I2:2},其生成的条件FP-树如右下图所示。这是一个单路径的条件FP-树,在FP-growth中把I2和模式后缀{I1,I3}取并得到模式{I1 I2 I3:2}。理论上还应该计算一下模式后缀为{I2,I3}的模式集,但是{I2,I3}的条件模式基为空,递归调用结束。最终模式后缀I3的支持度大于2的所有模式为:{ I2 I3:4, I1 I3:4, I1 I2 I3:2} 

根据FP-growth算法,最终得到的支持度大于2频繁模式如下:

item条件模式基条件FP树产生的频繁模式
I5{(I2 I1:1),(I2 I1 I3:1)}(I2:2, I1:2)I2 I5:2, I1 I5:2, I2 I1 I5:2
I4{(I2 I1:1), (I2:1)}(I2:2)I2 I4:2
I3{(I2 I1:2), (I2:2), (I1:2)}(I2:4, I1:2), (I1:2)I2 I3:4, I1 I3:4, I2 I1 I3:2
I1{(I2:4)}(I2:4)I2 I1:4

FP-growth算法实现

1. FP树的类定义

根据FP-growth算法,最终得到的支持度大于2频繁模式如下:

class treeNode:

    def __init__(self, nameValue, numOccur, parentNode):

        self.name = nameValue #节点名字

        self.count = numOccur #节点计数值

        self.nodeLink = None #用于链接相似的元素项

        self.parent = parentNode      #needs to be updated

        self.children = {} #子节点

    

    def inc(self, numOccur):

        '''

        对count变量增加给定值

        '''

        self.count += numOccur

    

    def disp(self, ind=1):

        '''

        将树以文本形式展示

        '''

        print ('  '*ind, self.name, ' ', self.count)

        for child in self.children.values():

            child.disp(ind+1)

2. FP树构建函数

def createTree(dataSet, minSup=1):

    '''

    创建FP树

    '''

    headerTable = {}    #第一次扫描数据集

    for trans in dataSet:#计算item出现频数

        for item in trans:

            headerTable[item] = headerTable.get(item, 0) + dataSet[trans]

    headerTable = {k:v for k,v in headerTable.items() if v >= minSup}

    freqItemSet = set(headerTable.keys())

    #print ('freqItemSet: ',freqItemSet)

    if len(freqItemSet) == 0: return None, None  #如果没有元素项满足要求,则退出

    for k in headerTable:

        headerTable[k] = [headerTable[k], None] #初始化headerTable

    

    #print ('headerTable: ',headerTable)

    #第二次扫描数据集

    retTree = treeNode('Null Set', 1, None) #创建树

    for tranSet, count in dataSet.items():  

        localD = {}

        for item in tranSet:  #put transaction items in order

            if item in freqItemSet:

                localD[item] = headerTable[item][0]

        

        if len(localD) > 0:

            orderedItems = [v[0] for v in sorted(localD.items(), key=lambda p: p[1], reverse=True)]

            updateTree(orderedItems, retTree, headerTable, count)#将排序后的item集合填充的树中

            

    return retTree, headerTable #返回树型结构和头指针表


def updateTree(items, inTree, headerTable, count):

    if items[0] in inTree.children:#检查第一个元素项是否作为子节点存在

        inTree.children[items[0]].inc(count) #存在,更新计数

    else:   #不存在,创建一个新的treeNode,将其作为一个新的子节点加入其中

        inTree.children[items[0]] = treeNode(items[0], count, inTree)

        if headerTable[items[0]][1] == None: #更新头指针表

            headerTable[items[0]][1] = inTree.children[items[0]]

        else:

            updateHeader(headerTable[items[0]][1], inTree.children[items[0]])

    

    if len(items) > 1:#不断迭代调用自身,每次调用都会删掉列表中的第一个元素

        updateTree(items[1::], inTree.children[items[0]], headerTable, count)


def updateHeader(nodeToTest, targetNode):

    '''

    this version does not use recursion

    Do not use recursion to traverse a linked list!

    更新头指针表,确保节点链接指向树中该元素项的每一个实例

    '''

    

    while (nodeToTest.nodeLink != None): 

        nodeToTest = nodeToTest.nodeLink

        nodeToTest.nodeLink = targetNode

3. 抽取条件模式基

def ascendTree(leafNode, prefixPath): #迭代上溯整棵树

    if leafNode.parent != None:

        prefixPath.append(leafNode.name)

        ascendTree(leafNode.parent, prefixPath)


def findPrefixPath(basePat, treeNode): #treeNode comes from header table

    condPats = {}

    while treeNode != None:

        prefixPath = []

        ascendTree(treeNode, prefixPath)

        if len(prefixPath) > 1: 

            condPats[frozenset(prefixPath[1:])] = treeNode.count

        treeNode = treeNode.nodeLink

    

    return condPats

4. 递归查找频繁项集

def mineTree(inTree, headerTable, minSup, preFix, freqItemList):

    bigL = [v[0] for v in sorted(headerTable.items(), key=lambda p: p[1][0])]# 1.排序头指针表

    for basePat in bigL:  #从头指针表的底端开始

        newFreqSet = preFix.copy()

        newFreqSet.add(basePat)

        print ('finalFrequent Item: ',newFreqSet)    #添加的频繁项列表

        freqItemList.append(newFreqSet)

        condPattBases = findPrefixPath(basePat, headerTable[basePat][1])

        print ('condPattBases :',basePat, condPattBases)

        

        # 2.从条件模式基创建条件FP树

        myCondTree, myHead = createTree(condPattBases, minSup)

        #         print ('head from conditional tree: ', myHead)

        if myHead != None: # 3.挖掘条件FP树

            print ('conditional tree for: ',newFreqSet)

            myCondTree.disp(1)

            mineTree(myCondTree, myHead, minSup, newFreqSet, freqItemList)

5. 测试结果

def loadSimpDat():

    simpDat=[

        ['I1','I2','I5'],

        ['I2','I4'],

        ['I2','I3'],

        ['I1','I2','I4'],

        ['I1','I3'],

        ['I2','I3'],

        ['I1','I3'],

        ['I1','I2','I3','I5'],

        ['I1','I2','I3']

        ]

    

    return simpDat


def createInitSet(dataSet):

    retDict = {}

    for trans in dataSet:

        retDict[frozenset(trans)] = retDict.get(frozenset(trans), 0) + 1 #若没有相同事项,则为1;若有相同事项,则加1 

    return retDict


minSup=2

simpDat = loadSimpDat()

initSet = createInitSet(simpDat)

myFPtree, myHeaderTab = createTree(initSet, minSup)

myFPtree.disp()

myFreqList = []

mineTree(myFPtree, myHeaderTab, minSup, set([]), myFreqList)


myFreqList