[数据挖掘] 关联规则 Apriori算法实现到PFP(paralled frequent pattern)算法

1. 关联分析(Association analysis)


理解:

  • 从大规模的数据中, 发现事物(物品)间的隐含关系的过程就是关联分析(association analysis)或者关联规则学习(association rule learning).
  • 是一种在大规模数据中发现有趣关系的任务.

这些有趣关系, 主要分为两种: 频繁项集或者关联规则

频繁项集(frequent item sets): 经常在一起出现的物品的集合
关联规则(association rule): 暗示两个物品的集合之间可存在某种很强的依赖的关系;后面会给出明确定义。
以下,将说明未然频繁项集的产生与关联规则的产生进行说明
因为频繁项集的产生需要对大规模数据进行遍历,所以产生了Apriori算法来挖掘频繁项集。

2. 相关概念


  • 支持度(support): 某个项集的支持度被定义为: 包含该项集的事务的比例( 包含该项集的事务 / 所有事务), 表示了该项集的有用性.
  • 置信度(confidence): 针对两个项集 如 {尿布} -->{啤酒} 的关联规则, 其置信度为 : support( {啤酒, 尿布} ) / support( {尿布} ) ,即可以理解为: 在尿布存在的情况下,啤酒存在的概率 或 由尿布可以推出啤酒这件事的确定性。
  • 项集(sets): 事务中的每一个物品的集合, 如商店每个购物车里的每件商品自由组合; 毒蘑菇每种蘑菇的特征的组合。所有标称数值的值的集合。
  • 事务: 现实世界中每一件完整的事项, 如商店每个人的购物车,美国国会的每一次投票, 毒蘑菇的每一种类, 每种事务有多个项集.
  • 候选项集(Candidate sets): 一般用C来表示,候选项集里面的部分或全部项集组成相应的频繁项集
  • 最小支持度(min-support): 根据实际业务情况来定义的一个最小支持度,大于该支持度的项集可以看做为有趣的项集。
  • 频繁项集(frequent sets): 一般用L表示,候选项集中 支持度大于最小支持度的项集
  • 最小置信度(min confidence):根据实际业务情况确定的一个最小置信度,大于该置信度的规则可以看做是有趣的。
  • n项集: 表示该项集中一共有n项物品,Cn表示候选n项集,Ln表示频繁n项集

3. Apriori算法查找频繁项集

3.1 Apriori算法的原理:

Apriori 算法的一般过程

  1. 收集数据:使用任意方法
  2. 准备数据:任何数据类型都可以, 因为我们需要的只是集合
  3. 分析数据:使用任一方法
  4. 训练算法:使用Apriori算法来找到频繁项集
  5. 测试算法:不需要测试
  6. 使用算法:用于发现频繁项集以及物品之间的关联规则

剪枝的基本原理

  • 如果一个项集是频繁的,那么它的所有子集也是频繁的,
    如: {1, 0} 是一个频繁项集,那么 {1}, {0}也是频繁项集
  • 反之,如果一个项集是非频繁的,那么它的所有超集也是非频繁的
    如:{1,2} 是一个非频繁项集,那么 {1,2,3},{0,1,2,}也是非频繁项集
  • 在下面可以看到,有了这个先验知识,就可以对频繁项集的寻找过程进行剪枝

3.2 Apriori算法步骤

主要步骤(主函数)

  1. 根据原始数据生成候选1项集 C1

  2. 根据C1生成频繁1项集 L1

  3. 迭代
    根据Lk项集生成Ck+1项集 //连接
    对Ck+1项集剪枝 //剪枝
    如果Ck+1剪枝后为空,算法结束
    根据Ck+1生成Lk+1项集

连接 由Ck生成Ck+1

  • 笛卡尔乘积
  • 例如 对于频繁项集L2: [ {1, 2}, {1, 3}, {2, 3}, {2, 4} ], 连接结果为C3: [ {1, 2, 3}, {2, 3, 4} ]
  • 具体过程: 对于频繁项集Lk中的每一内部有序的项Lk[i]与其他所有内部有序的项Lk[j], 判断Lk[i][:k-1] == Lk[j][:k-1], 如果相等,则 C3.append(Lk[i] | Lk[j]), 这里的 | 是集合的并操作

