数据挖掘(二) Apriori算法

数据挖掘(二) Apriori算法的python实现


使用的数据承接之前处理好的情报词库
数据挖掘(一) TF-IDF算法
Apriori算法的目的是为了查找,一些主题词元素的出现,是否存在关联性,算法流程如下:

Apriori算法

在这里插入图片描述

关联规则提取(判断)与存储

在这里插入图片描述

结合注释代码:
包括频繁模式的查找

class Apriori算法:
    def __init__(self, 数据库):
        """
        求取频繁模式
        :param 数据库: 输入的是一个二维列表,存储着一条一条的主题词或者关键字,
                    都是根据某一语义在其下共现的事务
        """
        self.数据库 = 数据库
        self.数据库长度 = len(数据库)
        self.k = 1
        self.事务数据最长长度 = 0
        self.频繁模式总表 = []
        self.当前频繁模式 = []
        self.历史频繁模式 = []
        self.频繁阈值 = 6 / len(数据库)
        """
        原处于各个位置的词汇都可以成为待选模式的一员
        """
        待选1模式 = {}
        for 词汇条 in self.数据库:
            if len(词汇条) > self.事务数据最长长度:
                self.事务数据最长长度 = len(词汇条)
            forin 词汇条:
                try:
                    待选1模式[] += 1
                except:
                    待选1模式.update({: 1})
        """
        根据出现的频次,按照阈值划分,去除待选模式的不频繁元素
        """
        频繁1模式列表 = {}
        for 频繁词 in 待选1模式:
            if 待选1模式[频繁词] / self.数据库长度 > self.频繁阈值:
                频繁1模式列表.update({频繁词: 待选1模式[频繁词] / self.数据库长度})
        self.频繁模式总表.append([])
        self.频繁模式总表[-1].append(list(频繁1模式列表.keys()))
        self.频繁模式总表[-1].append(频繁1模式列表)

    def 待选模式生成(self):
        """
        从频繁1模式中抽取 k个元素,构成新的集合,是原集合的 k元选组合
        :return:
        """
        if self.k < self.事务数据最长长度:
            temp = list(itertools.combinations(self.频繁模式总表[0][0], self.k))
            self.k += 1
            return temp
        else:
            return None

    @staticmethod
    def 查询函数(输入列表, 新元素, 查询参数):
        """
            函数功能是解决一个问题,在将一个元素(可以是一个字符串,也可以是一个列表)
            添加入新的列表时,先查询在这个列表是否存在了这个元素
            :param 输入列表: 待被添加进新元素的原列表
            :param 新元素: 待添加元素
            :param 查询参数: 新元素的数据长度
            :return: 布尔值:
                    True: 未存在(即可以添加的意思)
                    False: 已存在(就不添加了)
            """
        index = 0
        for 子元素 in 输入列表:
            查询元素个数 = 0
            for 查询元素个数 in range(查询参数):
                try:
                    if 子元素[查询元素个数] == 新元素[查询元素个数]:
                        查询元素个数 += 1
                except:
                    pass
            if 查询元素个数 == 查询参数 and 查询元素个数 != 0:
                index += 1
                break
        if index:
            return False
        else:
            return True

    @staticmethod
    def 列表元素拼接(输入列表):
        """
        由于k>=2的频繁模式,它的元素是k个字符串的集合,
        在做字典计数以及存储时,需要拼接,这里进行一下函数封装
        :param 输入列表: 待拼接列表
        :return: 拼接结果,以 + 作为拼接标识符
        """
        temp = ''
        for i in 输入列表:
            temp += i + '+'
        return temp[:-2]  # 末尾的 + 就不需要了

    def 频繁模式生成(self):
        self.当前频繁模式 = self.待选模式生成()
        self.历史频繁模式 = self.频繁模式总表[-1][0]
        """
        被注释掉的是一个优化过程,其子模式不是频繁模式
        那么它也不是,就不需要参与接下来的支持度查找了
        但是存在一定逻辑问题,当前并未加入这一段
        """
        # temp = []
        # for i in self.当前频繁模式:
        #     k = 0
        #     for j in self.历史频繁模式:
        #         if self.查询函数(i, j, len(j)):
        #             k += 1
        #     if k:
        #         temp.append(i)
        # self.当前频繁模式 = temp
        当前表 = {}
        for 频繁模式打分 in tqdm(self.当前频繁模式):
            for 词汇条 in self.数据库:
                if len(频繁模式打分) < len(词汇条):
                    pass
                else:
                    if self.查询函数(频繁模式打分, 词汇条, len(词汇条)):
                        pass
                    else:
                        try:
                            当前表[self.列表元素拼接(频繁模式打分)] += 1
                        except:
                            当前表.update({self.列表元素拼接(频繁模式打分): 1})
        频繁k模式列表 = {}
        for 频繁词 in 当前表:
            if 当前表[频繁词] > 0:
                频繁k模式列表.update({频繁词: 当前表[频繁词] / self.数据库长度})
        self.频繁模式总表.append([])
        self.频繁模式总表[-1].append(list(频繁k模式列表.keys()))
        self.频繁模式总表[-1].append(频繁k模式列表)
        pass

    def start(self):
        # while self.k < 5:
        self.频繁模式生成()

    def 关联规则提取与储存(self):
        strings = ''
        for i in self.频繁模式总表[1][0]:
            for j in self.频繁模式总表[0][0]:
                temp = i.split('+')
                if temp[0] == j or temp[1] == j:
                    置信度 = self.频繁模式总表[1][1][i] / self.频繁模式总表[0][1][j]
                    if 置信度 > 0.24:
                        print('<Class/主题词/{}> <Class/Relation/同一情报下> <Class/主题词/{}>'.format(temp[0], temp[1]))
                        strings += '<Class/topic/{}> <Class/Relation/one Description> <Class/topic/{}>\n'.format(
                            temp[0], temp[1])
        with open('out.xml', 'w') as f:
            f.write(strings)
        f.close()

