机器学习实战笔记9(Apriori算法)

Apriori算法也属于无监督学习,它强调的是“从数据X中能够发现什么”。从大规模的数据集中寻找物品之间隐含关系被称为关联分析或者称为关联规则学习。这里的主要问题在于,寻找物品的不同组合是一项十分耗时的任务,所需的计算代价很高,蛮力搜索并不能解决这个问题。因此此处介绍使用Apriorio算法来解决上述问题。

1:简单概念描述

(1)              频繁项集:指经常出现在一块的物品的集合。 关联规则暗示两种物品之间存在很强的关系。(这里我们事先定义阀值,超过该阀值,证明两者之间存在很强的关系).

(2)              一个项集的支持度(support)被定义为数据集中包含该项集的记录所占的比例。我们事先需要定义一个最小支持度(minSupport),而只保留满足最小支持度的项集。

(3)              可信度或置信度(confidence)是针对一条诸如{尿布}->{葡萄酒}的关联规则来定义的。

(4)              Apriori的原理是如果某个项集是频繁的,那么它的子集也是频繁的。反过来说,如果一个项集是非频繁的,那么它的所有超集也是非频繁的。比如{1,2}出现的次数已经小于最小支持度了(非频繁的),那么超集{0,1,2}的组合肯定也是非频繁的了。主要包括发现频繁项集和挖掘关联规则这两步。

2:发现频繁项集

过程是:从C1= {{0},{1},{2},{3}}开始,然后生成L1,L1是C1中项集的支持度大于等于最小支持度,比如L1 = {{0},{1},{3}}。然后由L1组合得到C2 = {{01},{03},{13}}。一直进行下去直到Ck为空。

# 加载数据
def loadDataSet():
    return [[1,3,4], [2,3,5], [1,2,3,5], [2,5]]

# 创建C1
def createC1(dataSet):
    C1 = []
    for transaction in dataSet:
        for item in transaction:
            if not[item] in C1:
                C1.append([item])
    C1.sort()
    return map(frozenset, C1)            #frozenset 可以将集合作为字典的键字使用

# 由Ck生成Lk
def scanD(D, Ck, minSupport):
    ssCnt = {}
    for tid in D:
        for can in Ck:
            if can.issubset(tid):
                if not ssCnt.has_key(can):ssCnt[can] = 1
                else: ssCnt[can] += 1
    numItems = float(len(D))
    retList = []
    supportData = {}
    for key in ssCnt:
        support = ssCnt[key]/numItems
        if support >= minSupport:
            retList.insert(0, key)            #在列表的首部插入任意新的集合
        supportData[key] = support
    return retList, supportData

#Apriori 算法
#  由Lk 产生Ck+1
def aprioriGen(Lk, k):
    retList = []
    lenLk = len(Lk)
    for i in range(lenLk):
        for j in range(i+1, lenLk):
            L1 = list(Lk[i])[:k-2]; L2 = list(Lk[i])[:k-2]
            L1.sort(); L2.sort()
            if L1 == L2:
                retList.append(Lk[i] | Lk[j])
    return retList

def apriori(dataSet, minSupport = 0.5):
    C1 = createC1(dataSet)
    D = map(set, dataSet)
    L1, supportData = scanD(D, C1, minSupport)
    L = [L1]
    k = 2
    while(len(L[k-2]) > 0):
        Ck = aprioriGen(L[k-2], k)
        Lk, supK = scanD(D,Ck, minSupport)
        supportData.update(supK)
        L.append(Lk)
        k += 1
    return L, supportData

注意:(1)C1是大小为1的所有候选项集的集合

(2)这里使用了python的frozenset类型。frozenset是指被“冰冻”的集合,就说它们是不可改变的,即用户不能修改它们。这里必须使用frozenset而不是set类型,因为之后必须要将这些集合作为字典键值使用,使用frozenset可以实现这一点,而set却做不到。

3:从频繁项集中发现关联规则

#从频繁项集中发现关联规则
def generateRules(L, supportData, minConf=0.7):  #supportData is a dict coming from scanD
    bigRuleList = []
    for i in range(1, len(L)):#only get the sets with two or more items
        for freqSet in L[i]:
            H1 = [frozenset([item]) for item in freqSet]
            if (i > 1):
                rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)
            else:
                calcConf(freqSet, H1, supportData, bigRuleList, minConf)
    return bigRuleList         