剪枝 由Ck+1生成Lk+1

  • 根据基本原理,对于生成的候选项集Ck,利用Apriori的原理:其子集若为非频繁项集,则该项集也为非频繁项集。
  • 具体来说,就是对于Ck中的每个元素Ck[i], 若Ck[i]的所有k-1项的子集在Lk-1中不存在,则说明Ck[i]肯定不是频繁的,剪枝
  • 根据最小支持度得出Lk
    遍历原始事务数据集,计算 support = 含有Ck[i]的事务的数量 / 总事务数量, support >= min-support 添加到 Lk中

Python 实现

  • 输入:事务的列表: [ [事务1的项], [事务2的项], … ]
  • 输出:
    1. 频繁项集列表freqSets: [ [频繁1项集], [频繁2项集], … ];
    2. 支持度字典support:{ {项集}:支持度, {项集}:支持度,… }
  • 数据结构:
    项集:冻结集合, frozenset , 可以用来作为字典的key
    频繁项集,候选项集: 列表
    项集与其支持度:字典
算法:

再看一下主要步骤(generate_freqSet_support_list(data, min_support)):

  1. 根据原始数据生成候选1项集 C1

  2. 根据C1生成频繁1项集 L1

  3. 迭代
    根据Lk项集生成Ck+1项集 //连接
    对Ck+1项集剪枝 //剪枝
    如果Ck+1剪枝后为空,算法结束
    根据Ck+1生成Lk+1项集

主要步骤中:

  1. 第1, 2步:
    get_frequent_1_itemsets(data, min_support)
    该方法主要计算 1项集 c1 以及对c1中每个项集, 存在这个项集的事务的计数, 在return时进行第2步:
    其中第2步主要由方法:
    get_frequent_itemsets(c, min_support, num_itmes)实现,
    输入: 第1步得到的 c1, 最小支持度, 总的事务数
    该方法 返回的是频繁项集L1每个项集对应的支持度
  2. 迭代部分:
    连接: decartes(c, c2) c与c2进行笛卡尔连接
    剪枝: cut() 根据剪枝的基本原理对第一步连接得到的Ck+1进行剪枝
    生成 频繁k+1项集-Lk+1 : find_frequent_n_itemsets(data, c, min_support)
    • 该函数与get_frequent_1_itemsets(data, min_support)一样分为两个部分: 生成k+1项集 Ck+1 以及对于Ck+1中每个项集, 存在这个项集的事务的计数,
    • 返回时调用get_frequent_itemsets(c, min_support, num_itmes)来得到频繁Lk+1项集Lk+1中每个项集对应的支持度

我的代码

这里我因为之前忘记了 frozenset这个数据结构, 所以用的元组来代替, 所以很多冗余代码, 懒得改了, 就这样吧, 实现的算法看主要步骤, 数据结构看上面, 很清楚了

def read_data(path):
    """
    这里大家根据数据集设置
    读取初始数据集, 给数据集格式化为字典
    :param path: 文件路径,
    :return: {key: [value1, value2, ...], key2: [...], ...}
    """
    data = dict()
    with open(path, 'r') as f:
        lines = f.readlines()
        for line in lines:
            cart = line.split(" ")
            data[cart[0]] = [c.strip() for c in cart[1:]]
            data[cart[0]].sort()
    print(data)
    return data


def get_frequent_itemsets(c, min_support, num_itmes):
    l = list()
    support = {}
    for i in filter(lambda key: c.get(key) if c.get(key)/float(num_itmes) >= min_support else None, c):
        support[i] = c.get(i)/float(num_itmes)
        l.append(i)
    l.sort()
    return l, support


def find_frequent_1_itemsets(data, min_support):
    c_1 = dict()
    for v in data.values():
        for j in v:
            r = c_1.get((j,))
            if r is not None:
                c_1[(j,)] = r + 1
            else:
                c_1[(j, )] = 1
    num_itmes = len(data)
    return get_frequent_itemsets(c_1, min_support, num_itmes)


def find_frequent_n_itemsets(data, c, min_support):
    c_n = dict()
    for i in c:  # 每个元组 项集
        for key in data:
            for j in i:  # 元组里面的元素 项
                try:
                    data.get(key).index(j)
                except ValueError as e:
                    break
            else:
                r = c_n.get(i)
                if r is not None:
                    c_n[i] = r + 1
                else:
                    c_n[i] = 1
    num_items = len(data)
    return get_frequent_itemsets(c_n, min_support, num_items)