结合上一次全部的数据挖掘过程

import csv
from math import log
from tqdm import tqdm
import itertools
# 读取数据
with open('attacks.csv', 'r', encoding='UTF-8') as csv文件:
    文件内容 = csv.reader(csv文件)
    文件内容列表 = list(文件内容)
    # print(文件内容列表)
    pass

# 列表存储词条
大词条库 = []
时间国家库 = []
时间城市库 = []
情报词库 = []


def 删除字符函数(输入0):
    """
    :param 输入0: 待处理的字符串
    :return: 删除无用字符后的字符串
    """
    删除字符 = "()[],.'&-…/1234567890:"
    处理 = 输入0
    for i in 删除字符:
        处理 = 处理.replace(i, ' ')
    # 由于 " 无法和 "" 同时出现,这里再进行一次删除后返回
    return 处理.replace('"', ' ')


for 序号0, 记录 in enumerate(文件内容列表):
    """
    记录[6]:即Description下的语句字符串
    删除字符函数(记录[6]):返回删除了无关字符的字符串
    删除字符函数(记录[6]).split(' '):以 " " 空格进行字符串划分,
                                返回一个分割成字符的列表
    然后添加进大词条库
    """
    大词条库.append(
        删除字符函数(记录[6]).split(' '))
    """
    当取出语句字符串后,将它删除,以便之后存入选好的主题词列表
    判断语句表示表头Description不做改动
    """
    if 序号0 != 0:
        文件内容列表[序号0].remove(记录[6])