def calcConf(freqSet, H, supportData, brl, minConf=0.7):
    prunedH = [] #create new list to return
    for conseq in H:
        conf = supportData[freqSet]/supportData[freqSet-conseq] #calc confidence
        if conf >= minConf:
            print freqSet-conseq,'-->',conseq,'conf:',conf
            brl.append((freqSet-conseq, conseq, conf))
            prunedH.append(conseq)
    return prunedH

def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
    m = len(H[0])
    if (len(freqSet) > (m + 1)): #try further merging
        Hmp1 = aprioriGen(H, m+1)#create Hm+1 new candidates
        Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf)
        if (len(Hmp1) > 1):    #need at least two sets to merge
            rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)

4:使用FP-growth算法来高效发现频繁项集

每次增加频繁项集的大小,Apriori算法都会重新扫描整个数据集。当数据集很大时,这会显著降低频繁项集发现的速度。而FP-growth树只需要对数据库进行两次遍历,能够显著加快频繁项集的速度。但是该算法不能用于发现关联规则。

第一遍对所有元素项的出现次数进行计数,只用来统计出现的频率。而第二遍扫描只考虑那些频繁元素,用来构建FP树。

# -*- coding: cp936 -*-
#创建FP树的数据结构
class treeNode:
    def __init__(self, nameValue, numOccur, parentNode):
        self.name = nameValue
        self.count = numOccur
        self.nodeLink = None
        self.parent = parentNode
        self.children = {}

    def inc(self, numOccur):
        self.count += numOccur

    def disp(self, ind = 1):
        print ' '*ind, self.name, ' ', self.count
        for child in self.children.values():
            child.disp(ind+1)

# 加载数据
def loadSimpDat():
    simpDat = [['r', 'z', 'h', 'j', 'p'],
               ['z', 'y', 'x', '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']]
    return simpDat

def createInitSet(dataSet):
    retDict = {}
    for trans in dataSet:
        retDict[frozenset(trans)] = 1
    return retDict

#构建FP树
def createTree(dataSet, minSup = 1):
    headerTable = {}
    for trans in dataSet:         #计算每个元素出现的频率
        for item in trans:
            headerTable[item] = headerTable.get(item, 0) + dataSet[trans]
    for k in headerTable.keys():    #移除不满足最小支持度的元素项
        if headerTable[k] < minSup:
            del[headerTable[k]]
    freqItemSet = set(headerTable.keys())
    if len(freqItemSet) == 0: return None, None    #如果没有数据项满足要求,则退出
    for k in headerTable:
        headerTable[k] = [headerTable[k], None]
    retTree = treeNode('Null Set', 1, None)
    for tranSet, count in dataSet.items():     #根据全局频率对每个事务中的元素进行排序
        localD = {}
        for item in tranSet:
            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)
    return retTree, headerTable

def updateTree(items, inTree, headerTable, count):
    if items[0] in inTree.children:
        inTree.children[items[0]].inc(count)
    else:
        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)    #对剩下的元素项迭代调用updateTree函数

def updateHeader(nodeToTest, targetNode):
    while(nodeToTest.nodeLink != None):
        nodeToTest = nodeToTest.nodeLink
    nodeToTest.nodeLink = targetNode

时间: 2024-10-22 12:59:26

机器学习实战笔记9(Apriori算法)的相关文章

机器学习实战笔记-K近邻算法1(分类动作片与爱情片)

K近邻算法采用测量不同特征值之间的距离方法进行分类 K近邻算法特点: 优点:精度高.对异常值不敏感.无数据输入假定. 缺点:计算复杂度高.空间复杂度高. 适用数据范围:数值型和标称型. K近邻算法原理: 存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系.输人没有标签的新数据后,将新数据的每个特征与样本集中数据对应的 特征进行比较,然后算法提取样本集中特征最相似数据(最近 邻)的分类标签.一般来说,我们只选择样本数据集中前k个最

机器学习实战笔记——基于KNN算法的手写识别系统