def decartes(c1, c2):
    c = list()
    for i_1 in c1:
        for i_2 in c2:
            if i_1[0:-1] == i_2[0:-1] and i_1[-1] < i_2[-1]:
                li = list()
                li.extend(i_1)
                li.append(i_2[-1])
                tu = tuple(li)
                c.append(tu)
    return c


def cut(c, pre_c):
    """
     找出c_k中所有k-1项的子集, 并判断在前一个(c_k-1)项集中是否存在该子集
     若不存在,则将该项去除
    """
    num = len(c[0])
    for i in c:
        for lost in range(num):
            tmp = list(i)
            tmp.remove(i[lost])
            try:
                pre_c.index(tuple(tmp))
            except ValueError:  # 不存在该项集 移除
                c.remove(i)
                break
    return c


def generate_freqSet_support_list(data, min_support):
    l, support = find_frequent_1_itemsets(data, min_support)
    freq_support = {}

    while len(l) > 0:
        print("正在计算{0}项集的support...".format(len(l[0])))
        freq_support.update(support)
        c = decartes(l, l)
        if len(c) == 0:
            break
        cut_c = cut(c, l)
        l, support = find_frequent_n_itemsets(data, cut_c, min_support)
    return freq_support
数据集:
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
Apriori 测试运行结果:

在这里插入图片描述
在这里插入图片描述

3.3 Apriori 算法优劣

  • 优势:
    1. 实现简单
    2. 处理大型数据的时候,可以存储到外存上
  • 劣势
    1. 效率低,每次计算Li项集的时候,就需要遍历一遍原始数据来计算支持度

4.另一种频繁项集计算:FP_growth (frequent pattern)

Han J , Pei J , Yin Y . Mining Frequent Patterns without Candidate Generation[J]. Acm Sigmod Record, 2000, 29(2):1-12.

4.1 FP_growth原理

FP树,类似于哈夫曼树的一种数据编码,FP树将频繁一起出现的项集中在一条路径上。
在初始的FP树构建完成之后,输入一个新的项集,便可以将该项集加入到该FP树中,这就是FP树的更新(生长)过程,即growth的含义

FP 算法的优势

Apriori算法在计算频繁项集时,采用自底向上的思路,需要迭代的获取所有潜在的频繁项集,并计算其支持度以判断其是否频繁。故在迭代过程中会得到许多非频繁项集再通过剪枝去掉,这使得Apriori算法耗费大量时间。
而FP算法直接通过原数据构建FP树,将频繁一起出现的项尽量的集中在一条从根到叶子节点的路径上,通过FP树的构建减少了非频繁项集的出现次数从而节省时间消耗。

FP 算法的一般过程

  1. 收集数据:使用任意方法
  2. 准备数据:需要的是集合,故需要离散数据,连续型数据需进行离散化
  3. 分析数据:使用任一方法
  4. 训练算法:1)构建FP树,2)对树进行挖掘找到频繁项集
  5. 测试算法:不需要测试
  6. 使用算法:用于识别经常出现的元素项(频繁项集),实现决策制定,元素推荐,或预测等应用

FP树的一个例子:
fp树的例子,从table1中构建fp树

4.2 FP树构建算法

FP树的构建算法中,将分为两个部分,一是创建FP树,二是更新FP树
在这里贴上论文在这里贴上PFP论文中的算法图结合理解,PFP论文中的算法与本文实现不完全相同,例如下图中将FP树的生长(更新)与频繁模式挖掘结合在一起了。
在下文将给出本文更具体的算法步骤。
创建FP树

更新FP树同时进行频繁项集的挖掘

4.2.1 创建FP树

FP树的数据结构:

FPNode类属性:树节点

nodeLink: 指向相似的项(同一元素/商品),链接了树中同一项
name: 项名称
parent: 指向父节点
count: 该项在所有事务中的总出现次数,决定了该项是否频繁
child: 孩子节点集合{}

HeaderTable类,所有项构成的一个表头:一个链表

name: 项名称
count: 该项在事务中的出现次数
nodeLink: 指向该项在FP树中的第一个FPNode

方法:

构造方法:初始化节点
print:可视化(非必须,调试的时候可以用到)
prefixPath: 找到节点的前缀路径