class 我的tf_idf类:
    def __init__(self, 待处理大词条库, TFIDF阈值=0.3, 频繁模式阈值=0.2):
        """
        :param 待处理大词条库: 2维列表形式,第一维列表保存有一个段字库
        """
        self.初始大词条库 = 待处理大词条库
        self.语句总数 = len(待处理大词条库)
        self.总词条词频库 = []
        self.总词条单词评分库 = []

        self.词在句出现总频库 = {}

        self.TFIDF阈值 = TFIDF阈值
        self.总词条主题词库 = []

        self.频繁模式阈值 = 频繁模式阈值
        self.频繁模式表 = []

    def 语句词库(self, 词条分词库):
        """
        :param 词条分词库: 输入的是一条语句的词汇列表
        :return: 返回该词汇列表各个词汇的词频统计字典
                以及self.词在句出现总频库 这个是统计词汇在各个语句中出现的情况
        """
        """
        词条词频库:使用字典进行词频统计,字典使用字符串(称为键)进行索引,得到键值,
                键值反复被键(也就是某个词汇)索引累加,完成词频统计
        重复记录:在完成语句词频的统计时,也完成了对这个词在语句中出现的次数,
                由于一句只统计一次,所以需要在此记录一下,是否这个词在该列表被统计过了
        """
        词条词频库 = {}
        重复记录 = []
        for 单词 in 词条分词库:
            """
            这里出现的try/except都是为了做一件事,
            try:给字典里面的字符串键值加1,
            except:这个键不在字典里,则添加进去,初始化键值为1
            """
            try:
                词条词频库[单词] += 1
                """
                若单词在重复记录出现了,则跳过
                若没有,则记录入重复记录列表
                同时在self.词在句出现总频库中给这个词汇的键值加1
                """
                if 单词 in 重复记录:
                    pass
                else:
                    重复记录.append(单词)
                    try:
                        self.词在句出现总频库[单词] += 1
                    except:
                        self.词在句出现总频库.update({单词: 1})
                pass
            except:
                词条词频库.update({单词: 1})
                """
                若单词在重复记录出现了,则跳过
                若没有,则记录入重复记录列表
                同时在self.词在句出现总频库中给这个词汇的键值加1
                """
                if 单词 in 重复记录:
                    pass
                else:
                    重复记录.append(单词)
                    try:
                        self.词在句出现总频库[单词] += 1
                    except:
                        self.词在句出现总频库.update({单词: 1})
                pass
        return 词条词频库
        pass

    def 文本词库(self):
        """
        :return: None
        """

        """
        对每条语句词库重复调用
        在self.总词条词频库记录所有的语句以及其词频
        """
        for 词条 in self.初始大词条库:
            self.总词条词频库.append(self.语句词库(词条))
        pass

    def tf_idf函数(self, 单词条频库):
        """
        :param 单词条频库: 输入单词条评分
        :return: 无
        """
        """
        这里还使用了self.词在句出现总频库,
        也就是查找词在某些句子中出现的语句条数
        """
        单词评分库 = {}
        词总数 = sum(list(单词条频库.values()))
        for 单词 in 单词条频库:
            单词TF分数 = 单词条频库[单词] / 词总数
            单词IDF分数 = log(self.语句总数 / (self.词在句出现总频库[单词] + 1))
            单词评分库.update({单词: 单词TF分数 * 单词IDF分数})
        return 单词评分库

    def tf_idf加速函数(self):
        self.总词条单词评分库 = list(map(self.tf_idf函数, self.总词条词频库))
        pass

    def tf_idf阈值划分(self, 单词条评分):
        """
        :param 单词条评分: 输入单词条评分库
        :return:
        """
        主题词 = {}
        for 词汇 in 单词条评分:
            if 单词条评分[词汇] >= self.TFIDF阈值:
                主题词.update({词汇: 单词条评分[词汇]})
                pass
            pass
        return 主题词

    def tf_idf阈值划分加速函数(self):
        """
        对 tf_idf阈值划分调用
        :return: 无
        """
        self.总词条主题词库 = list(map(self.tf_idf阈值划分, self.总词条单词评分库))
        pass

    def TFIDF(self):
        """
        启动函数
        :return: 无
        """
        self.文本词库()
        self.tf_idf加速函数()
        self.tf_idf阈值划分加速函数()