本文主要利用k-近邻分类器实现手写识别系统,训练数据集大约2000个样本,每个数字大约有200个样本,每个样本保存在一个txt文件中,手写体图像本身是32X32的二值图像,如下图所示: 首先,我们需要将图像格式化处理为一个向量,把一个32X32的二进制图像矩阵通过img2vector()函数转换为1X1024的向量: def img2vector(filename): returnVect = zeros((1,1024)) fr = open(filename) for i in range(

机器学习实战笔记——利用KNN算法改进约会网站的配对效果

一.案例背景 我的朋友海伦一直使用在线约会网站寻找合适自己的约会对象.尽管约会网站会推荐不同的人选,但她并不是喜欢每一个人.经过一番总结,她发现曾交往过三种类型的人: (1)不喜欢的人: (2)魅力一般的人: (3)极具魅力的人: 尽管发现了上述规律,但海伦依然无法将约会网站推荐的匹配对象归入恰当的分类,她觉得可以在周一到周五约会那些魅力一般的人,而周末则更喜欢与那些极具魅力的人为伴.海伦希望我们的分类软件可以更好地帮助她将匹配对象划分到确切的分类中.此外,海伦还收集了一些约会网站未曾记录的数据

机器学习实战笔记-K近邻算法2(改进约会网站的配对效果)

案例二.:使用K-近邻算法改进约会网站的配对效果 案例分析: 海伦收集的数据集有三类特征,分别是每年获得的飞行常客里程数.玩视频游戏所耗时间百分比. 每周消费的冰淇淋公升数.我们需要将新数据的每个新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签.一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数.最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类. 流程:在约会网站上使用K

机器学习实战笔记--k近邻算法

1 #encoding:utf-8 2 from numpy import * 3 import operator 4 import matplotlib 5 import matplotlib.pyplot as plt 6 7 from os import listdir 8 9 def makePhoto(returnMat,classLabelVector): #创建散点图 10 fig = plt.figure() 11 ax = fig.add_subplot(111) #例如参数为

机器学习实战笔记-K近邻算法3(手写识别系统)

1 准备数据:将图像转换为测试向量 这次数据集还是有两种,训练数据集和测试数据集,分别有2000个,900个. 我们将把一个32*32的二进制图像矩阵转换为1 x 1024的向量,这样前两节使用的分类器就可以处理数字图像信息了. 代码: def img2vector(filename): returnVect = zeros((1,1024)) file = open(filename) for i in range(32): line = file.readline() for j in ra

机器学习实战笔记6(SVM)

鉴于July大哥的SVM三层境界(http://blog.csdn.net/v_july_v/article/details/7624837)已经写得非常好了,这里我就不详细描述,只是阐述简单的几个概念.如果看SVM三层境界有困惑,我也愿意与大家交流,共同进步. 简单概念描述: (1)      支持向量机(SVM, support vectormachine)就是通过最大化支持向量到分类超平面之间的分类间隔.分类超平面就是我们想要得到的决策曲面:支持向量就是离分类超平面最近的点,而间隔即为支持

机器学习实战笔记7(Adaboost)

1:简单概念描述 Adaboost是一种弱学习算法到强学习算法,这里的弱和强学习算法,指的当然都是分类器,首先我们需要简单介绍几个概念. 1:弱学习器:在二分情况下弱分类器的错误率会高于50%.其实任意的分类器都可以做为弱分类器,比如之前介绍的KNN.决策树.Na?ve Bayes.logiostic回归和SVM都可以.这里我们采用的弱分类器是单层决策树,它是一个单节点的决策树.它是adaboost中最流行的弱分类器,当然并非唯一可用的弱分类器.即从特征中选择一个特征来进行分类,该特征能是错误率

机器学习实战笔记1(机器学习基础)

1:如何选择合适的算法 2:python简介 (1)   python的优势:相对于matlab,matlab单个软件授权就要花费数千美元,也没有一个有影响力的大型开源项目.相对于c++/c/java,完成简单的操作就需要编写大量的代码:而如今我们应该花费更多的时间去处理数据内在的含义,而无需花费太多精力解决计算机如何得到数据结果(python简洁) (2)   python具有numpy科学函数库,它是一个使运算更容易.执行更迅速的库:另外还有matplotlib绘图工具. 3:python语