输入:事务与及其项;支持度阈值
初始化:空FP树节点作为根节点;空HeaderTable
输出:FP树,HeaderTable。
算法:
FP树的构建需要两次遍历完成。

第一次遍历:

构造HeaderTable:
对每个事务,遍历其项集,将遇到的项添加进HeaderTable中,并将其count+1

第二次遍历

createTree(dataset, minSup)构造FP树:
输入:事务;最小支持度阈值
初始化:空节点作为根节点

遍历所有的事务:
	从FP树根节点开始
	1.删除事务中小于支持度阈值(minSupprt)的项
	2.将项集按照HeaderTable中的count排序存储在临时有序表(freqList)中
	3.若freqList中没有元素:
		continue;
	否则:调用updateTree(当前节点,freqLis)函数将freqList中的项加入到树中。

4.2.2 FP树的生长 updateTree()

输入:当前节点(子树的根节点inTree);需加入的有序项集freqList;
输出:更新后的FP树
算法:

updataTree()递归的将freqList添加进树中:

if freqList不为空时:
	item=freqList[0];
	if item in inTree.children://若当前节点子节点中含有item,将其计数增加
		inTree.children[item].count++;
	else://若没有,创建新的节点,并将其加入孩子集中,同时更新headerTable链表
		node = new FPNode(count=1,name=item);
		inTree.addChildren(item=node);
		updateHeaderTable(HeaderTable[item], node);

	updateTree(inTree.children, freqList[1:]);//递归添加完所有的freqList中的项

updataHeaderTable(headerNode, node)链表的增加元素:

p = headerNode;
while p.nodeLink != null:
	p = p.nodeLink;
	p.nodeLink = node;

4.3 从FP树种挖掘频繁项集

输入:FP树;需研究的项HeaderTable
输出:频繁项集
算法如下:

条件模式基(conditional pattern base): 以所查找元素在FP树中的所有节点为尾节点的前缀路径集合。
从FP树中挖掘频繁项集主要有三个步骤:

  1. 从FP树中获取节点的条件模式基。
  2. 根据条件模式基构建条件FP树,当前节点(条件)添加到频繁项集中
  3. 迭代1.2.直到条件模式基只剩一个元素

4.3.1 获取条件模式基

输入:当前项(item);FP树;HeaderTable
输出:item的条件模式基集合condPat={prefixPath, count}
算法:

getPrefixPathSet(FPTree, item):

遍历链表 node in HeaderTable[item]:
	condPat[ascendTree(node, FPTree)] = HeaderTable[item].count;
return condPat;

ascendTree(node, FPTree):

p = node;
init prefixPath;
while p->parent != null:
	prefixPath.add(p->name);
return prefixPath;

4.3.2 创建条件FP树同时得到频繁项集

输入:item的条件模式基集合 condPat;
输出:频繁项集 freqItemList;
算法:对HeaderTable中每一项都进行挖掘:

mineFreqItem(condPat):

freqItemList.append(item);//将item单个元素先加入到频繁项集中
newHeaderTable = createHeaderTable(condPat);//过滤了其中count不到minSup的项
itemFPTree = createTree(condPat);//根据condPat构建新的FP树
对newHeaderTable中的所有元素 newItem:
	condPat = getPrefixPathSet(itemFPTree, newItem);
	mineFreqItem(condPat);
return freqItemList;

4.4 PFP(paralleled frequent pattern):基于分布式的频繁模式挖掘

论文:PFP: Parallel FP-Growth for Query Recommendation

5. 根据频繁项集挖掘关联规则

原理

在上一步, 我们已经得到了 频繁项集支持度计数(support)
根据关联规则公式: 对于关联规则 p --> r 有:conf = support( p 并 r ) / support( p )

算法主要步骤(python实现)

主函数: generateRules()
计算支持度的函数:

  • caculConf(freqSet, support, h1, min_conf, ruleList, *f)
  • 参数:
    freqSet: (p并r)
    support: 第一步中的支持度, 这里在计算支持度时用来查表
    h1: 被作为 r 的项集
  • return: 将 freqSet - h1 --> h1 时强关联规则的写入文件