class Apriori算法:
    def __init__(self, 数据库):
        """
        求取频繁模式
        :param 数据库: 输入的是一个二维列表,存储着一条一条的主题词或者关键字,
                    都是根据某一语义在其下共现的事务
        """
        self.数据库 = 数据库
        self.数据库长度 = len(数据库)
        self.k = 1
        self.事务数据最长长度 = 0
        self.频繁模式总表 = []
        self.当前频繁模式 = []
        self.历史频繁模式 = []
        self.频繁阈值 = 6 / len(数据库)
        """
        原处于各个位置的词汇都可以成为待选模式的一员
        """
        待选1模式 = {}
        for 词汇条 in self.数据库:
            if len(词汇条) > self.事务数据最长长度:
                self.事务数据最长长度 = len(词汇条)
            forin 词汇条:
                try:
                    待选1模式[] += 1
                except:
                    待选1模式.update({: 1})
        """
        根据出现的频次,按照阈值划分,去除待选模式的不频繁元素
        """
        频繁1模式列表 = {}
        for 频繁词 in 待选1模式:
            if 待选1模式[频繁词] / self.数据库长度 > self.频繁阈值:
                频繁1模式列表.update({频繁词: 待选1模式[频繁词] / self.数据库长度})
        self.频繁模式总表.append([])
        self.频繁模式总表[-1].append(list(频繁1模式列表.keys()))
        self.频繁模式总表[-1].append(频繁1模式列表)

    def 待选模式生成(self):
        """
        从频繁1模式中抽取 k个元素,构成新的集合,是原集合的 k元选组合
        :return:
        """
        if self.k < self.事务数据最长长度:
            temp = list(itertools.combinations(self.频繁模式总表[0][0], self.k))
            self.k += 1
            return temp
        else:
            return None

    @staticmethod
    def 查询函数(输入列表, 新元素, 查询参数):
        """
            函数功能是解决一个问题,在将一个元素(可以是一个字符串,也可以是一个列表)
            添加入新的列表时,先查询在这个列表是否存在了这个元素
            :param 输入列表: 待被添加进新元素的原列表
            :param 新元素: 待添加元素
            :param 查询参数: 新元素的数据长度
            :return: 布尔值:
                    True: 未存在(即可以添加的意思)
                    False: 已存在(就不添加了)
            """
        index = 0
        for 子元素 in 输入列表:
            查询元素个数 = 0
            for 查询元素个数 in range(查询参数):
                try:
                    if 子元素[查询元素个数] == 新元素[查询元素个数]:
                        查询元素个数 += 1
                except:
                    pass
            if 查询元素个数 == 查询参数 and 查询元素个数 != 0:
                index += 1
                break
        if index:
            return False
        else:
            return True

    @staticmethod
    def 列表元素拼接(输入列表):
        """
        由于k>=2的频繁模式,它的元素是k个字符串的集合,
        在做字典计数以及存储时,需要拼接,这里进行一下函数封装
        :param 输入列表: 待拼接列表
        :return: 拼接结果,以 + 作为拼接标识符
        """
        temp = ''
        for i in 输入列表:
            temp += i + '+'
        return temp[:-2]  # 末尾的 + 就不需要了

    def 频繁模式生成(self):
        self.当前频繁模式 = self.待选模式生成()
        self.历史频繁模式 = self.频繁模式总表[-1][0]
        """
        被注释掉的是一个优化过程,其子模式不是频繁模式
        那么它也不是,就不需要参与接下来的支持度查找了
        但是存在一定逻辑问题,当前并未加入这一段
        """
        # temp = []
        # for i in self.当前频繁模式:
        #     k = 0
        #     for j in self.历史频繁模式:
        #         if self.查询函数(i, j, len(j)):
        #             k += 1
        #     if k:
        #         temp.append(i)
        # self.当前频繁模式 = temp
        当前表 = {}
        for 频繁模式打分 in tqdm(self.当前频繁模式):
            for 词汇条 in self.数据库:
                if len(频繁模式打分) < len(词汇条):
                    pass
                else:
                    if self.查询函数(频繁模式打分, 词汇条, len(词汇条)):
                        pass
                    else:
                        try:
                            当前表[self.列表元素拼接(频繁模式打分)] += 1
                        except:
                            当前表.update({self.列表元素拼接(频繁模式打分): 1})
        频繁k模式列表 = {}
        for 频繁词 in 当前表:
            if 当前表[频繁词] > 0:
                频繁k模式列表.update({频繁词: 当前表[频繁词] / self.数据库长度})
        self.频繁模式总表.append([])
        self.频繁模式总表[-1].append(list(频繁k模式列表.keys()))
        self.频繁模式总表[-1].append(频繁k模式列表)
        pass

    def start(self):
        # while self.k < 5:
        self.频繁模式生成()

    def 关联规则提取与储存(self):
        strings = ''
        for i in self.频繁模式总表[1][0]:
            for j in self.频繁模式总表[0][0]:
                temp = i.split('+')
                if temp[0] == j or temp[1] == j:
                    置信度 = self.频繁模式总表[1][1][i] / self.频繁模式总表[0][1][j]
                    if 置信度 > 0.1:
                        print('<Class/主题词/{}> <Class/Relation/同一情报下> <Class/主题词/{}>'.format(temp[0], temp[1]))
                        strings += '<Class/topic/{}> <Class/Relation/one Description> <Class/topic/{}>\n'.format(
                            temp[0], temp[1])
        with open('out.xml', 'w') as f:
            f.write(strings)
        f.close()
####################################################################################################################
# 词的TF_IDF的评分计算
####################################################################################################################

