精华内容
下载资源
问答
  • 映美fp700k打印机驱动是fp700k型号打印的必要程序,它可以有效地解决电脑不能正常识别打印机或不能正常连接等导致不能正常打印的问题,欢迎有需要的朋友下载使用!官方介绍FP-700K+是映美根据各行业的各类应用个性...
  • FP算法

    万次阅读 2011-10-17 22:13:51
    Apriori算法和FPTree算法都是数据挖掘中的关联规则挖掘算法,处理的都是最简单的单层单维布尔关联规则。 转自http://blog.csdn.net/sealyao/article/details/6460578 Apriori算法 Apriori算法是一种最有影响的...

    Apriori算法和FPTree算法都是数据挖掘中的关联规则挖掘算法,处理的都是最简单的单层单维布尔关联规则。

    转自http://blog.csdn.net/sealyao/article/details/6460578

    Apriori算法

    Apriori算法是一种最有影响的挖掘布尔关联规则频繁项集的算法。是基于这样的事实:算法使用频繁项集性质的先验知识。Apriori使用一种称作逐层搜索的迭代方法,k-项集用于探索(k+1)-项集。首先,找出频繁1-项集的集合。该集合记作L1L1用于找频繁2-项集的集合L2,而L2用于找L3,如此下去,直到不能找到频繁k-项集。找每个Lk需要一次数据库扫描。

    这个算法的思路,简单的说就是如果集合I不是频繁项集,那么所有包含集合I的更大的集合也不可能是频繁项集。

    算法原始数据如下:

    TID

    List of item_ID’s

    T100

    T200

    T300

    T400

    T500

    T600

    T700

    T800

    T900

    I1,I2,I5

    I2,I4

    I2,I3

    I1,I2,I4

    I1,I3

    I2,I3

    I1,I3

    I1,I2,I3,I5

    I1,I2,I3

    算法的基本过程如下图:

    image

    首先扫描所有事务,得到1-项集C1,根据支持度要求滤去不满足条件项集,得到频繁1-项集。

    下面进行递归运算:

    已知频繁k-项集(频繁1-项集已知),根据频繁k-项集中的项,连接得到所有可能的K+1_项,并进行剪枝(如果该k+1_项集的所有k项子集不都能满足支持度条件,那么该k+1_项集被剪掉),得到clip_image002项集,然后滤去该clip_image002[1]项集中不满足支持度条件的项得到频繁k+1-项集。如果得到的clip_image002[2]项集为空,则算法结束。

    连接的方法:假设clip_image004项集中的所有项都是按照相同的顺序排列的,那么如果clip_image004[1][i]和clip_image004[2][j]中的前k-1项都是完全相同的,而第k项不同,则clip_image004[3][i]和clip_image004[4][j]是可连接的。比如clip_image006中的{I1,I2}和{I1,I3}就是可连接的,连接之后得到{I1,I2,I3},但是{I1,I2}和{I2,I3}是不可连接的,否则将导致项集中出现重复项。

    关于剪枝再举例说明一下,如在由clip_image006[1]生成clip_image008的过程中,列举得到的3_项集包括{I1,I2,I3},{I1,I3,I5},{I2,I3,I4},{I2,I3,I5},{I2,I4,I5},但是由于{I3,I4}和{I4,I5}没有出现在clip_image006[2]中,所以{I2,I3,I4},{I2,I3,I5},{I2,I4,I5}被剪枝掉了。

    海量数据下,Apriori算法的时空复杂度都不容忽视。

    空间复杂度:如果clip_image010数量达到clip_image012的量级,那么clip_image014中的候选项将达到clip_image016的量级。

    时间复杂度:每计算一次clip_image018就需要扫描一遍数据库。

    FP-Tree算法

    FPTree算法:在不生成候选项的情况下,完成Apriori算法的功能。

    FPTree算法的基本数据结构,包含一个一棵FP树和一个项头表,每个项通过一个结点链指向它在树中出现的位置。基本结构如下所示。需要注意的是项头表需要按照支持度递减排序,在FPTree中高支持度的节点只能是低支持度节点的祖先节点。

    image

    另外还要交代一下FPTree算法中几个基本的概念:

    FP-Tree:就是上面的那棵树,是把事务数据表中的各个事务数据项按照支持度排序后,把每个事务中的数据项按降序依次插入到一棵以NULL为根结点的树中,同时在每个结点处记录该结点出现的支持度。

    条件模式基:包含FP-Tree中与后缀模式一起出现的前缀路径的集合。也就是同一个频繁项在PF树中的所有节点的祖先路径的集合。比如I3在FP树中一共出现了3次,其祖先路径分别是{I2,I1:2(频度为2)},{I2:2}和{I1:2}。这3个祖先路径的集合就是频繁项I3的条件模式基。

    条件树:将条件模式基按照FP-Tree的构造原则形成的一个新的FP-Tree。比如上图中I3的条件树就是:

    image

     

    1、 构造项头表:扫描数据库一遍,得到频繁项的集合F和每个频繁项的支持度。把F按支持度递降排序,记为L。

    2、 构造原始FPTree:把数据库中每个事物的频繁项按照L中的顺序进行重排。并按照重排之后的顺序把每个事物的每个频繁项插入以null为根的FPTree中。如果插入时频繁项节点已经存在了,则把该频繁项节点支持度加1;如果该节点不存在,则创建支持度为1的节点,并把该节点链接到项头表中。

    3、 调用FP-growth(Tree,null)开始进行挖掘。伪代码如下:

    procedure FP_growth(Treea)

    if Tree 含单个路径then{

             for 路径P中结点的每个组合(记作b

             产生模式b U a,其支持度support = 中结点的最小支持度;

    } else {

             for each i 在Tree的头部(按照支持度由低到高顺序进行扫描){

                      产生一个模式b = i U a,其支持度support .support

                      构造b的条件模式基,然后构造b的条件FP-树Treeb;

                      if Treeb 不为空 then

                                调用 FP_growth (Treeb, b);

               }

    }

    FP-growth是整个算法的核心,再多啰嗦几句。

    FP-growth函数的输入:tree是指原始的FPTree或者是某个模式的条件FPTree,a是指模式的后缀(在第一次调用时a=NULL,在之后的递归调用中a是模式后缀)

    FP-growth函数的输出:在递归调用过程中输出所有的模式及其支持度(比如{I1,I2,I3}的支持度为2)。每一次调用FP_growth输出结果的模式中一定包含FP_growth函数输入的模式后缀。

    我们来模拟一下FP-growth的执行过程。

    1、 在FP-growth递归调用的第一层,模式前后a=NULL,得到的其实就是频繁1-项集。

    2、 对每一个频繁1-项,进行递归调用FP-growth()获得多元频繁项集。

    下面举两个例子说明FP-growth的执行过程。

    1、I5的条件模式基是(I2 I1:1), (I2 I1 I3:1),I5构造得到的条件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}。

    绘图1

    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}

          image         绘图2




                                             图1                                                                     图2

     

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

    item

    条件模式基

    条件FP-树

    产生的频繁模式

    I5

    I4

    I3

    I1

    {(I2 I1:1),(I2 I1 I3:1)

    {(I2 I1:1), (I2:1)}

    {(I2 I1:2), (I2:2), (I1:2)}

    {(I2:4)}

    <I2:2, I1:2>

    <I2:2>

    <I2:4, I1:2>, <I1:2>

    <I2:4>

    I2 I5:2, I1 I5:2, I2 I1 I5:2

    I2 I4:2

    I2 I3:4, I1 I3:4, I2 I1 I3:2

    I2 I1:4

    FP-growth算法比Apriori算法快一个数量级,在空间复杂度方面也比Apriori也有数量级级别的优化。但是对于海量数据,FP-growth的时空复杂度仍然很高,可以采用的改进方法包括数据库划分,数据采样等等。

    展开全文
  • Spark MLlib中FPGrowth和FPTree详解之二

    千次阅读 2016-08-20 20:35:49
    这一章节,主要介绍FPGrowth源码,以及运行过程演示 2.3 FPGrowth源码详解 run方法是FPGrowth的入口函数,其代码注释如下: /**  * Computes an FP-Growth model that contains frequent itemsets.  * @...

    这一章节,主要介绍FPGrowth源码,以及运行过程演示

    2.3 FPGrowth源码详解

    run方法是FPGrowth的入口函数,其代码注释如下:

    /**

      * Computes an FP-Growth model that contains frequent itemsets.

      * @param data input data set, each element contains a transaction

      * @return an [[FPGrowthModel]]

      *

      */

     @Since("1.3.0")

     defrun[Item: ClassTag](data: RDD[Array[Item]]): FPGrowthModel[Item] = {

       if(data.getStorageLevel == StorageLevel.NONE) {

         logWarning("Input data is notcached.")

       }

       valcount= data.count()

       valminCount= math.ceil(minSupport* count).toLong

       valnumParts= if(numPartitions> 0) numPartitions else data.partitions.length //获取分区数(PFP算法中的分组)

       valpartitioner= newHashPartitioner(numParts)

       valfreqItems= genFreqItems(data, minCount, partitioner)//生成频繁项

       valfreqItemsets= genFreqCloseItemsets_V1(data, minCount, freqItems,partitioner)//生成频繁项集

    //      genFreqItemsets(data, minCount,freqItems, partitioner)

       newFPGrowthModel(freqItemsets)

      }

     

             Sparkmllib中的算法通常都是调用run方法,然后返回一个模型。本章中,我们测试运行的代码如下:

     

    def main(args: Array[String]) {

       valsc = new SparkContext(new SparkConf().setMaster("local[*]").setAppName("test"))

     sc.setLogLevel("WARN")

     valdata= sc.textFile("F:/test/fpg/data.txt")

       .map(_.split(" ")).cache

     valmodel= newFPGrowth().setMinSupport(0).setNumPartitions(3).run(data)

     model.freqItemsets.collect.filter(_.items.size >= 1).foreach(f => println(f.items.mkString(",")+"->"+f.freq))

      }

     

    其中,参数minSupport设置为0,保留所有项;partition设置为3,也就是将所有项划分到3个组中,至于具体的分组情况。可以调用mapPartitionWithIndex方法来查看。对于,本章使用的数据集,分组情况如下所示:

    0号:I2, I5

    1号:I3, I4

    3号:I1

             其他同道们如果跟我一样的数据集和分区数的话,应该也是相关分组情况。所以,接下来我会以这个分区情况来进行示例。

     

    genFreqItems容易理解,就是统计所有项的频次,并筛选出满足条件的频繁项。这个方法里面还做的一件事就是利用HashPartitioner将各个item划分到不同的分区中。(为什么用hash,还有数据倾斜之类的问题这里就不考虑啦!)。其代码注释如下:

    /**

      * Generates frequent items by filtering the input data using minimal support level.

      * @param minCount minimum count for frequent itemsets

      * @param partitioner partitioner used to distribute items

      * @return array of frequent pattern ordered by their frequencies

      */

     privatedefgenFreqItems[Item:ClassTag](

         data: RDD[Array[Item]],

         minCount: Long,

         partitioner: Partitioner): Array[Item] = {

       data.flatMap { t =>

         valuniq= t.toSet

         if(t.size != uniq.size){ //这里注意一条事务的项不能有重复,否则会报错

            throw new SparkException(s"Items in atransaction must be unique but got ${t.toSeq}.")

         }

         t

       }.map(v => (v, 1L))

         .reduceByKey(partitioner, _ + _) //将每一个item根据hash分配到各个分区,并求其频次

         .filter(_._2>= minCount)

         .collect()

         .sortBy(-_._2)//按频次降序排列

         .map(_._1)

      }

             该方法对样本数据进行划分和统计的结果如下表所示:

    TID

    商品ID的列表

    排序后的ID与对应组ID

    基于Q对事务进行划分

    T100

    I1,I2,I5

    I2, I1, I5 -> Q0, Q2, Q0

    Q0->{I2, I1, I5 }, Q2->{I2, I1}

    T200

    I2,I4

    I2, I4 -> Q0, Q1

    Q0->{I2}, Q1->{I2, I4}

    T300

    I2,I3

    I2, I3 -> Q0, Q1

    Q0->{I2}, Q1->{I2, I3}

    T400

    I1,I2,I4

    I2, I1, I4 -> Q0, Q2, Q1

    Q0->{I2}, Q1->{I2, I1, I4}, Q2->{I2, I1}

    T500

    I1,I3

    I1, I3 -> Q2, Q1

    Q1->{I1, I3}, Q2->{I1}

    T600

    I2,I3

    I2, I3 -> Q0, Q1

    Q1->{I2, I3}, Q0->{I2}

    T700

    I1,I3

    I1, I3 -> Q2, Q1

    Q1->{I1, I3}, Q2->{I1}

    T800

    I1,I2,I3,I5

    I2, I1, I3, I5 -> Q0, Q2, Q1,Q0

    Q0->{I2, I1,I3, I5 },

    Q1->{I2,I1,I3},

    Q2->{I2, I1}

    T900

    I1,I2,I3

    I2, I1, I3 ->  Q0, Q2, Q1

    Q1->{I2,I1,I3}, Q2->{I2, I1}, Q0->{I2}

    F-list

    I2:7 I1:6 I3:6 I4:2 I5:2

    Q-list

    Q0:{I2, I5} Q1:{I3, I4} Q2:{I1}

     

     

     

    /**

      * Generates conditional transactions.

      * 这里面有一个技巧:就是在生成条件事务的时候,itemToRankfreqItemset用其对应的下标来映射。

      * 所以每条事务进过筛选并按freqItemset中的频次重排之后,以item对应的下标来输出

      * @param transaction a transaction

      * @param itemToRank map from item to their rank

      * @param partitioner partitioner used to distribute transactions

      * @return a map of (target partition, conditional transaction)

      */

     privatedefgenCondTransactions[Item: ClassTag](

         transaction: Array[Item],

         itemToRank: Map[Item, Int],

         partitioner: Partitioner): mutable.Map[Int, Array[Int]] = {

       valoutput= mutable.Map.empty[Int, Array[Int]]

       // Filter the basket by frequent itemspattern and sort their ranks.

       /**

         * 假设事务为I1,I2,I5, 其中itemToRank中只有{I2->0, I1->1}

         * 那么itemToRank.get对这三项取得的值为 {1,0,option(null)},经过flatMap展平后

         * 得到的filtered中为:Array(1, 0)

         * 再经过sort变成Array(0, 1)

         */

       valfiltered= transaction.flatMap(itemToRank.get)

       ju.Arrays.sort(filtered) //按照itemToRank重新排序

       valn = filtered.length

       vari = n - 1

       while(i >= 0) {

         valitem= filtered(i)

         valpart= partitioner.getPartition(item)

         if(!output.contains(part)) {

            output(part) = filtered.slice(0, i + 1)

         }

         i -= 1

       }

       output

      }

     

    /**

      * Generate frequent itemsets by building FP-Trees, the extraction isdone on each partition.

      * @param data transactions

      * @param minCount minimum count for frequent itemsets

      * @param freqItems frequent items

      * @param partitioner partitioner used to distribute transactions

      * @return an RDD of (frequent itemset, count)

      */

     privatedefgenFreqItemsets[Item: ClassTag](

         data: RDD[Array[Item]],

         minCount: Long,

         freqItems: Array[Item],

         partitioner: Partitioner): RDD[FreqItemset[Item]] = {

       valitemToRank= freqItems.zipWithIndex.toMap

       data/*input:RDD[Array[Item]]*/

       .flatMap { transaction =>

         genCondTransactions(transaction, itemToRank, partitioner) //(part:分区号, array[int]:事务)

       }/*output: RDD[(part, Array[Int])]*/

       //aggregateByKey的作用是对每个分区及其包含的所有事务,构建一颗FPTree

       .aggregateByKey(new FPTree[Int], partitioner.numPartitions)(

         (tree, transaction) => tree.add(transaction, 1L), //一条事务作为只有一条分支的树

         (tree1, tree2) => tree1.merge(tree2))           //所有单分支树进行合并成为一颗树(各个分区分别进行这两个操作)

       .flatMap { case (part,tree)=>

         //分别从各个分区对应树进行频繁模式抽取

         tree.extract(minCount,x => partitioner.getPartition(x) == 0)

       }.map { case(ranks,count)=>

         newFreqItemset(ranks.map(i=> freqItems(i)).toArray, count)//将下标转换成其对应的item

       }

      }

    下图给出了aggregateByKey中运行情况的演示


    然后,接下来的两幅图以0号分区为例,展示了频繁模式抽取的过程。


    展开全文
  • Spark MLlib中FPGrowth和FPTree详解之一

    千次阅读 2016-08-20 00:31:42
    一、准备知识 1.1 Scala版本:2.10.4 1.2 Spark版本:1.5.0 Spark中实现关联规则算法的包是:org.apache.spark.mllib.fpm。包中的文件如下图所示: ...1.3 频繁模式增长FP-Growth 要理解Spark MLlib中FPGro

    一、准备知识

    1.1 Scala版本:2.10.4

    1.2 Spark版本:1.5.0

    Spark中实现关联规则算法的包是:org.apache.spark.mllib.fpm。包中的文件如下图所示:


    这里面我重点讲解红色箭头指向的两个代码文件。讲解过程中如果有误解的地方,还请评论指正,谢谢!

    1.3 频繁模式增长FP-Growth

    要理解Spark MLlib中FPGrowth和FPTree中的源码,首先在理论上要有一定的基础。首先就是韩教授他们发明的基于频繁模式树的关联规则挖掘算法。这里就不细表了,只要记得如下图的频繁模式树的原理就行。友情提醒:结点链和叶子结点对理解源码很有帮助


    注:摘自韩家炜《数据挖掘》

    图中的数据样本也是我们等下理解源码进行测试的数据样本,样本如下表所示

    测试样本

    TID

    商品ID的列表

    T100

    I1,I2,I5

    T200

    I2,I4

    T300

    I2,I3

    T400

    I1,I2,I4

    T500

    I1,I3

    T600

    I2,I3

    T700

    I1,I3

    T800

    I1,I2,I3,I5

    T900

    I1,I2,I3

    1.4 并行频繁模式增长PFP-Growth

    Spark MLlib中的FPGrowth一个并行化的版本实现,在其注释中也提到了实现算法的出处。摘录如下,红色字体为文献标题。

    /**

     *

     * Aparallel FP-growth algorithm to mine frequent itemsets. The algorithm isdescribed in

     *[[http://dx.doi.org/10.1145/1454008.1454027 Li et al., PFP: Parallel FP-Growth for Query

     *  Recommendation]].PFP distributes computation in such a way that each worker executes an

     *independent group of mining tasks. The FP-Growth algorithm is described in

     *[[http://dx.doi.org/10.1145/335191.335372 Han et al., Mining frequent patternswithout candidate

     * generation]].

     *

     *@param minSupport the minimal support level of the frequent pattern, anypattern appears

     *                   more than (minSupport *size-of-the-dataset) times will be output

     *@param numPartitions number of partitions used by parallel FP-growth

     *

     *@see [[http://en.wikipedia.org/wiki/Association_rule_learning Association rulelearning

     *      (Wikipedia)]]

     *

     */

    所以在开始阅读源码之前,最好还是先读几遍相关的文献。在下面的章节中,我会以刚才的样本为例,演示一下PFP的过程,如果读过该文献,理解起来应该还是容易的。因为文献是英文,这里大致讲解一下过程:

    •步骤1:sharding(碎片化)
    •步骤2:ParallelCounting(并行计数)
    •步骤3:GroupingItems(项分组)
    •步骤4:ParallelFP-Growth(并行的FP-Growth)
    •步骤5:Aggregating(聚合)

    以样本数据集为例,其运行过程如下所示:

    TID

    商品ID的列表

    排序后的ID与对应组ID

    基于Q对事务进行划分

    T100

    I1,I2,I5

    I2, I1, I5 -> Q1, Q1, Q3

    Q3->{I2, I1, I5 }, Q1->{I2, I1}

    T200

    I2,I4

    I2, I4 -> Q1, Q2

    Q2->{I2, I4}, Q1->{I2}

    T300

    I2,I3

    I2, I3 -> Q1, Q2

    Q2->{I2, I3}, Q1->{I2}

    T400

    I1,I2,I4

    I2, I1, I4 -> Q1, Q1, Q2

    Q2->{I2, I1, I4}, Q1->{I2, I1}

    T500

    I1,I3

    I1, I3 -> Q1, Q2

    Q2->{I1, I3}, Q1->{I1}

    T600

    I2,I3

    I2, I3 -> Q1, Q2

    Q2->{I2, I3}, Q1->{I2}

    T700

    I1,I3

    I1, I3 -> Q1, Q2

    Q2->{I1, I3}, Q1->{I1}

    T800

    I1,I2,I3,I5

    I2, I1, I3, I5 -> Q1, Q1, Q2,Q3

    Q3->{I2, I1,I3, I5 },

    Q2->{I2,I1,I3},

    Q1->{I2, I1}

    T900

    I1,I2,I3

    I2, I1, I3 ->  Q1, Q1, Q2

    Q2->{I2,I1,I3}, Q1->{I2, I1}

    F-list

    I2:7 I1:6 I3:6 I4:2 I5:2

    Q-list

    Q1:{I2, I1} Q2:{I3, I4} Q3:{I5}


    其中,F-list为排序后的项;Q-list是对所有item进行分组的情况。表中第四列,是第三列中每一行从右往左遍历直到第一个组号出现时,将其前面的项和该项作为一种划分的情况。最终,程序先将组进行合并,然后在每一组内进行FPTree的创建,并通过FPGrowth得到频繁模式。

    二、源码详解

    2.1 首先给出这两个代码文件的概览,如下表所示,对源码进行的分解说明。


    FPGrowth和FPTree源码概览

    2.2 FPTree源码详解

    FPTree.scala中定义了FPTree类和它的单例对象。

    而在单例对象中又定义了两个类。一个是Node类,顾名思义,就是表示树上的结点。具体的说明见下面的注释

    /**

       * Representing a node in an FP-Tree.

       * @paramparent该结点的父结点

       */

      class Node[T](valparent: Node[T])extends Serializable {

        var item: T = _         //结点中包含的项(商品)

        var count: Long = 0L    //对应的计数

       

        /**

         * children表示孩子结点,用一个item->Node[item]的映射表示

         * 根据FPTree的特点,一个结点的孩子结点中包含的项item肯定是互不相同的;

         * 或者一个item在树的每一层最多只能出现一次,在树的每个分枝也只可能出现一次

         */

        val children: mutable.Map[T, Node[T]] = mutable.Map.empty

     

        def isRoot: Boolean =parent ==null//判断是否到达根结点

      }

    这里要注意的是不同的Node可以由相同的item构成,比如下图中框出来存在于不同分枝的I5结点。而连接这两个Node的虚线其实就是接下来要介绍的另一个类Summary。



    包含相同item的不同Nodes

    Summary是单例对象中另一个类,其注释如下:

    /**

       * Summary of a item in an FP-Tree.

       * 就是同一个项item对应的结点链

       */

      private class Summary[T] extendsSerializable {

        var count: Long = 0L //item(商品)在数据样本(transactions)中出现的次数

        val nodes: ListBuffer[Node[T]] = ListBuffer.empty //FPTree中包该item的所有结点列表

      }

     

        理解了这两个类之后,我们再来看FPTree这个关键类。

        首先类成员变量包括一个root和summaries. Summaries定义如下,是所有item到它的结点链的映射。

    private val summaries: mutable.Map[T, Summary[T]] = mutable.Map.empty

    下图中的列表是比较形象的理解。



    Summaries的形象化理解

     

        接下来的一些方法,这里只给出一些注释,具体的运行过程在测试样本(第二章)的时候再讲解。

    /** Adds a transaction withcount. */

      def add(t: Iterable[T], count: Long =1L):this.type = {

        require(count > 0)

        var curr = root //从根结点开始,将事务中的项依次添加到当前结点的孩子结点中

        curr.count += count

        /**

         * 可以将一个transaction看作树的一个分枝

         * 接下来就是将这个分枝添加到树中,对应层上有包含相同itemNode时就只更新count

         * 没有就要生成新的结点。。。

         */

        t.foreach { item => //依次遍历事务中的每一项

          val summary = summaries.getOrElseUpdate(item,new Summary)//如果item在树中已经存在,获取其结点链,否则生成一个

          summary.count += count

          val child = curr.children.getOrElseUpdate(item,{//首先从当前结点的孩子结点中看item是否存在

            val newNode = new Node(curr//如果不存在,生成一个新的以curr为父结点的newNode

            newNode.item = item 

            summary.nodes +=newNode

            newNode

          })

          child.count += count

          curr = child //得到孩子结点之后,将孩子结点看作当前结点向下遍历

        }//foreach过程执行结束

        this

      }


    /**

       * Gets a subtree with the suffix.

       *  以事务中某项item为后缀,向上遍历FPTree

       *  得到一颗以包含itemNode为叶子结点的子树

       *  但是该方法是从item的父结点开始的,所以子树中不包含item

       *  这是因为extract方法中递归提取的原因

       */

      private def project(suffix: T): FPTree[T] = {

        val tree = new FPTree[T]

        if (summaries.contains(suffix)) {//判断结点链中是否包含该后缀项(貌似没有必要)

          val summary = summaries(suffix) //获取该suffix对应的结点链

          summary.nodes.foreach { node =>

            var t = List.empty[T]

            var curr = node.parent //从父结点开始

            while (!curr.isRoot) {//一直向上遍历直到根结点

              t = curr.item :: t

              curr = curr.parent

            }

            //t中是一条以item为结点的分枝

            tree.add(t, node.count)

          }

        }

        tree

      }

     

    举个例子,假设item=I5,I5对应的summary中包含两个结点。Project方法分别从这两个结点向上遍历,遍历过程如下图所示。


    以I5为后缀的子树投影过程

    遍历之后,就可以得到下图所示子树:


    Project(I5)方法的输出

     

    /**

       *  Extracts allpatterns with valid suffix and minimum count.

       *  分别以summaries一个item为后缀,递归输出所有的频繁项

       */

      def extract(

          minCount: Long,

          validateSuffix: T => Boolean = _ =>true): Iterator[(List[T], Long)] = {

        summaries.iterator.flatMap {case (item,summary) =>//每一项和它对应结点链

         

          /**

           * validateSuffix只在第一次进行判断,判断该item是否属于FPTree对应的分区part

           * FPGrowthgenFreqItemSets方法中,可以看到一行代码 tree.extract(minCount, x=> partitioner.getPartition(x) == part)

           * PFP算法中将所有item进行组划分,假设有3组。那么每个item都有一个组号,在spark中是分区号。

           * 另外,每组都对应着一颗FPTree,对每一组的FPTree提取频繁模式的时候,

           * 只能以属于该组的那些项items为后缀来提取,不属于该分区的则忽略

           *  但是提取过程中是不需要再判断的

           */

          if (validateSuffix(item) &&summary.count >= minCount) {//

            Iterator.single((item :: Nil,summary.count)) ++//item为频繁一项集中的一个

              project(item).extract(minCount).map{case (t,c) =>//递归的抽取item所在分枝上所有大于minCount的项集

                (item :: t, c)

              }

          } else {

            Iterator.empty

          }

        }

      }


    未完待续……


    展开全文
  • FP-Growth算法

    千次阅读 2014-10-28 09:19:43
    Apriori算法和FPTree算法都是数据挖掘中的关联规则挖掘算法,处理的都是最简单的单层单维布尔关联规则。 转自http://blog.csdn.net/sealyao/article/details/6460578 Apriori算法 Apriori算法是一种最有影响的...

    Apriori算法和FPTree算法都是数据挖掘中的关联规则挖掘算法,处理的都是最简单的单层单维布尔关联规则。

    转自http://blog.csdn.net/sealyao/article/details/6460578

    Apriori算法

    Apriori算法是一种最有影响的挖掘布尔关联规则频繁项集的算法。是基于这样的事实:算法使用频繁项集性质的先验知识。Apriori使用一种称作逐层搜索的迭代方法,k-项集用于探索(k+1)-项集。首先,找出频繁1-项集的集合。该集合记作L1L1用于找频繁2-项集的集合L2,而L2用于找L3,如此下去,直到不能找到频繁k-项集。找每个Lk需要一次数据库扫描。

    这个算法的思路,简单的说就是如果集合I不是频繁项集,那么所有包含集合I的更大的集合也不可能是频繁项集。

    算法原始数据如下:

    TID

    List of item_ID’s

    T100

    T200

    T300

    T400

    T500

    T600

    T700

    T800

    T900

    I1,I2,I5

    I2,I4

    I2,I3

    I1,I2,I4

    I1,I3

    I2,I3

    I1,I3

    I1,I2,I3,I5

    I1,I2,I3

    算法的基本过程如下图:

    image

    首先扫描所有事务,得到1-项集C1,根据支持度要求滤去不满足条件项集,得到频繁1-项集。

    下面进行递归运算:

    已知频繁k-项集(频繁1-项集已知),根据频繁k-项集中的项,连接得到所有可能的K+1_项,并进行剪枝(如果该k+1_项集的所有k项子集不都能满足支持度条件,那么该k+1_项集被剪掉),得到clip_image002项集,然后滤去该clip_image002[1]项集中不满足支持度条件的项得到频繁k+1-项集。如果得到的clip_image002[2]项集为空,则算法结束。

    连接的方法:假设clip_image004项集中的所有项都是按照相同的顺序排列的,那么如果clip_image004[1][i]和clip_image004[2][j]中的前k-1项都是完全相同的,而第k项不同,则clip_image004[3][i]和clip_image004[4][j]是可连接的。比如clip_image006中的{I1,I2}和{I1,I3}就是可连接的,连接之后得到{I1,I2,I3},但是{I1,I2}和{I2,I3}是不可连接的,否则将导致项集中出现重复项。

    关于剪枝再举例说明一下,如在由clip_image006[1]生成clip_image008的过程中,列举得到的3_项集包括{I1,I2,I3},{I1,I3,I5},{I2,I3,I4},{I2,I3,I5},{I2,I4,I5},但是由于{I3,I4}和{I4,I5}没有出现在clip_image006[2]中,所以{I2,I3,I4},{I2,I3,I5},{I2,I4,I5}被剪枝掉了。

    海量数据下,Apriori算法的时空复杂度都不容忽视。

    空间复杂度:如果clip_image010数量达到clip_image012的量级,那么clip_image014中的候选项将达到clip_image016的量级。

    时间复杂度:每计算一次clip_image018就需要扫描一遍数据库。

    FP-Tree算法

    FPTree算法:在不生成候选项的情况下,完成Apriori算法的功能。

    FPTree算法的基本数据结构,包含一个一棵FP树和一个项头表,每个项通过一个结点链指向它在树中出现的位置。基本结构如下所示。需要注意的是项头表需要按照支持度递减排序,在FPTree中高支持度的节点只能是低支持度节点的祖先节点。

    image

    另外还要交代一下FPTree算法中几个基本的概念:

    FP-Tree:就是上面的那棵树,是把事务数据表中的各个事务数据项按照支持度排序后,把每个事务中的数据项按降序依次插入到一棵以NULL为根结点的树中,同时在每个结点处记录该结点出现的支持度。

    条件模式基:包含FP-Tree中与后缀模式一起出现的前缀路径的集合。也就是同一个频繁项在PF树中的所有节点的祖先路径的集合。比如I3在FP树中一共出现了3次,其祖先路径分别是{I2,I1:2(频度为2)},{I2:2}和{I1:2}。这3个祖先路径的集合就是频繁项I3的条件模式基。

    条件树:将条件模式基按照FP-Tree的构造原则形成的一个新的FP-Tree。比如上图中I3的条件树就是:

    image

     

    1、 构造项头表:扫描数据库一遍,得到频繁项的集合F和每个频繁项的支持度。把F按支持度递降排序,记为L。

    2、 构造原始FPTree:把数据库中每个事物的频繁项按照L中的顺序进行重排。并按照重排之后的顺序把每个事物的每个频繁项插入以null为根的FPTree中。如果插入时频繁项节点已经存在了,则把该频繁项节点支持度加1;如果该节点不存在,则创建支持度为1的节点,并把该节点链接到项头表中。

    3、 调用FP-growth(Tree,null)开始进行挖掘。伪代码如下:

    procedure FP_growth(Treea)

    if Tree 含单个路径then{

             for 路径P中结点的每个组合(记作b

             产生模式b U a,其支持度support = 中结点的最小支持度;

    } else {

             for each i 在Tree的头部(按照支持度由低到高顺序进行扫描){

                      产生一个模式b = i U a,其支持度support .support

                      构造b的条件模式基,然后构造b的条件FP-树Treeb;

                      if Treeb 不为空 then

                                调用 FP_growth (Treeb, b);

               }

    }

    FP-growth是整个算法的核心,再多啰嗦几句。

    FP-growth函数的输入:tree是指原始的FPTree或者是某个模式的条件FPTree,a是指模式的后缀(在第一次调用时a=NULL,在之后的递归调用中a是模式后缀)

    FP-growth函数的输出:在递归调用过程中输出所有的模式及其支持度(比如{I1,I2,I3}的支持度为2)。每一次调用FP_growth输出结果的模式中一定包含FP_growth函数输入的模式后缀。

    我们来模拟一下FP-growth的执行过程。

    1、 在FP-growth递归调用的第一层,模式前后a=NULL,得到的其实就是频繁1-项集。

    2、 对每一个频繁1-项,进行递归调用FP-growth()获得多元频繁项集。

    下面举两个例子说明FP-growth的执行过程。

    1、I5的条件模式基是(I2 I1:1), (I2 I1 I3:1),I5构造得到的条件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}。

    绘图1

    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}

          image         绘图2




                                             图1                                                                     图2

     

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

    item

    条件模式基

    条件FP-树

    产生的频繁模式

    I5

    I4

    I3

    I1

    {(I2 I1:1),(I2 I1 I3:1)

    {(I2 I1:1), (I2:1)}

    {(I2 I1:2), (I2:2), (I1:2)}

    {(I2:4)}

    <I2:2, I1:2>

    <I2:2>

    <I2:4, I1:2>, <I1:2>

    <I2:4>

    I2 I5:2, I1 I5:2, I2 I1 I5:2

    I2 I4:2

    I2 I3:4, I1 I3:4, I2 I1 I3:2

    I2 I1:4

    FP-growth算法比Apriori算法快一个数量级,在空间复杂度方面也比Apriori也有数量级级别的优化。但是对于海量数据,FP-growth的时空复杂度仍然很高,可以采用的改进方法包括数据库划分,数据采样等等。

    展开全文
  • FP-Tree频繁模式树算法

    万次阅读 2015-01-28 18:21:46
    参考资料:http://blog.csdn.net/sealyao/article/details/6460578 ...介绍 FP-Tree算法全称是FrequentPattern Tree算法,就是频繁模式树算法,他与Apriori算法一样也是用来挖掘频繁项集的,不过不同的是,FP
  • A6392FP是VCD专用集成电路.为28脚双列式塑,在日本索尼HCD-700影碟机上的上正常工作电压典型检测数据如下表所列(单位为V).采用DT890C型数字多用表(DC挡)测... 表1 A6392FP在索尼HCD-700型VCD机上的检测数据  
  • FP6276B 5V升压 实验

    千次阅读 2018-09-15 21:41:14
    最近应用需要把锂电池升压转5V,试过了SX1308,非常便宜,低负载运行很好,高负载700mA有点问题,无法带动移动硬盘,需要对布线特别当心,尽量增粗并缩短馈线。 又换了一个方案用FP6276B来实现,电路也基本上就是...
  • FP-growth挖掘频繁项集算法 当我们在搜索引擎中输入查询词句的一部分时,搜索引擎会自动补全。不正式地说,可以认为搜索引擎将经常出现在一起的词对[1]推荐给了我们,这里就是用了挖掘频繁项集的方法。 FP树类似于...
  • Apriori&FP算法

    2013-11-29 13:56:45
    Apriori算法和FPTree算法都是数据挖掘中的关联规则挖掘算法,处理的都是最简单的单层单维布尔关联规则。 转自http://blog.csdn.net/sealyao/article/details/6460578 Apriori算法 Apriori算法是一种最有影响的挖掘...
  • Apriori和FPTree

    2013-11-24 16:43:00
    Apriori算法和FPTree算法都是数据挖掘中的关联规则挖掘算法,处理的都是最简单的单层单维布尔关联规则。 Apriori算法 Apriori算法是一种最有影响的挖掘布尔关联规则频繁项集的算法。是基于这样的事实:算法使用...
  • FP-growth 算法

    2012-12-04 17:23:01
    Apriori算法和FPTree算法都是数据挖掘中的关联规则挖掘算法,处理的都是最简单的单层单维布尔关联规则。 转自http://blog.csdn.net/sealyao/article/details/6460578 Apriori算法 Apriori算法是一种最有影响的...
  • 这个是要求,说实话GUI做起来太难受了,要是随便做下还可以,但是要是非常细节,那就是折磨人的,这个实现了Apriori算法和FP-Growth算法,说实话,我确实不会,都是百度的,再修改嘛。 from tkinter import * ...
  • FP树(附)

    2014-10-10 20:43:00
    Apriori算法和FPTree算法都是数据挖掘中的关联规则挖掘算法,处理的都是最简单的单层单维布尔关联规则。 转自http://blog.csdn.net/sealyao/article/details/6460578 Apriori算法 Apriori算法是一种最有影响的...
  • 基于Spark的FPGrowth(关联规则算法)

    万次阅读 2016-10-24 11:34:10
    在推荐中,关联规则推荐使用的比较频繁,毕竟是通过概率来预测的,易于理解且准确度比较高,不过有一个...一FPGrowth算法描述:FPGrowth算法概念:支持度,置信度,提升度(Spark好像没有计算这个的函数,需要自己计算
  • 关联挖掘算法Apriori和FP-Tree学习

    万次阅读 多人点赞 2011-06-02 08:52:00
    关联挖掘算法 Apriori算法和FPTree算法原理,伪码和举例说明
  • 松下PLC FP-XH视频教程 松下PLC模拟量视频教程 松下PLC PID控制视频教程 松下PLC MODBUS RTU通讯 控制变频 视频教程 视频教程700M左右
  • 推荐系统_FP-Tree算法

    千次阅读 2016-12-27 19:35:42
    参考资料:http://blog.csdn.NET/sealyao/article/details/6460578 ...介绍 FP-Tree算法全称是FrequentPattern Tree算法,就是频繁模式树算法,他与Apriori算法一样也是用来挖掘频繁项集的,不过不同的
  • 频繁模式增长算法(FP-growth)

    千次阅读 2019-03-26 17:32:40
    算法提出的背景 尽管有着很多的办法用来提升Apriori算法效率,但是如下的两个问题并没有得到很好的解决: ...FP-growth算法的提出,就很好的解决了在产生候选项集过程中巨大的开销。 它采用了分治的...
  • FP-growth算法:高效频繁项集挖掘

    千次阅读 2018-01-23 00:00:00
    Apriori算法和FPTree算法都是数据挖掘中的关联规则挖掘算法,处理的都是最简单的单层单维布尔关联规则。FP-growth算法是用来解决频繁项集发现问题的,这个问题再前面我们可以通过Apriori算法来解决,但是虽然利用...
  • 100台700成以900元=70000——90000元 挂机号的准备;10/个成以2/3成以=20——30成以100台=3000元1000台=30000元 我们公司现在是开远市第一家网络公司我们生产的TM软件支持DNF和九阴真经,在不久的将来我们还会不断...
  • 频繁项集挖掘算法Apriori FPGrowth

    万次阅读 2017-03-26 23:19:14
    参考:http://blog.sina.com.cn/s/blog_5357c0af0101jq6z.html ... ...Apriori算法和FPTree算法都是数据挖掘中的关联规则挖掘算法,处理的都是最简单的单层单维布尔关联规则。 Apriori算法 Ap
  • 松下PLC FP-XH模拟量+PID控制 MODBUS RTU通讯 视频教程 松下PLC FP-XH视频教程 松下PLC模拟量视频教程 松下PLC PID控制视频教程 松下PLC MODBUS RTU通讯 控制变频 视频教程 视频教程700M左右
  • 松下KX-FP706CN_W维修手册(中文),资料全面,官方维修手册。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,262
精华内容 1,304
关键字:

700fp