算法(主函数generateRules()):
对于第一步的结果: support

  1. 遍历 support 中的所有频繁项集 每一个频繁项集定义为 freqSet, 即为 p–>r中的(p并r)
  2. 对freqSet的每一项, 生成新的一项子集 h, 此处的 h 中的所有项与其超集, 会作为 p–>r 中的 r
  3. 若freqSet是二项集, 则直接调用 caculConf()来计算freqSet - h -->h的支持度
    若不是二项集, 则需要计算 h 与其所有超级的支持度, 调用函数rulseFromConseq()

代码

from Apriori.apriori import decartes  # 计算笛卡尔乘积
from Apriori import apriori


def tuple2frozenset(freq_support):
    """
    将数据结构{元组:支持度, 元组:支持度}, 转换为: {frozenset: 支持度, frozenset:支持度}
    :param freq_support:{元组:支持度, 元组:支持度}
    :return:{frozenset: 支持度, frozenset:支持度}
    """
    # freq_support的key转换成frozenset
    support = dict()
    for i in freq_support:
        support[frozenset(i)] = freq_support.get(i)
    return support


def generateRules(res_path, support, min_conf=0.7):
    """
    生成关联规则
    :param res_path: 关联规则的文件写入路径 
    :param support: apriori算法得到的支持度字典 {frozenset: 支持度, frozenset:支持度}
    :param min_conf: 最小置信度
    :return: 强关联规则的结果集 对于 p->q conf 有 [(p, q, conf), ()]
    """
    with open(res_path, 'w+') as f:
        ruleList = []
        for freqSet in support:  # freqSet: 频繁项集(frozenset)
            h1 = [frozenset([item]) for item in freqSet]  # 对频繁项集的每一项生成一个项集

            if len(freqSet) == 2:  # 如果是频繁二项集, h1连接之后也是2项集, 所以只需要计算一次 h1
                caculConf(freqSet, support, h1, min_conf, ruleList, f)
            else:
                rulesFromConseq(freqSet, support, h1, min_conf, ruleList, f)
    return ruleList


def caculConf(freqSet, support, h1, min_conf, ruleList, *f):
    for conSeq in h1:
        try:
            conf = support[freqSet]/support[freqSet-conSeq]  # freqSet-conSeq --> conSeq
        except ValueError:
            print("集合不存在该频繁项集!")
            continue

        if conf > min_conf:
            str = "{0}-->{1}:   support:{2:.2}, conf:{3:.2}".format(set(freqSet-conSeq), set(conSeq), support[freqSet], conf)
            f[0].write(str+'\n')  # 该强关联规则写入文件
            ruleList.append((freqSet-conSeq, conSeq, conf))  # 该强关联规则加入最后的结果集


def rulesFromConseq(freqSet, support, h1, min_conf, ruleList, *f):
    """
    循环
    1.  计算 freqSet - h1[i] --> h1[i] 的置信度
    2.  h1进行笛卡尔乘积连接 成为新的h1
    3.  h1不为空 and  len(h1[i]) < freqSet
            返回 1.
        否则
            退出循环
    :param freqSet: 
    :param support: 
    :param h1: 
    :param min_conf: 
    :param ruleList: 存储所有的 强关联规则 
    :param f: 写入文件路径
    :return: 
    """
    while len(h1[0]) < len(freqSet):
        caculConf(freqSet, support, h1, min_conf, ruleList, f[0])
        # 以下对h1进行连接
        c = list(map(tuple, h1))  
        h1 = [i for i in map(frozenset, decartes(c, c))]
        if len(h1) == 0:
            break

挖掘结果:

在这里插入图片描述
res.dat:

