精华内容
下载资源
问答
  • 制造执行系统,能够采集生产现场的实时数据,面向制造过程,企业生产管理系统有着承上启下的重要作用,对于生产计划监控、资源调配、调度和生产过程优化等工作有着促进作用。国内企业随着信息化工作的逐步深入,...

        美国先进制造机构,首先提出了MES 的大致概念,并且将定位了MES 的应用方向——解决重点生产管理问题。制造执行系统,能够采集生产现场的实时数据,面向制造过程,在企业生产管理系统中有着承上启下的重要作用,对于生产计划监控、资源调配、调度和生产过程优化等工作有着促进作用。国内企业随着信息化工作的逐步深入,目前,在电子、航天、航空等领域MES 都获得了广泛的应用,MES 俨然已经成为了企业应用和企业制造信息化研究的热点之一。

    1 电子产品制造业的特点及小批量电子产品生产管理的主要问题

        电子电器制造类企业,既有单件小批量生产,也有批量生产;有按库存生产,也有按订单生产,属于典型的离散制造行业。因产品的不同其生产工艺流程也不尽相同,生产设备的布置不是按产品,而是按照工艺进行布置。而且,可以同一种工艺可以有多台机床同时进行加工,所以,同时要对所加工的物料进行调度,并且中间品需要进行搬运。其企业自动化主要在单元级,自动化水平相对较低,因此产品的生产率和产品质量很大程度依赖于工作人员的技术水平。因为电子生产企业多数为按订单进行组织生产的企业,对生产车间和采购的计划需要很好的生产计划系统,产品生产的工艺过程经常需要变更,并且很难预测到什么时候有订单,所以生产计划系统对投资效益来说作用较大。电子制造业制订生产计划的依据可以根据市场的预测,企业的ERP 系统主要是采用工作令的方式向MES 下达作业计划指令。

        在成本核算方式方面,是由底层向高层逐层累积得出的,电子制造业的MES系统计算产品成本是按照产品的BOM 所描述的加工装配过程,它反映了产品增值的整个实际过程。电子制造业对设备级、工序级的作业计划进行调度,需要根据工作中心能力、均衡生产、优先级和设备能力等方面。在电子制造业中,让操作人员及时掌握相关工序的生产任务一般采用电子看板方式,或者采用作业指示书、派工单等方式将作业计划调度结果下达给操作人员,作业的计划内容,一般包括该工序的开工时间、成产数据和完工时间等方面。由于电子制造业的一台或几台设备故障,对整个产品的工艺生产过程一般不会产生特别严重的影响,所以在设备管理方面,一般只需要对瓶颈和关键设备进行重点管理。

        制造过程是整个工程应用的重要保障。目前,一部分产品具有产品质量要求高、多品种、技术尖端和小批量等特点,生产环节多,生产过程也相对复杂。近年来,科研生产呈现出多种型号产品的生产和研究,生产计划有一定的不确定性,项目要求变更也在日渐增多等特点。边研制边进行成产和定型,新型号的研制打破了传统的串行研究制程序,研制周期也很短,这对生产组织的管来来说有着很大的难度。

        采用传统的生产管理方式来完成任务,在这种形式下则需要投入较大的管理成本。随着型号产品的日渐增多,研制周期的日益缩短,传统的生产管理方式面临着重大挑战,主要表现在,生产和技术准备周期过长,管理信息和技术信息管理程序不够规范及信息不能共享;生产过程中工作主动性及车间工作人员调度能力,管理部门、生产车间对生产过程的不可监控;各部门的数据统计不够协调,不能及时发现问题,缺乏资源一致性维护;工时定额不够准确,不能为型号的成本核算提供相对准确和合理的数据,也无法作为工作人员绩效考核的有效依据;难以对制造过程中的产品质量进行动态分析和监控,数据采集困难;生产流程的数据信息和分支也在随着设备和型号产品的不断激增而不断的增多,快速分析各产品的加工过程信息和各工位的任务情况,已经无法仅仅依靠人力来完成,只能依靠对最终节点情况的了解。这种传统的生产管理方式,对生产过程的了解往往是滞后的、局部的、粗略的,同时也无法对生产过程进行有效控制。

    2 电子产品制造业MES 功能模型框架

        电子产品制造业的MES 功能系统主要可分为九个子系统,分别是:信息查询子系统、质量管理子系统、系统安全管理子系统、设备管理子系统、库存管理子系统、工作人员岗位管理子系统、制造管理子系统、成本核算子系统和成产计划管理子系统。电子制造业MES 系统实施主要有现场数据采集和作业调度两个关键性技术。现场数据收集除了生产数据的实时收集外,还有收集强调与设备控制系统的集成。电子制作业的作业调度是指MES系统能够及时发现生产环节的各种问题,并且进行提异常警报示,从而使系统可以根据各站点的情况进行重新排配,高效地解决瓶颈问题。要遵循相关的标准进行与设备控制系统的集成,为了方便分析和调用,系统里的数据标准肯定要有一个统一管理方式。通过规范化的编码信息来完成实时生产数据的收集,比如缺陷和型号以及供应商等,基于这些数据,制造管理、产品追踪、品质管理和设备管理,是其功能的核心模块。从核心功能模块派生出来的有异常警报、品质信息报表查询、生产状况监控和生产信息表报查询等,同时,MES 系统还应该提供其他一些系统的接口。

        实行所和车间是电子产品生产过程通常实行的两级生产管理体制。实行所其工作内容侧重于对产品生产流程的全程管理、监控和生产计划的制定,是生产管理部门的科研生产处。实际生产任务车间主要由质检中心、机械加工车间、工艺室和电子装联车间等单位来承担。科研生产处下达的批次生产计划由车间接收,车间根据现阶段的实际生产情况和具体生产任务,进一步制定出各生产小组的具体批次生产计划。同时根据生产资源制定出作业计划,进行粗能力平衡,并且确定各工序的开工及完工日期。按照正常流程,整批产品的一道工序完成后就应该提交进行质量检验,质量检查中心检验不合格的产品进行返工返修或者实行报废补投,而经检验后合格的的产品则入库。

        各相关生产单位在电子产品MES 中的主要工作模式为:为了及时掌握并组织解决生产过程中所出现的问题,生产单位及科研生产处利用MES 对现场生产活动进行查询和监控,对生产计划做出有效调整;在MES 中科研生产处完成所生产任务单;在MES中,明确生产数量,进行工艺定额制定,完成工时定额及材料定额,作为车间进行生产组织的依据和数据,将工时定额和材料定额信息储存在MES 中;工艺部门根据生产任务单在计算机辅助工艺过程设计系统中完成工艺规程设计;根据所生产工艺规程及生产计划,电子装联车间和机械加工车间自动从CAPP 系统中导出工艺信息,并在MES 中完成车间计划调度及生产指令卡生成等过程,并且根据生产指令卡组织工序进行;在条码技术的支持下,质量检验部门在工序检验过程中,要将质量信息和操作者等相关生产现场数据录入MES 中提供系统管理。

    3 在电子产品生产管理中MES 的具体应用

        在MES 的应用和实施中,通过共享信息,管理效率、信息的利用率及透明度都得到了有效的提高。MES 的所有数据都以科研生产任务为主线,都基于统一的数据库平台,使各岗位工作人员都能够通过系统的数据统计功能和信息查询功能获得与自己相关联的数据。通过与CAPP 系统的集成,减少了信息的重复录入量,自动生成了生产指令卡,有效的缩短了车间的生产准备时间。通过MES 系统内丰富的生产数据,为产品的生产资源优化配置、产品质量分析和生产计划的合理安排提供了科学的依据。对生产过程中的各环节的数量、进度和时间节点等信息,通过MES 系统进行了有效的监控和限制,规范了生产管理流程,并且达到了规范生产流程的目的。总而言之,MES 的开发以及它在小批量电子产品生产管理中的应用和实施,对电子产品生产业的发展,是具有良好的实际效果的。

    4 总结

        针对特定的产业生产形态以及功能需求,开发MES 应采用相应的功能模块设计,MES 系统的功能设计,是开发设计MES 系统的关键工作之一。今后,随着MESBCO 的进一步实施和优化,MES 的应用将起到提高产品质量和规范生产过程控制的作用,将有效的提高各部门的快速响应能力,推动科研生产管理活动高效益、快节奏的有序运行。同时,也可增加生产信息的透明度,通过信息集成、信息共享和信息处理等技术,减少电子产品的生产准备时间,大大提高生产管理效率。

    展开全文
  • SAP,有的企业同时应用了MM物料管理模块和WM参考管理模块。这就导致某些操作需要做双重处理。比如物料移动,当一个物料MM模块从一个库存地点移动到另一个库存地点时,WM模块层面,需要做相同的操作。否则...

    在SAP中,有的企业同时应用了MM物料管理模块和WM参考管理模块。这就导致某些操作需要做双重处理。比如物料移动,当一个物料在MM模块中从一个库存地点移动到另一个库存地点时,在WM模块层面,需要做相同的操作。否则,就会导致两个模块中物料库存数据的不一致。通常在系统设计阶段,外部顾问会在MM模块的物料移动执行后,自动调用WM模块的相关事务来引导用户做关联处理。但如果用户在执行完MM层面的物料移动后,取消了后续WM模块的移库操作,差异问题就会发生。

    本文讨论在出现类似问题时的争决方法:

    首先,仓库部门会通过相应库存查询事务发现差异,体现在MM中做库存查询和WM中库存查询出现的同一物料数量不一致。
    比如下图,先用MM模块事务MMBE查询某物料显示总库存和WM模块事务LS24查询出的库存数量不一致。
    在这里插入图片描述

    出现问题后,通过事务LX23来查询库存地点物料差异情况,输入出现差异的工厂和库存地点来查询。其差异结果如下图所示:
    在这里插入图片描述
    查询到结果后,退回到LX23界面,选择清除差异。请注意,建议上一步骤差异查询时先不要勾选清除差异。等查询结果确认后,再返回来做处理。通过LX23事务自动处理差异的原理是返回到产生差异前的情形。

    举例说明:假如在MM层面运行移库事务,将某物料做盘亏处理后,MM层面物料会减少。此时,没有做WM层面的处理,那么WM层面的库存并不会相应减少。所以MM和WM的差异就产生了。发现问题后,用LX23做自动清除差异处理时,系统就会自分理处冲销掉MM层面的盘亏调整凭证。回来处理前的状态。这样,MM层面的库存就回来了。差异就没有了。
    在这里插入图片描述

    展开全文
  • 3.库存管理(摆放);4.促销页面设计;5.捆绑销售;6.内容推荐 相关概念 支持度:物品或物品组合,所有数据出现的概率(计算物品A的概率) [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接...

    apriori:算法(无监督学习)

    • 应用场景:

      • 1.啤酒、尿不湿;2.大量数据中(购物小票)找到经常在一起出现的物品组合
      • 3.库存管理(摆放);4.促销页面设计;5.捆绑销售;6.内容推荐
    • 相关概念

      • 1.支持度support:物品或物品组合,在所有数据中出现的概率

        • 公式:计算同时购买AB的支持度:support(A&B) = 同时购买AB的订单数量/总的订单数量=n(A&B)/n
      • 2.置信度confidence:购买A的订单中同时购买了B的订单数量/购买A的订单数量,就称为A对B的置信度

        • 公式:confidence(A->B)=P(B|A)=P(B&A)/P(A)= (n(A&B)/n)/(n(A)/n)= n(A&B)/n(A)
        • 相当于条件概率的计算P(B|A)=同时出现AB的概率/出现A的概率
        • 注意:A对B的置信度,与B对A的置信度不是一个概念
      • 3.提升度lift:应用关联规则与不应用产生结果的比例;

        • 公式:lift(A->B)= 对购买A的人运用规则计算会去买B的数量比例 / 不考虑是否购买A计算购买B的数量比例 = confidence(A->B) / support(B) = P(B&A)/P(A) / P(B) = n(A&B)/n(A) / (n(B)/n) = n(A&B)*n/n(A)/n(B) (这就是A对B的提升度,从公式很快得出,A对B的提升度与B对A的提升度相等
        • 如果lift>1,说明关联规则有效果,但在实际运用中,我们认为提升度>3才算作值得认可的关联规则
        • 如果lift=1,说明没有任何意义,A与B相互独立,互不影响;
        • 如果lift<1,说明有反作用,买了A就不愿意买B;
    • 举例说明: 20个人,5个人买了面包+牛奶,3个人只买了面包,7个人只买了牛奶,还有5个人只买了鸡蛋

      • 同时购买 面包+牛奶 的支持度support = 5/20=0.25 >0.1(满足支持度阈值>0.1)
      • 购买面包 对 购买牛奶 的置信度confidence = 5/(5+3)=5/8 >0.5(满足置信度阈值>0.5)
      • 购买牛奶 对 购买面包 的置信度confidence = 5/(5+7)=5/12 <0.5(不满足置信度阈值>0.5)
      • 同时购买:面包+牛奶 的提升度lift = 5*20/((5+3)(5+7))=100/8/12>1
    • 补充说明:为什么在实际运用中,我们认为提升度>3才算作值得认可的关联规则

      • 当n中零事件由5变为35时,此时同时购买面包+牛奶 的支持度support = 5/49=0.102 >0.1(刚刚满足支持度阈值>0.1),此时计算提升度为:lift = 5*49/((5+3)(5+7))=245/8/12=2.55>1,有关联
      • 当n中零事件由5变为0时,此时同时购买面包+牛奶 的支持度support = 5/15=0.33 >0.1(满足支持度阈值>0.1),此时计算提升度为:lift = 5*15/((5+3)(5+7))=75/8/12=0.78<1,互斥
      • 结论:
        • 根据补充说明中的情况,在满足支持度>0.1的情况下,零事件数量的改变对提升度的影响,从0.78提升到了2.55,n中零事件越多,提升度的值越大
        • 所以,在实际运用中,我们一般定义支持度>0.1的情况下,认为提升度>3才算作值得认可的关联规则

    apriori原理

    • apriori原理:如果某个项集是频繁项集,那么它所有的子集也是频繁的。即如果 {0,1} 是频繁的,那么 {0}, {1} 也一定是频繁的;;这个原理直观上没有什么用,但是反过来看就有用了,该定理的逆反定理为 :如果一个项集是非频繁的,那么它的所有超集(包含该集合的集合)也是非频繁的;;Apriori原理的出现,可以在得知某些项集是非频繁之后,不需要计算该集合的超集,有效地避免项集数目的指数增长,从而在合理时间内计算出频繁项集。
    • 使用Apriori算法发现数据的(频繁项集、关联规则)
      • 频繁项集:经常出现在一块的物品的集合
      • 关联规则:暗示两种物品之间可能存在很强的关系
      • Apriori具体算法实现网上查,直接使用其接口即可Apriori
      • pip install akapriori
      • 使用: from akapriori import apriori
      • rules = apriori(order_records, support=0.1, confidence=0.5, lift=0,minlen=0, maxlen=5)
      • 返回 5个值:rules_all = pd.DataFrame(rules, columns=[‘item1’,‘item2’,‘support’,‘confidence’,‘lift’])

    代码实现

    import pandas as pd
    import apriori
    
    # 加载数据文件
    data = pd.read_csv('order_table.csv')
    
    # 转换成关联所用的记录模式
    order_ids = pd.unique(data['order_id'])  # 去重得到订单id
    # 将相同id的产品名称拼接到一个子列表中,再将这些id对应的子列表拼到一个列表中
    order_records = [data[data['order_id']==each_id]['product_name'].tolist() for each_id in 
                    order_ids]
    # 通过调用自定义的apriori做关联分析
    minS = 0.1 # 定义最小支持度阈值
    minC = 0.5 # 定义最小置信度阈值
    # 计算得到满足最小支持度的规则
    L, suppData = apriori.apriori(order_records, minSupport=minS)
    # 计算满足最小置信度的规则
    rules = apriori.generateRules(order_records, L, suppData, minConf=minC)
    # 关联结果报表评价
    # 展示数据集记录数和满足阈值定义的规则数量
    model_summary = 'data record: {1} \ nassociation rules count: {0}'
    print(model_summary.format(len(rules), len(order_records)), '\n','-'*60) # 使用str.format()输出
    # 创建频繁规则数据集
    rules_all = pd.DataFrame(rules, 
                             columns=['item1','item2','instance','support','confidence','lift'])
    rules_sort = rules_all.sort_values(['lift'], ascending=False)
    rules_sort.head(10)
    
    展开全文
  • 1. 关联分析是什么? Apriori和FP-growth算法是一种关联算法,属于无监督算法的一种,它们可以自动从数据挖掘出潜在的关联关系。例如经典的啤酒与尿布的故事。下面我们用一个例子来切入本文对关联关系以及关联...

    1. 关联分析是什么?

    Apriori和FP-growth算法是一种关联算法,属于无监督算法的一种,它们可以自动从数据中挖掘出潜在的关联关系。例如经典的啤酒与尿布的故事。下面我们用一个例子来切入本文对关联关系以及关联分析的讨论。

    0x1:一个购物篮交易的例子

    许多商业企业在日复一日的运营中积聚了大量的交易数据。例如,超市的收银台每天都收集大量的顾客购物数据。

    例如,下表给出了一个这种数据集的例子,我们通常称其为购物篮交易(market basket transaction)。表中每一行对应一个交易,包含一个唯一标识TID和特定顾客购买的商品集合。

    零售商对分析这些数据很感兴趣,以便了解其顾客的购买行为。可以使用这种有价值的信息来支持各种商业中的实际应用,如市场促销,库存管理和顾客关系管理等等。

    交易号码

    商品

    0

    豆奶,莴苣

    1

    莴苣,尿布,葡萄酒,甜菜

    2

    豆奶,尿布,葡萄酒,橙汁

    3

    莴苣,豆奶,尿布,葡萄酒

    4

    莴苣,豆奶,尿布,橙汁

    是购物篮数据中所有项的集合,而是所有交易的集合。包含0个或多个项的集合被称为项集(itemset)。

    如果一个项集包含 k 个项,则称它为 k-项集。显然,每个交易包含的项集都是 I 的子集。

    接下来基于这个例子,我们来讨论都有哪些关联关系,以及如何发掘这些关联关系。

    0x2:事物之间关联关系的两种抽象形式

    关联分析是在大规模数据集中寻找关联关系的任务。这些关系可以有两种形式:

    • 频繁项集:频繁项集(frequent item sets)是经常出现在一块儿的物品的集合,它暗示了某些事物之间总是结伴或成对出现。
    • 关联规则:关联规则(association rules)暗示两种物品之间可能存在很强的关系,它更关注的是事物之间的互相依赖条件先验关系

    下面用一个例子来说明这两种概念:下图给出了某个杂货店的交易清单。

    交易号码

    商品

    0

    豆奶,莴苣

    1

    莴苣,尿布,葡萄酒,甜菜

    2

    豆奶,尿布,葡萄酒,橙汁

    3

    莴苣,豆奶,尿布,葡萄酒

    4

    莴苣,豆奶,尿布,橙汁

    频繁项集是指那些经常出现在一起的商品集合,图中的集合{葡萄酒,尿布,豆奶}就是频繁项集的一个例子;

    从这个数据集中也可以找到诸如“尿布->葡萄酒”的关联规则,即如果有人买了尿布,那么他很可能也会买葡萄酒。

    这里我们注意,为什么是说尿布->葡萄酒的关联规则,而不是葡萄酒->尿布的关联规则呢?因为我们注意到,在第4行,出现了尿布,但是没有出现葡萄酒,所以这个关联推导是不成立的,反之却成立(至少在这个样本数据集里是成立的)。

    0x3:如何度量事物之间的关联关系

    我们用支持度和可信度来度量事物间的关联关系,虽然事物间的关联关系十分复杂,但是我们基于统计规律以及贝叶斯条件概率理论的基础进行抽象,得到一种数值化的度量描述。

    1. 项与项集

    设itemset={item1, item_2, …, item_m}是所有项的集合。

    其中,item_k(k=1,2,…,m)成为项。项的集合称为项集(itemset),包含k个项的项集称为k项集(k-itemset)

    k-项集对应到物理世界可能就是我们的规则集合,每个频繁项集都是一个k-项集。

    2. 支持度(support)- 用来寻找频繁项集(k-项集)的,即寻找频繁共现项

    关联规则的支持度定义如下:

    其中表示事务包含集合A和B的并(即包含A和B中的每个项)的概率。这里的支持度也可以理解为项集A和项集B的共现概率。

    通俗的说,一个项集的支持度(support)被定义数据集中包含该项集(多个项的组合集合)的记录所占的比例。

    如上图中,{豆奶}的支持度为4/5,{豆奶,尿布}的支持度为3/5。

    在实际的业务场景中,支持度可以帮助我们发现潜在的规则集合

    例如在异常进程检测中,当同时出现{ java->bash、bash->bash }这种事件序列集合会经常在发生了反弹shell恶性入侵的机器日志中出现(即这种组合的支持度会较高),这种频繁项集暗示了我们这是一个有代表性的序列标志,很可能是exploited IOC标志。

    3. 置信度(confidence)- 评价一个关联规则的置信度

    关联规则是形如 X→Y 的蕴涵表达式,其中 X 和 Y 是不相交的项集,即 X∩Y=∅。

    关联规则的置信度定义如下:

    这个公式暗示一个非常质朴的道理,如果一个事件A出现概率很高,那么这个事件对其他事件是否出现的推测可信度就会降低,很简单的道理,例如夏天今天气温大于20°,这是一个非常常见的事件,可能大于0.9的可能性,事件B是今天你会中彩票一等奖。confidence(A => B)的置信度就不会很高,因为事件A的出现概率很高,这种常见事件对事件B的推导关联几乎没有实际意义。

    通俗地说,可信度置信度(confidence)是针对关联规则来定义的。例如我们定义一个规则:{尿布}➞{葡萄酒},即购买尿布的顾客也会购买啤酒,这是一个关联规则,这个关联规则的可信度被定义为"支持度({尿布,葡萄酒}) / 支持度({尿布})"。

    由于{尿布,葡萄酒}的支持度为3/5,尿布的支持度为4/5,所以"尿布➞葡萄酒"的可信度为3/4。

    从训练数据的统计角度来看,这意味着对于包含"尿布"的所有记录,我们的规则对其中75%的记录都适用。

    从关联规则的可信程度角度来看,“购买尿布的顾客会购买葡萄酒”这个商业推测,有75%的可能性是成立的,也可以理解为做这种商业决策,可以获得75%的回报率期望。

    可以发现,置信度本质就是,贝叶斯条件概率的基本形式:P(A | B)= P(A,B)/ P(B)

    4. 强关联规则与频繁项集

    支持度是针对项集来说的,因此可以定义一个最小支持度,而只保留满足最小值尺度的项集。

    置信度是针对关联规则来说的,因此可以定义一个最小置信度,而只保留满足最小值置信度的关联规则

    • support ≥ minsup threshold
    • confidence ≥ minconf threshold

    满足最小支持度和最小置信度的关联规则,即待挖掘的最终关联规则。也是我们期望模型产出的业务结果。

    这实际上是在工程化项目中需要关心的,因为我们在一个庞大的数据集中,频繁项集合关联规则是非常多的,我们不可能采纳所有的这些关系,特别是在入侵检测中,我们往往需要提取TOP N的关联,并将其转化为规则,这个过程也可以自动化完成。

    0x4:关联规则挖掘算法的主要任务

    这个小节其实和0x2小节是一样的,关联规则挖掘算法就是在基于一种抽象评价函数,对事物间的关系进行抽象数值化,并进行计算。通过概率统计的基本定理,从中挖掘出有价值的“关系”。

    因此,大多数关联规则挖掘算法通常采用的一种策略是,将关联规则挖掘任务分解为如下两个主要的子任务。

    • 频繁项集产生:其目标是发现满足最小支持度阈值的所有项集,这些项集称作频繁项集(frequent itemset)。
    • 规则的产生:其目标是从上一步发现的频繁项集挖掘它们之间存在的依赖和推倒关系,并从所有关系中提取所有高置信度的规则,这些规则称作强规则(strong rule)。

    通常,频繁项集产生所需的计算开销远大于产生规则所需的计算开销。

    0x5:怎么去挖掘数据集中潜在的关系呢?暴力搜索可以吗?

    一种最直接的进行关联关系挖掘的方法或许就是暴力搜索(Brute-force)的方法,实际上,如果算力足够,理论上所有机器学习算法都可以暴力搜索,也就不需要承担启发式搜索带来的局部优化损失问题。

    1. List all possible association rules
    2. Compute the support and confidence for each rule
    3. Prune rules that fail the minsup and minconf thresholds

    然而,由于Brute-force的计算量过大,所以采样这种方法并不现实!

    格结构(Lattice structure)常被用来枚举所有可能的项集。如下图所示为 I={a,b,c,d,e} 的项集格。

    一般来说,排除空集后,一个包含k个项的数据集最大可能产生个频繁项集。由于在实际应用中k的值可能非常大,需要探查的项集搜索空集可能是指数规模的。

    Relevant Link:

    https://blog.csdn.net/baimafujinji/article/details/53456931
    https://www.cnblogs.com/qwertWZ/p/4510857.html
    https://www.cnblogs.com/llhthinker/p/6719779.html

     

    2. Apriori算法

    0x1:Apriori算法中对频繁项集的层级迭代搜索思想

    在上一小节的末尾,我们已经讨论说明了Brute-force在实际中并不可取。我们必须设法降低产生频繁项集的计算复杂度。

    此时我们可以利用支持度对候选项集进行剪枝,它的核心思想是在上一轮中已经明确不能成功频繁项集的项集就不要进入下一轮浪费时间了,只保留上一轮中的频繁项集,在本轮继续进行统计。

    Apriori定律1:如果一个集合是频繁项集,则它的所有子集都是频繁项集

    假设一个集合{A,B}是频繁项集,即A、B同时出现在一条记录的次数大于等于最小支持度min_support,则它的子集{A},{B}出现次数必定大于等于min_support,即它的子集都是频繁项集。

    Apriori定律2:如果一个集合不是频繁项集,则它的所有超集都不是频繁项集

    假设集合{A}不是频繁项集,即A出现的次数小于 min_support,则它的任何超集如{A,B}出现的次数必定小于min_support,因此其超集必定也不是频繁项集

    下图表示当我们发现{A,B}是非频繁集时,就代表所有包含它的超集也是非频繁的,即可以将它们都剪除(剪纸)

    一般而言,关联规则的挖掘是一个两步的过程:

    1. 找出所有的频繁项集
    2. 由频繁项集产生强关联规则

    0x2:挖掘频繁项集

    1. 伪码描述

      • Let k=1:最开始,每个项都是候选1-项集的集合C1的成员
        • Generate frequent itemsets of length k, and Prune candidate itemsets that are infrequent:计算C1每个1-项集的频率,在第一步就要根据支持度阈值对不满足阈值的项集进行剪枝,得到第一层的频繁项
      • Repeat until no new frequent itemsets are identified:迭代过程
        • Generate length (k+1) candidate itemsets from length k frequent itemsets:在上一步k-项集的基础上,算法扫描所有的记录,获得项集的并集组合,生成所有(k+1)-项集。
        • Prune candidate itemsets containing subsets of length k+1 that are infrequent:(k+1)-项集每个项进行计数(根据该项在全量数据集中的频数进行统计)。然后根据最小支持度从(k+1)-项集中删除不满足的项,从而获得频繁(k+1)-项集,Lk+1
      • the finnal k-items:因为Apriori每一步都在通过项集之间的并集操作,以此来获得新的候选项集,如果在某一轮迭代中,候选项集没有新增,则可以停止迭代。因为这说明了在这轮迭代中,通过支持度阈值的剪枝,非频繁项集已经全部被剪枝完毕了,则根据Apriori先验定理2,迭代没有必要再进行下去了。

    下面是一个具体的例子,最开始数据库里有4条交易,{A、C、D},{B、C、E},{A、B、C、E},{B、E},使用min_support=2作为支持度阈值,最后我们筛选出来的频繁集为{B、C、E}。

    2. 一个频繁项集生成的python代码示例

    # coding=utf-8
    from numpy import *
    
    
    def loadDataSet():
        return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
    
    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)
    
    
    # 其中D为全部数据集,
    # # Ck为大小为k(包含k个元素)的候选项集,
    # # minSupport为设定的最小支持度。
    # # 返回值中retList为在Ck中找出的频繁项集(支持度大于minSupport的),
    # # supportData记录各频繁项集的支持度
    def scanD(D, Ck, minSupport):
        ssCnt = {}
        for tid in D:
            for can in Ck:
                if can.issubset(tid):
                    ssCnt[can] = ssCnt.get(can, 0) + 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
    
    
    # 生成 k+1 项集的候选项集
    # 注意其生成的过程中,首选对每个项集按元素排序,然后每次比较两个项集,只有在前k-1项相同时才将这两项合并。
    # # 这样做是因为函数并非要两两合并各个集合,那样生成的集合并非都是k+1项的。在限制项数为k+1的前提下,只有在前k-1项相同、最后一项不相同的情况下合并才为所需要的新候选项集。
    def aprioriGen(Lk, k):
        retList = []
        lenLk = len(Lk)
        for i in range(lenLk):
            for j in range(i + 1, lenLk):
                # 前k-2项相同时,将两个集合合并
                L1 = list(Lk[i])[:k-2]; L2 = list(Lk[j])[: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
    
    
    dataSet = loadDataSet()
    D = map(set, dataSet)
    print dataSet
    print D
    
    C1 = createC1(dataSet)
    print C1    # 其中C1即为元素个数为1的项集(非频繁项集,因为还没有同最小支持度比较)
    
    L1, suppDat = scanD(D, C1, 0.5)
    print "L1: ", L1
    print "suppDat: ", suppDat
    
    
    # 完整的频繁项集生成全过程
    L, suppData = apriori(dataSet)
    print "L: ",L
    print "suppData:", suppData

    最后生成的频繁项集为:

    suppData: 
    frozenset([5]): 0.75, 
    frozenset([3]): 0.75, 
    frozenset([2, 3, 5]): 0.5,
    frozenset([1, 2]): 0.25,
    frozenset([1, 5]): 0.25,
    frozenset([3, 5]): 0.5,
    frozenset([4]): 0.25, 
    frozenset([2, 3]): 0.5, 
    frozenset([2, 5]): 0.75, 
    frozenset([1]): 0.5, 
    frozenset([1, 3]): 0.5, 
    frozenset([2]): 0.75 

    需要注意的是,阈值设置的越小,整体算法的运行时间就越短,因为阈值设置的越小,剪纸会更早介入。

    0x3:从频繁集中挖掘关联规则

    解决了频繁项集问题,下一步就可以解决相关规则问题。

    1. 关联规则来源自所有频繁项集

    从前面对置信度的形式化描述我们知道,关联规则来源于每一轮迭代中产生的频繁项集(从C1开始,因为空集对单项集的支持推导是没有意义的)

    从公式中可以看到,计算关联规则置信度的分子和分母我们都有了,就是上一步计算得到的频繁项集。所以,关联规则的搜索就是围绕频繁项集展开的。

    一条规则 S➞H 的可信度定义为 P(H | S)= support(P 并 S) / support(S)。可见,可信度的计算是基于项集的支持度的

    2. 关联规则的搜索过程

    既然关联规则来源于所有频繁项集 ,那要怎么搜索呢?所有的组合都暴力穷举尝试一遍吗?

    显然不是的,关联规则的搜索一样可以遵循频繁项集的层次迭代搜索方法,即按照频繁项集的层次结构,进行逐层搜索

    3. 关联规则搜索中的剪枝策略

    下图给出了从项集{0,1,2,3}产生的所有关联规则,其中阴影区域给出的是低可信度的规则。可以发现:

    如果{0,1,2}➞{3}是一条低可信度规则,那么所有其他以3作为后件(箭头右部包含3)的规则均为低可信度的。即如果某条规则并不满足最小可信度要求,那么该规则的所有子集也不会满足最小可信度要求。

    反之,如果{0,1,3}->{2},则说明{2}这个频繁项作为后件,可以进入到下一轮的迭代层次搜索中,继续和本轮得到的规则列表的右部进行组合。直到搜索一停止为止

    可以利用关联规则的上述性质属性来减少需要测试的规则数目,类似于Apriori算法求解频繁项集的剪纸策略。

    4. 从频繁项集中寻找关联规则的python示例代码

    # coding=utf-8
    from numpy import *
    
    def loadDataSet():
        return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
    
    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)
    
    
    # 其中D为全部数据集,
    # # Ck为大小为k(包含k个元素)的候选项集,
    # # minSupport为设定的最小支持度。
    # # 返回值中retList为在Ck中找出的频繁项集(支持度大于minSupport的),
    # # supportData记录各频繁项集的支持度
    def scanD(D, Ck, minSupport):
        ssCnt = {}
        for tid in D:
            for can in Ck:
                if can.issubset(tid):
                    ssCnt[can] = ssCnt.get(can, 0) + 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
    
    
    # 生成 k+1 项集的候选项集
    # 注意其生成的过程中,首选对每个项集按元素排序,然后每次比较两个项集,只有在前k-1项相同时才将这两项合并。
    # # 这样做是因为函数并非要两两合并各个集合,那样生成的集合并非都是k+1项的。在限制项数为k+1的前提下,只有在前k-1项相同、最后一项不相同的情况下合并才为所需要的新候选项集。
    def aprioriGen(Lk, k):
        retList = []
        lenLk = len(Lk)
        for i in range(lenLk):
            for j in range(i + 1, lenLk):
                # 前k-2项相同时,将两个集合合并
                L1 = list(Lk[i])[:k-2]; L2 = list(Lk[j])[: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
    
    
    # 频繁项集列表L
    # 包含那些频繁项集支持数据的字典supportData
    # 最小可信度阈值minConf
    def generateRules(L, supportData, minConf=0.7):
        bigRuleList = []
        # 频繁项集是按照层次搜索得到的, 每一层都是把具有相同元素个数的频繁项集组织成列表,再将各个列表组成一个大列表,所以需要遍历Len(L)次, 即逐层搜索
        for i in range(1, len(L)):
            for freqSet in L[i]:
                H1 = [frozenset([item]) for item in freqSet]    # 对每个频繁项集构建只包含单个元素集合的列表H1
                print "\nfreqSet: ", freqSet
                print "H1: ", H1
                rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)     # 根据当前候选规则集H生成下一层候选规则集
        return bigRuleList
    
    
    # 根据当前候选规则集H生成下一层候选规则集
    def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
        m = len(H[0])
        while (len(freqSet) > m):  # 判断长度 > m,这时即可求H的可信度
            H = calcConf(freqSet, H, supportData, brl, minConf)     # 返回值prunedH保存规则列表的右部,这部分频繁项将进入下一轮搜索
            if (len(H) > 1):  # 判断求完可信度后是否还有可信度大于阈值的项用来生成下一层H
                H = aprioriGen(H, m + 1)
                print "H = aprioriGen(H, m + 1): ", H
                m += 1
            else:  # 不能继续生成下一层候选关联规则,提前退出循环
                break
    
    # 计算规则的可信度,并过滤出满足最小可信度要求的规则
    def calcConf(freqSet, H, supportData, brl, minConf=0.7):
        ''' 对候选规则集进行评估 '''
        prunedH = []
        for conseq in H:
            print "conseq: ", conseq
            print "supportData[freqSet]: ", supportData[freqSet]
            print "supportData[freqSet - conseq]: ", supportData[freqSet - conseq]
            conf = supportData[freqSet] / supportData[freqSet - conseq]
            if conf >= minConf:
                print freqSet - conseq, '-->', conseq, 'conf:', conf
                brl.append((freqSet - conseq, conseq, conf))
                prunedH.append(conseq)
                print "prunedH: ", prunedH
        return prunedH
    
    
    
    
    
    dataSet = loadDataSet()
    L, suppData = apriori(dataSet, minSupport=0.5)      # 得到频繁项集列表L,以及每个频繁项的支持度
    print "频繁项集L: "
    for i in L:
        print i
    print "频繁项集L的支持度列表suppData: "
    for key in suppData:
        print key, suppData[key]
    
    # 基于频繁项集生成满足置信度阈值的关联规则
    rules = generateRules(L, suppData, minConf=0.7)
    print "rules = generateRules(L, suppData, minConf=0.7)"
    print "rules: ", rules
    
    
    rules = generateRules(L, suppData, minConf=0.5)
    #print
    #print "rules = generateRules(L, suppData, minConf=0.5)"
    #print "rules: ", rules

    Relevant Link:

    https://blog.csdn.net/baimafujinji/article/details/53456931 
    https://www.cnblogs.com/llhthinker/p/6719779.html
    https://www.cnblogs.com/qwertWZ/p/4510857.html

     

    3. FP-growth算法

    FP-growth算法基于Apriori构建,但采用了高级的数据结构减少扫描次数,大大加快了算法速度。FP-growth算法只需要对数据库进行两次扫描,而Apriori算法对于每个潜在的频繁项集都会扫描数据集判定给定模式是否频繁,因此FP-growth算法的速度要比Apriori算法快。

    FP-growth算法发现频繁项集的基本过程如下:

    1. 构建FP树
    2. 从FP树中挖掘频繁项集

    0x1:FP树数据结构 - 用于编码数据集的有效方式

    在讨论FP-growth算法之前,我们先来讨论FP树的数据结构,可以这么说,FP-growth算法的高效很大程度来源组FP树的功劳。

    FP-growth算法将数据存储在一种称为FP树的紧凑数据结构中。FP代表频繁模式(Frequent Pattern)。FP树通过链接(link)来连接相似元素,被连起来的元素项可以看成一个链表。下图给出了FP树的一个例子。

    与搜索树不同的是,一个元素项可以在一棵FP树种出现多次。FP树辉存储项集的出现频率,而每个项集会以路径的方式存储在树中。

    存在相似元素的集合会共享树的一部分。只有当集合之间完全不同时,树才会分叉。

    树节点上给出集合中的单个元素及其在序列中的出现次数,路径会给出该序列的出现次数。

    相似项之间的链接称为节点链接(node link),用于快速发现相似项的位置。 

    为了更好说明,我们来看用于生成上图的原始事务数据集:

    事务ID事务中的元素项
    001r, z, h, j, p
    002z, y, x, w, v, u, t, s
    003z
    004r, x, n, o, s
    005y, r, x, z, q, t, p
    006y, z, x, e, q, s, t, m

    上图中:

    元素项z出现了5次,集合{r, z}出现了1次。于是可以得出结论:z一定是自己本身或者和其他符号一起出现了4次。

    集合{t, s, y, x, z}出现了2次,集合{t, r, y, x, z}出现了1次,z本身单独出现1次。

    就像这样,FP树的解读方式是:读取某个节点开始到根节点的路径。路径上的元素构成一个频繁项集,开始节点的值表示这个项集的支持度

    根据上图,我们可以快速读出:

    项集{z}的支持度为5;

    项集{t, s, y, x, z}的支持度为2;

    项集{r, y, x, z}的支持度为1;

    项集{r, s, x}的支持度为1。

    FP树中会多次出现相同的元素项,也是因为同一个元素项会存在于多条路径,构成多个频繁项集。但是频繁项集的共享路径是会合并的,如图中的{t, s, y, x, z}和{t, r, y, x, z}

    和Apriori一样,我们需要设定一个最小阈值,出现次数低于最小阈值的元素项将被直接忽略(提前剪枝)。上图中将最小支持度设为3,所以q和p没有在FP中出现。 

    0x2:构建FP树过程

    1. 创建FP树的数据结构

    我们使用一个类表示树结构

    # coding=utf-8
    
    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)
    
    
    rootNode = treeNode('pyramid', 9, None)
    rootNode.children['eye'] = treeNode('eye', 13, None)
    rootNode.children['phoenix'] = treeNode('phoenix', 3, None)
    rootNode.disp()

    2. 构建FP树

    1)头指针表

    FP-growth算法需要一个称为头指针表的数据结构,就是用来记录各个元素项的总出现次数的数组,再附带一个指针指向FP树中该元素项的第一个节点。这样每个元素项都构成一条单链表。图示说明:

    这里使用Python字典作为数据结构,来保存头指针表。以元素项名称为键,保存出现的总次数和一个指向第一个相似元素项的指针。

    第一次遍历数据集会获得每个元素项的出现频率,去掉不满足最小支持度的元素项,生成这个头指针表。这个过程相当于Apriori里的1-频繁项集的生成过程。

    2)元素项排序

    上文提到过,FP树会合并相同的频繁项集(或相同的部分)。因此为判断两个项集的相似程度需要对项集中的元素进行排序。排序基于元素项的绝对出现频率(总的出现次数)来进行。在第二次遍历数据集时,会读入每个项集(读取),去掉不满足最小支持度的元素项(过滤),然后对元素进行排序(重排序)。

    对示例数据集进行过滤和重排序的结果如下:

    事务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

    3)构建FP树

    在对事务记录过滤和排序之后,就可以构建FP树了。从空集开始,将过滤和重排序后的频繁项集一次添加到树中。

    如果树中已存在现有元素,则增加现有元素的值;

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

    对前两条事务进行添加的过程:

    整体算法过程描述如下:

    输入:数据集、最小值尺度
    输出:FP树、头指针表
    1. 遍历数据集,统计各元素项出现次数,创建头指针表
    2. 移除头指针表中不满足最小值尺度的元素项
    3. 第二次遍历数据集,创建FP树。对每个数据集中的项集:
        3.1 初始化空FP树
        3.2 对每个项集进行过滤和重排序
        3.3 使用这个项集更新FP树,从FP树的根节点开始:
            3.3.1 如果当前项集的第一个元素项存在于FP树当前节点的子节点中,则更新这个子节点的计数值
            3.3.2 否则,创建新的子节点,更新头指针表
            3.3.3 对当前项集的其余元素项和当前元素项的对应子节点递归3.3的过程

    实现以上逻辑的py代码逻辑如下:

    # coding=utf-8
    
    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) # 根节点
    
        print dataSet.items()
        for tranSet, count in dataSet.items():  # 第二次遍历数据集,创建FP树
            localD = {} # 对一个项集tranSet,记录其中每个元素项的全局频率,用于排序
            for item in tranSet:
                if item in freqItemSet:
                    localD[item] = headerTable[item][0] # 注意这个[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) # 更新FP树
        return retTree, headerTable
    
    
    def updateTree(items, inTree, headerTable, count):
        if items[0] in inTree.children:
            # 有该元素项时计数值+1
            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函数
            updateTree(items[1::], inTree.children[items[0]], headerTable, count)
    
    
    def updateHeader(nodeToTest, targetNode):
        while (nodeToTest.nodeLink != None):
            nodeToTest = nodeToTest.nodeLink
        nodeToTest.nodeLink = targetNode
    
    
    
    simpDat = loadSimpDat()
    initSet = createInitSet(simpDat)
    myFPtree, myHeaderTab = createTree(initSet, 3)
    myFPtree.disp()

    0x3:从一棵FP树种挖掘频繁项集

    有了FP树之后,接下来可以抽取频繁项集了。这里的思路与Apriori算法大致类似,首先从单元素项集合开始,然后在此基础上逐步构建更大的集合。

    从FP树中抽取频繁项集的三个基本步骤如下:

    1. 从FP树中获得条件模式基;
    2. 利用条件模式基,构建一个条件FP树;
    3. 迭代重复步骤1步骤2,直到树包含一个元素项为止。

    1. 抽取条件模式基

    首先从头指针表中的每个频繁元素项开始,对每个元素项,获得其对应的条件模式基(conditional pattern base)。

    条件模式基是以所查找元素项为结尾的路径集合。每一条路径其实都是一条前缀路径(prefix path)。简而言之,一条前缀路径是介于所查找元素项与树根节点之间的所有内容。

    则每一个频繁元素项的所有前缀路径(条件模式基)为:

    频繁项前缀路径
    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{z, x, y, s}: 2, {z, x, y, r}: 1

    z存在于路径{z}中,因此前缀路径为空,另添加一项该路径中z节点的计数值5构成其条件模式基;

    r存在于路径{r, z}、{r, y, x, z}、{r, s, x}中,分别获得前缀路径{z}、{y, x, z}、{s, x},另添加对应路径中r节点的计数值(均为1)构成r的条件模式基;

    以此类推。

    2. 创建条件FP树

    对于每一个频繁项,都要创建一棵条件FP树。可以使用刚才发现的条件模式基作为输入数据,并通过相同的建树代码来构建这些树。

    例如,对于r,即以“{x, s}: 1, {z, x, y}: 1, {z}: 1”为输入,调用函数createTree()获得r的条件FP树;

    对于t,输入是对应的条件模式基“{z, x, y, s}: 2, {z, x, y, r}: 1”。

    3. 递归查找频繁项集

    有了FP树和条件FP树,我们就可以在前两步的基础上递归得查找频繁项集。

    递归的过程是这样的:

    输入:我们有当前数据集的FP树(inTree,headerTable)
    1. 初始化一个空列表preFix表示前缀
    2. 初始化一个空列表freqItemList接收生成的频繁项集(作为输出)
    3. 对headerTable中的每个元素basePat(按计数值由小到大),递归:
            3.1 记basePat + preFix为当前频繁项集newFreqSet
            3.2 将newFreqSet添加到freqItemList中
            3.3 计算t的条件FP树(myCondTree、myHead)
            3.4 当条件FP树不为空时,继续下一步;否则退出递归
            3.4 以myCondTree、myHead为新的输入,以newFreqSet为新的preFix,外加freqItemList,递归这个过程

    4. 完整FP频繁项集挖掘过程py代码

    # coding=utf-8
    
    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) # 根节点
    
        print dataSet.items()
        for tranSet, count in dataSet.items():  # 第二次遍历数据集,创建FP树
            localD = {} # 对一个项集tranSet,记录其中每个元素项的全局频率,用于排序
            for item in tranSet:
                if item in freqItemSet:
                    localD[item] = headerTable[item][0] # 注意这个[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) # 更新FP树
        return retTree, headerTable
    
    
    def updateTree(items, inTree, headerTable, count):
        if items[0] in inTree.children:
            # 有该元素项时计数值+1
            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函数
            updateTree(items[1::], inTree.children[items[0]], headerTable, count)
    
    
    def updateHeader(nodeToTest, targetNode):
        while (nodeToTest.nodeLink != None):
            nodeToTest = nodeToTest.nodeLink
        nodeToTest.nodeLink = targetNode
    
    
    def findPrefixPath(basePat, treeNode):
        ''' 创建前缀路径 '''
        condPats = {}
        while treeNode != None:
            prefixPath = []
            ascendTree(treeNode, prefixPath)
            if len(prefixPath) > 1:
                condPats[frozenset(prefixPath[1:])] = treeNode.count
            treeNode = treeNode.nodeLink
        return condPats
    
    
    def ascendTree(leafNode, prefixPath):
        if leafNode.parent != None:
            prefixPath.append(leafNode.name)
            ascendTree(leafNode.parent, prefixPath)
    
    
    def mineTree(inTree, headerTable, minSup, preFix, freqItemList):
        bigL = [v[0] for v in sorted(headerTable.items(), key=lambda p: p[1])]
        for basePat in bigL:
            newFreqSet = preFix.copy()
            newFreqSet.add(basePat)
            freqItemList.append(newFreqSet)
            condPattBases = findPrefixPath(basePat, headerTable[basePat][1])
            myCondTree, myHead = createTree(condPattBases, minSup)
    
            if myHead != None:
                # 用于测试
                print 'conditional tree for:', newFreqSet
                myCondTree.disp()
    
                mineTree(myCondTree, myHead, minSup, newFreqSet, freqItemList)
    
    
    def fpGrowth(dataSet, minSup=3):
        initSet = createInitSet(dataSet)
        myFPtree, myHeaderTab = createTree(initSet, minSup)
        freqItems = []
        mineTree(myFPtree, myHeaderTab, minSup, set([]), freqItems)
        return freqItems
    
    
    dataSet = loadSimpDat()
    freqItems = fpGrowth(dataSet)
    print freqItems

    FP-growth算法是一种用于发现数据集中频繁模式的有效方法。FP-growth算法利用Apriori原则,执行更快。Apriori算法产生候选项集,然后扫描数据集来检查它们是否频繁。由于只对数据集扫描两次,因此FP-growth算法执行更快。在FP-growth算法中,数据集存储在一个称为FP树的结构中。FP树构建完成后,可以通过查找元素项的条件基及构建条件FP树来发现频繁项集。该过程不断以更多元素作为条件重复进行,直到FP树只包含一个元素为止。

    Relevant Link: 

    https://www.cnblogs.com/qwertWZ/p/4510857.html

     

    4. 支持度-置信度框架的瓶颈 - 哪些模式是有趣的?强规则不一定是有趣的?

    0x1:支持度-置信度框架的瓶颈

    关联规则挖掘算法基本都使用支持度-置信度框架。但是在实际工程项目中,我们可能会期望从数据集中挖掘潜在的未知模式(0day),但是低支持度阈值挖掘或挖掘长模式时,会产生很多无趣的规则,这是关联规则挖掘应用的瓶颈之一。

    基于支持度-置信度框架识别出的强关联规则,不足以过滤掉无趣的关联规则,它可能仅仅是数据集中包含的一个显而易见的统计规律,或者仅仅是我们传入的数据集中包含了脏数据。统计有时候就是魔鬼。

    0x2:相关性度量 - 提升度(lift)

    为识别规则的有趣性,需使用相关性度量来扩充关联规则的支持度-置信度框架。

    相关规则不仅用支持度和置信度度量,而且还用项集A和B之间的相关性度量。一个典型的相关性度量的方法是:提升度(lift)

    1. A 和 B是互相独立的:P(A∪B) = P(A)P(B);
    2. 项集A和B是依赖的(dependent)和相关的(correlated):P(A∪B) != P(A)P(B);

    A和B出现之间的提升度定义为:lift(A,B) = P(A∪B) / P(A) * P(B)

    如果lift(A,B)<1,则说明A的出现和B的出现是负相关的;

    如果lift(A,B)>1,则A和B是正相关的,意味每一个的出现蕴涵另一个的出现;

    如果lift(A,B)=1,则说明A和B是独立的,没有相关性。

    Relevant Link:

    https://blog.csdn.net/fjssharpsword/article/details/78291638
    https://blog.csdn.net/dq_dm/article/details/38145075

     

    5. 在实际工程项目中的思考

    0x1:你的输入数据集是什么?是否单纯?包含了哪些概率分布假设?

    在实际的机器学习工程项目中,要注意的一点是,Apriori和FP-growth是面向一个概率分布纯粹的数据集进行共现模式和关联模式的挖掘的,例如商品交易数据中,所有的每一条数据都是交易数据,算法是从这些商品交易数据中挖掘有趣关系。

    如果要再入侵检测场景中使用该算法,同样也要注意纯度的问题,不要引入噪音数据,例如我们提供的数据集应该是所有发生了异常入侵事件的时间窗口内的op序列,这里单个op序列可以抽象为商品单品,每台机器可以抽象为一次交易。这种假设没太大问题。它基于的假设是全网的被入侵服务器,在大数据的场景下,都具有类似的IOC模式。

    记住一句话,关联分析算法只是在单纯从统计机器学习层面去挖掘数据集中潜在的规律和关联,你传入什么数据,它就给你挖掘出什么。所以在使用算法的时候,一定要思考清楚你传入的数据意味着什么?数据中可能蕴含了哪些规则但是你不想或者没法人肉地去自动化挖掘出来,算法只是帮你自动化地完成了这个过程,千万不能把算法当成魔法,把一堆数据扔进去,妄想可以自动挖掘出0day。

    0x2:频繁项集和关联规则对你的项目来说意味着什么?

    关联挖掘算法是从交易数据商机挖掘的场景中被开发出来的,它的出发点是找到交易数据中的伴随购买以及购买推导关系链。这种挖掘模式在其他项目中是否能映射到一个类似的场景?这是需要开发者要去思考的。

    例如,在入侵检测场景中,我们通过Apriori挖掘得到的频繁项集和关联规则可能是如下的形式:

    这种结果的解释性在于:
    入侵以及伴随入侵的恶意脚本植入及执行,都是成对出现的,并且满足一定的先后关系。

    但是在入侵检测领域,我们知道,一次入侵往往会通过包含多种指令序列模式,我们并不需要强制在一个机器日志中完整匹配到整个频繁项集。
    一个可行的做法是:
    只取算法得到结果的1-频繁项集或者将所有k-频繁项集split拆分成1-频繁项集后,直接根据1-频繁项集在原始日志进行匹配,其实如果只要发现了一个频繁项集对应的op seq序列,基本上就是认为该时间点发生了入侵事件。

    0x3:其他思考

    项目开发过程中,我们发现有一篇paper用的方案是非常类似的,只是业务场景稍有不同。

    http://www.paper.edu.cn/scholar/showpdf/NUD2UNyINTz0MxeQh

    它这有几点很有趣的,值得去思考的:

    1. 利用关联挖掘算法先挖掘出正常行为模式,用于进行白名单过滤
    2. 加入了弱规则挖掘,即低支持度,高置信度的弱规则。根据网络攻击的实际特点,有些攻击是异常行为比较频繁的攻击,如DDOS攻击等,通过强规则挖掘能检测出此类攻击;而有些攻击异常行为不太频繁,如慢攻击在单位时间内异常扫描数量很少。强规则挖掘适合抓出批量大范围行为,弱规则挖矿适合抓出0day攻击
    3. 下游stacking了贝叶斯网络来进行异常行为的最终判断

     

    展开全文
  • 条码库存管理

    千次阅读 2011-10-24 17:07:20
    库存管理系统包括:从供应商开始到向生产线出库结束的整个过程的管理。  入库接收时发行条形码标签,为部品分配... 在库存管理中可能存在的问题:  ·库房管理难以做到帐面数量和实物数量相符  ·库房管理人
  • Apriori算法目录一、前言二、关联分析三、Apriori原理四、利用Apriori算法来发现频繁集1、Apriori算法及实例描述2、生成候选项集2、组织完整的Apriori算法五、从频繁项集中挖掘关联规则六、示例1:发现国会投票的...
  • 使用Apriori关联规则算法实现购物篮分析

    千次阅读 多人点赞 2020-11-19 15:19:26
    购物篮分析是通过发现顾客一次购买行为放入购物篮不同商品之间的关联,研究客户的购买行为,从而辅助零售企业制定营销策略的一种数据分析方法。 本章使用Apriori关联规则算法实现购物篮分析,发现超市不同商品...
  • 由于该软件设计之初就立足解决各子公司的物资库存管理问题,当该软件后期需要集团内推广,以及集团采购部提出以集团层面进行管控的时候,原有设计不能满足集团化的管理,因此继续进行扩展及升级有很大难度,且需要...
  • 库存管理的ABC分析法 库存费用分析 平均库存概念 经济订货量(EOQ) 经济订货量(EOQ)公式的典型应用示例 最佳订货批量 每次订货的最佳总金额 最佳订货次数 订货时间确定 真题 库存管理的作用和意义 库存管理的作用...
  • 基于web的库存管理系统

    千次阅读 2021-02-21 21:38:26
    该系统可以实现对仓库的基本维护,例如,对仓库和货物信息进行添加、删除、修改和查询等功能;同时也可满足仓库的基本管理,如:进出货时更改仓库信息及对货物销售情况进行统计等。 基于web的购.
  • ERP : 库存管理的基本原理

    千次阅读 2019-05-29 21:55:57
    2.同作业有关的人将说库存是成品、原材料、制品或产品使用的物料。 这种财务观点是一种真正的自相矛盾。毫无疑问库存具有价值,特别是当买进或卖出公 司时,它们的价值总是表示资产负债平衡表上资产的一方。...
  • 21世纪的今天,ERP系统已经成为工业行业提高经济效益和解决管理难题的重要工具,为了全面满足工业行业对ERP系统的需求,智邦国际为此针对性的研发了一款ERP系统,能够从根本解决工业行业面临的各种管理问题,比如...
  • 仓库管理系统(Warehouse Management System,简称WMS)是通过出库、入库、库位调拨、库存调拨等功能,综合批次管理、物料对应、库存盘点、质检管理和即时库存管理等功能综合运用的管理系统。WMS属于电...
  • 收货比较好理解,有此采购物资比较零碎,如办公用品,因此系统采购订单,通常不会作细目管理。而是直接与供应商系统外通过纸置交货单来对账,系统内就不做收货,仅做发票校验付款。但什么是非评估收货,其...
  • 文章目录数据建模基础大数据分析场景和模型应用常见的数据建模分类分类与回归应用:原理:区别:聚类应用:原理:时序模型应用:原理:常见的数据分析应用场景如下:市场营销风险管理 数据建模基础 大数据分析场景和...
  •  数据分析是当前企业管理过程不容忽视的重要支撑点,企业需要有完整、真实、有效的数据进行支撑,企业需要使用大量的数据,才能够对未来行业的发展趋势进行有效的预测,从而采取积极的应对措施,制定良好的战略。...
  • 本系统客户需求的基础上,主要需要实现以下...规范管理产品组成(BOM),要求做销售订单的时候,只要录入成品名称,就拉出相应内容物。(由于客户产品的特殊性,成品包含内容物、包材、彩盒等,订单里只显示内容物,
  • 数据挖掘(Data Mining,DM)又被称为数据库的知识发现(Knowledge Discovery from DataBase,KDD),是指从大量数据提取隐含的、先前未知的、有价值的知识和规则。 它是人工智能和数据库发展相结合的产物,是...
  • 原文出处:Use the Library to Create Associative Containers 摘要:当索引是整型,那么将值与之关联并不难,但如果数据的关联值对是其它数据类型怎么办呢?库具备一个关联容器,使用它可以很方便地关联所有类型的...
  • 项目质量管理 试题分析

    千次阅读 2017-02-20 21:12:28
    问题的原因,这属于质量管理中的(13)。 (13)A.质量计划编制 B.质量工具 C.质量保证 D.质量控制试题 11 分析 质量控制过程,有“老七种工具”:因果图、流程图、直方图、检查表、散点图、排列图和控制图,...
  • XML数据传输的安全加密第二部分郭路Technical Manager2001 年 6 月 布式多层系统是目前企业级大应用中最流行的架构,而XML则是计算机数据处理的最新技术,强强联手能产生多大的化学效应;作为新的数据处理标准...
  • 3.3 生产管理系统需求分析

    万次阅读 2007-09-17 08:31:00
    根据以上对生产管理内容和生产管理系统的分析,一个标准的MRP生产管理系统应该包括如图3.12所示的几大功能。除此之外系统还应包括信息系统必须具备的通用功能,例如系统管理、权限设置、数据备份与恢复等,这些功能...
  • 可视化分析领导者Qlik®今天宣布发布2017年6月版Qlik Sense®,这是自助服务商业智能(BI)和可视化分析下一代应用的最新版本。Qlik Sense采用全面集成的云就绪平台进行开发,并由获得专利的QIX关联索引引擎提供支持...
  • 今天就就来谈谈能源化工生产管理数据分析,说是能源化工业,但其他行业也都可参考! 能源化工行业有什么特点? 能源化工行业资源密集、技术密集、设备密集、人员密集、高度封闭。 能源化工生产管理有什么特点? ...
  • 二、操作型数据与分析型数据对比、 三、数据仓库 特征 与 定义、 四、特征一 : 面向主题 数据组织方式、 五、面向应用 数据组织方式、 六、面向主题 组织数据、 七、数据 从 面向应用 转为 面向主题、 七、数据仓库...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,134
精华内容 4,853
关键字:

关联分析在库存管理中的应用