Python machine learning-TensorFlowPython machine learning-sklearning

关联规则挖掘算法

2018-09-01  本文已影响25人  阿发贝塔伽马

I=\{i_1,i_2,...,i_m\}为所有项目的集合,D为事务数据库,事物T是一个项目子集(T\subseteq I)。每一个事务具有唯一的事务标识TID。设A是一个由项目构成的集合,称为项集。事务T包含项集A,当且仅当A\subseteq T。如果项集A中包含k个项目,则称其为K项集

项集A在事务数据库D中出现的次数占总事务的百分比叫做项集的支持度。如果项集的支持度超过用户给定的最小支持度阈值,就称该项集是频繁项集(或频集)

关联规则是形如X \Rightarrow Y的逻辑蕴含式,其中X\subset I,Y\subset I,且X\cap Y=\phi

如果事务数据库D中有s\%的事务包含X∪Y, 则称关
联规则X⇒Y的⽀持度为s\%

关联规则的信任度为support (X∪Y)/support (X)
也就是:
support (X⇒Y)=P (X ∪Y)
confidence (X⇒Y)=P (Y | X)

强关联规则就是⽀持度和信任度分别满⾜⽤户
给定阈值的规则

例子

交易ID 购买的商品
2000 A,B,C
1000 A,C
4000 A,D
5000 B,E,F

设最⼩⽀持度为50%, 最⼩可信度为 50%, 则可得到

Apriori算法

命名源于算法使⽤了频繁项集性质的先验( Prior) 知识。

Apriori算法将发现关联规则的过程分为两个步骤:

Apriori的性质

性质1: 频繁项集的所有⾮空⼦集必为频繁项集。

性质2: ⾮频繁项集的超集⼀定是⾮频繁的。

Apriori的步骤

连接步: 为找Lk,通过将Lk-1与⾃⾝连接产⽣候选k项集
的集合

剪枝步: Ck是Lk 的超集, 也就是说, Ck的成员可以是
也可以不是频繁的, 但所有的频繁k项集都包含在Ck中。
任何⾮频繁的( k-1) 项集都不是频繁k项集的⼦集

Apriori算法实例

现有A、 B、 C、 D、 E五种商品的交易记录表, 试找出
三种商品关联销售情况(k=3), 最小支持度=50%

交易号 商品代码
100 A,C,D
200 B,C,E
300 A,B,C,E
400 B,E

读入数据

data = {'交易号':range(100,500,100),'商品代码':['A,C,D', 'B,C,E', 'A,B,C,E', 'B,E']}
df_data = pd.DataFrame(data=data)

算一个事务集在事务数据库的支持度

def get_score(values):
    score = 0.0
    b = True
    for value_code in df_data['商品代码'].values:
        if values.difference(value_code.split(',')) == set():
            score += 1
    return score/len(df_data)

首先构造等候集C

c = []
for code in df_data['商品代码'].values:
    for _ in code.split(','):
        if {_} not in c:
            c.append({_})

输出c

 [{'A'}, {'C'}, {'D'}, {'B'}, {'E'}]

计算L

from collections import defaultdict

score = 0.5
# 这里用字典来保存频繁项集
L = defaultdict(list)
i = 0
length = len(c)
while c:
    i += 1
    for ci in c:
        if get_score(ci) >= score:
            L[i].append(ci)
    print L[i]
    c = get_c(L[i])
[set(['A']), set(['C']), set(['B']), set(['E'])]
[set(['A', 'C']), set(['C', 'B']), set(['C', 'E']), set(['B', 'E'])]
[set(['C', 'B', 'E'])]

可以得出三种商品关联销售情况(k=3), 最小支持度=50%只有一组(CBE)

Apriori算法的不⾜

FP-tree算法(不⽤⽣成候选集)

2000年, Han等提出了⼀个称为FP-tree的算法。
FP-tree算法只进⾏2次数据库扫描。

FP-tree两个主要步骤

步骤1: 构造 FP-tree树

具体过程:
1.  扫描数据库⼀次, 得到频繁1-项集
2.  把项按⽀持度递减排序
3.  再⼀次扫描数据库, 建⽴FP-tree

FP-tree 结构的好处

步骤2: 频繁模式的挖掘

FP-tree算法的一个例子

事物数据库:

Tid Items
1 I1,I2,I5
2 I2,I4
3 I2,I3
4 I1,I2,I4
5 I1,I3
6 I2,I3
7 I1,I3
8 I1,I2,I3,I5
9 I1,I2,I3
df_fp_data = pd.DataFrame({'Tid':xrange(1,10,1), 'Items':['I1,I2,I5', 'I2,I4','I2,I3','I1,I2,I4',
                                                         'I1,I3', 'I2,I3','I1,I3','I1,I2,I3,I5',
                                                         'I1,I2,I3']})
def get_item_number(item):
    for el in item.split(','):
        dic_items[el]+=1   
dic_items = defaultdict(int)

df_fp_data['Items'].map(get_item_number)
dic_items

统计了每一项频数,输出

defaultdict(int, {'I1': 6, 'I2': 7, 'I3': 6, 'I4': 2, 'I5': 2})

按照频数对Items由大到小排序

df_fp_data['Items'] = df_fp_data['Items'].map(lambda items: 
        ','.join(sorted(items.split(','), key=lambda item:-dic_items[item])))

创建节点类与树类

# 节点
class Node():
    def __init__(self, item):
        self.item = item
        self.numbers = 1
        self.children = []
        
class Tree():
    def __init__(self, root=None):
        self.root = root
    # 加入items
    def add_nodes(self, items):
        # 建立根节点
        if self.root is None:
            self.root = Node('null')
        temp = self.root.children
        if temp == [] and len(items)>0:
            temp.append(Node(items[0]))
            items.pop(0)
            temp_tree = Tree(temp[0])
            temp_tree.add_nodes(items)
        elif temp != []:
            for item in items:
                b = False
                for node in temp:
                    if node.item == item:
                        node.numbers += 1
                        temp = node.children
                        b = True
                        break
                if b is False:
                    temp_tree = Tree(Node(item))
                    temp_tree.add_nodes(items[items.index(item)+1:])
                    temp.append(temp_tree.root)
                    break
    def print_tree(self):
        node = self.root
        stack = [node]
        while stack != []:
            temp_node = stack.pop(0)
            print temp_node.item,temp_node.numbers
            stack += temp_node.children   
    def preorder_traversal(self):
        # 采用先序遍历
        stack = []
        path = []
        temp = self.root
        while temp or stack:
            if temp is not None:
                print temp.item, temp.numbers
                stack.append(temp)
                if temp.children == []:
                    temp = None
                else:
                    temp = temp.children.pop(0)
            else:
                children = stack[-1].children
                if children == []:
                    stack.pop()
                else:
                    if len(children) == 1:
                        stack.pop()
                    temp = children.pop(0)
         

将节点加入树中

tree = Tree(Node('null'))
for item in df_fp_data['Items'].values:
    tree.add_nodes(item.split(','))

打印树(层次打印)

tree.print_tree()
null 1
I2 7
I1 2
I1 4
I4 1
I3 2
I3 2
I5 1
I4 1
I3 2
I5 1
FP-tree树
tree.preorder_traversal()

输出

null 1
I2 7
I1 4
I5 1
I4 1
I3 2
I5 1
I4 1
I3 2
I1 2
I3 2
上一篇下一篇

猜你喜欢

热点阅读