工作啦 = 我的tf_idf类(大词条库, TFIDF阈值=0.35)
工作啦.TFIDF()

print(工作啦.总词条主题词库)


def 结果表格形式():
    """
    这个函数是为了把原来删掉了Description的文件内容列表
    填充进主题词列表,方便后面的主题词处理
    同时把待选的时间国家库/时间城市库提取做好
    :return:
    """
    import pandas as pd
    for 序号1, 主题词 in enumerate(工作啦.总词条主题词库):
        if 序号1 != 0:
            文件内容列表[序号1].append([])
            if 主题词:
                for 主题词0 in 主题词:
                    文件内容列表[序号1][-1].append(主题词0)
            else:
                文件内容列表[序号1][-1].append([])
    主题词提取 = pd.DataFrame(文件内容列表[1:], columns=文件内容列表[0]).drop(['index'], axis=1)
    print(主题词提取)
    for 序号3, 记录1 in enumerate(文件内容列表):
        # print(记录)
        if 记录1[6]:
            时间国家库.append([记录1[1], 记录1[2]])
            时间城市库.append([记录1[1], 记录1[3]])
    # print(主题词提取)


结果表格形式()


####################################################################################################################
# 等价语义划分
####################################################################################################################
def 查询函数(输入列表, 新元素, 查询参数):
    """
    函数功能是解决一个问题,在将一个元素(可以是一个字符串,也可以是一个列表)
    添加入新的列表时,先查询在这个列表是否存在了这个元素
    :param 输入列表: 待被添加进新元素的原列表
    :param 新元素: 待添加元素
    :param 查询参数: 新元素的数据长度
    :return: 布尔值:
            True: 未存在(即可以添加的意思)
            False: 已存在(就不添加了)
    """
    index = 0
    for 子元素 in 输入列表:
        查询元素个数 = 0
        for 查询元素个数 in range(查询参数):
            try:
                if 子元素[查询元素个数] == 新元素[查询元素个数]:
                    查询元素个数 += 1
            except:
                pass
        if 查询元素个数 == 查询参数 and 查询元素个数 != 0:
            index += 1
            break
    if index:
        return False
    else:
        return True


####################################################################################################################
# 基于情报语义
def 情报语义事务():
    """
    在从工作啦.总词条主题词库提取主题词至情报词库的过程中
    同时,进行该词库是否在情报词库进行判断
    :return: 无
    """
    """
    tqdm库是可以显示处理进度的函数包
    """
    for 词条主题词 in tqdm(工作啦.总词条主题词库):
        if 词条主题词:
            # if 查询函数(情报词库, list(词条主题词.keys()), len(词条主题词)):
                # good = list(词条主题词.keys())
                情报词库.append(list(词条主题词.keys()))


情报语义事务()

print(情报词库)


#########################################
# 基于时间国家语义
def 时间国家事务():
    """
    在从时间国家库提取关键字组合(即时间和国家的组合)
    至时间国家事务库0的过程中,
    同时,进行该是否在时间国家事务库0进行判断
    :return: 基于时间国家语义的时间国家事务库0
    """
    时间国家事务库0 = []
    for 序号2, 时间国家 in enumerate(时间国家库):
        if 序号2:
            if 查询函数(时间国家事务库0, 时间国家, 2):
                时间国家事务库0.append(时间国家)
    return 时间国家事务库0


时间国家事务库 = 时间国家事务()
print(时间国家事务库)


#########################################
# 基于时间城市语义
def 时间城市事务():
    """
    在从时间城市库提取关键字组合(即时间和城市的组合)
    至时间城市事务库0的过程中,
    同时,进行该是否在时间城市事务库0进行判断
    :return: 基于时间城市语义的时间城市事务0
    """
    时间城市事务库0 = []
    序号 = 0
    for 时间城市 in tqdm(时间城市库):
        if 序号:
            if 查询函数(时间城市事务库0, 时间城市, 2):
                时间城市事务库0.append(时间城市)
        序号 += 1
    return 时间城市事务库0


# 时间城市事务库 = 时间城市事务()
# print(时间城市事务库)

####################################################################################################################
# 频繁模式查找与规则输出
####################################################################################################################

工作1 = Apriori算法(情报词库[:1000])
工作1.待选模式生成()
工作1.start()
工作1.关联规则提取与储存()
print((工作1.频繁模式总表[0][0]))
print((工作1.频繁模式总表[1][0]))
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值