{'I1'}-->{'I2'}:   support:0.44, conf:0.67
{'I2'}-->{'I1'}:   support:0.44, conf:0.57
{'I1'}-->{'I3'}:   support:0.44, conf:0.67
{'I3'}-->{'I1'}:   support:0.44, conf:0.67
{'I1'}-->{'I5'}:   support:0.22, conf:0.33
{'I5'}-->{'I1'}:   support:0.22, conf:1.0
{'I2'}-->{'I3'}:   support:0.44, conf:0.57
{'I3'}-->{'I2'}:   support:0.44, conf:0.67
{'I2'}-->{'I4'}:   support:0.22, conf:0.29
{'I4'}-->{'I2'}:   support:0.22, conf:1.0
{'I2'}-->{'I5'}:   support:0.22, conf:0.29
{'I5'}-->{'I2'}:   support:0.22, conf:1.0
{'I1', 'I2'}-->{'I3'}:   support:0.22, conf:0.5
{'I3', 'I1'}-->{'I2'}:   support:0.22, conf:0.5
{'I3', 'I2'}-->{'I1'}:   support:0.22, conf:0.5
{'I1'}-->{'I3', 'I2'}:   support:0.22, conf:0.33
{'I2'}-->{'I3', 'I1'}:   support:0.22, conf:0.29
{'I3'}-->{'I2', 'I1'}:   support:0.22, conf:0.33
{'I1', 'I2'}-->{'I5'}:   support:0.22, conf:0.5
{'I1', 'I5'}-->{'I2'}:   support:0.22, conf:1.0
{'I2', 'I5'}-->{'I1'}:   support:0.22, conf:1.0
{'I1'}-->{'I5', 'I2'}:   support:0.22, conf:0.33
{'I2'}-->{'I5', 'I1'}:   support:0.22, conf:0.29
{'I5'}-->{'I2', 'I1'}:   support:0.22, conf:1.0

6.Apriori实例:挖掘毒蘑菇分类特征


数据集介绍

uci数据集:
原始数据:http://archive.ics.uci.edu/ml/machine-learning-databases/mushroom/agaricus-lepiota.data
处理后的数据:http://fimi.ua.ac.be/data/
其中, 第一行 1代表 有毒, 2 代表可食用, 我们对此进行关联规则挖掘
其他参数的意义…emmmm
毒蘑菇数据集是一个二分类数据集

编写脚本并引入以上我们编写的代码模块:

from Apriori.apriori import generate_freqSet_support_list as gfsl
from Apriori.genAssocRules import tuple2frozenset
from Apriori.genAssocRules import generateRules
mushroom_data = {}

with open('mushroom.dat', 'r') as f:
    i = 0
    for line in f.readlines():
        mushroom_data[i] = line.strip().split(' ')
        i = i + 1
# 计算设置最小支持度为0.6 来计算其规则
mushroom_support = gfsl(mushroom_data, 0.6)
mushroom_support = tuple2frozenset(mushroom_support)
print(mushroom_support)
rules = generateRules('res.dat', mushroom_support)
for i in rules:
    print(i)

部分结果

前30行
res.dat:

{'34'}-->{'36'}:   support:0.81, conf:0.83
{'36'}-->{'34'}:   support:0.81, conf:0.97
{'39'}-->{'34'}:   support:0.66, conf:0.96
{'59'}-->{'34'}:   support:0.61, conf:0.96
{'34'}-->{'85'}:   support:0.97, conf:1.0
{'85'}-->{'34'}:   support:0.97, conf:0.97
{'34'}-->{'86'}:   support:0.97, conf:1.0
{'86'}-->{'34'}:   support:0.97, conf:1.0
{'34'}-->{'90'}:   support:0.9, conf:0.92
{'90'}-->{'34'}:   support:0.9, conf:0.97
{'85'}-->{'36'}:   support:0.84, conf:0.84
{'36'}-->{'85'}:   support:0.84, conf:1.0
{'86'}-->{'36'}:   support:0.81, conf:0.84
{'36'}-->{'86'}:   support:0.81, conf:0.97
{'36'}-->{'90'}:   support:0.8, conf:0.95
{'90'}-->{'36'}:   support:0.8, conf:0.86
{'39'}-->{'85'}:   support:0.69, conf:1.0
{'39'}-->{'86'}:   support:0.67, conf:0.97
{'39'}-->{'90'}:   support:0.61, conf:0.89
{'59'}-->{'85'}:   support:0.64, conf:1.0
{'59'}-->{'86'}:   support:0.61, conf:0.96
{'63'}-->{'85'}:   support:0.61, conf:1.0
{'86'}-->{'85'}:   support:0.98, conf:1.0
{'85'}-->{'86'}:   support:0.98, conf:0.98
{'85'}-->{'90'}:   support:0.92, conf:0.92
{'90'}-->{'85'}:   support:0.92, conf:1.0
{'86'}-->{'90'}:   support:0.9, conf:0.92
{'90'}-->{'86'}:   support:0.9, conf:0.97
{'85', '34'}-->{'36'}:   support:0.81, conf:0.83
{'36', '34'}-->{'85'}:   support:0.81, conf:1.0
  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值