当前位置:   article > 正文

数据挖掘(一) TF-IDF算法

tf-idf算法

语句的主题词提取技术 TF-IDF

1、什么是情报的主题词

对于一段话,具有表征它描述内容的,可以称之为主题词。
在这里插入图片描述
这些都可以成为关键词,也就是说一句话可以有多个关键词,例如:

在这里插入图片描述
这样一句话,我们认为,王小二、山顶、求婚可以称之为主题词。

2、为什么要进行主题词的提取

作为用来进行计算机进行数据挖掘的材料,比较显然的是,通过一段描述性的话,是很难进行的。而用主题词来表征一句话的含义,可以很好的实现相关信息的查找。

3、如何进行主题词的提取

主题词的提取,在这里我们基于TF-IDF算法来实现。

3.1 算法思路

核心思想:词的重要性,可以被量化,通过分值的高低,实现主题词的提取。
算法实现的也就是词的重要性打分,而TF-IDF算法,也可以看作TF*IDF
也就是TF分
在这里插入图片描述

(比较好理解,一个词在语句中出现的次数很多,那么它可能比较重要)
和IDF分
在这里插入图片描述

(它的意思是,在多个语句中都出现词,像的、地、得这样的助词,没有实在的含义,基本不会成为主题词)
那么将TF值与IDF值相乘,所得到的TF*IDF则可以作为这个词在该句中的一个评分量化,进而根据设置阈值,大于这个阈值的词成为该句的主题词(所以一个句子,可以有多个主题词,也可以没有)

3.2 算法实现

使用python语言的实现过程

3.2.1 读取数据与预处理

使用的是csv文件
结构如下:
在这里插入图片描述
Description就是我们要处理的语句内容,在每一行的第7列(后面用6进行索引,列表计数从0开始),下面写个代码,读取一下

import csv
# 读取数据
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])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

效果
在这里插入图片描述
至此,我们得到了待处理的语句词条大列表了,其中每一个小列表,都是一条语句的词汇内容。

3.2.2 词频统计

这里完成了对词在语句中个数、以及词出现过的句子的数目的统计

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
'
运行
3.2.3 TF-IDF算法主体

完成了词汇数目的统计,下面的算法就很容易了

    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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

至此,需要的处理结果就提取到了

主函数显示结果

这里包括了TF-IDF的算法结果,还有基于不同语义下的等价类划分,直观的讲,就是将一些列抽出来,组成集合,再在集合内去除重复元素

import csv
from math import log
from tqdm import tqdm
# 读取数据
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阈值划分加速函数()

####################################################################################################################
# 词的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 = []
    for 序号3, 时间城市 in tqdm(enumerate(时间城市库)):
        if 序号3:
            if 查询函数(时间城市事务库0, 时间城市, 2):
                时间城市事务库0.append(时间城市)
    return 时间城市事务库0


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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318

工作啦.总词条主题词库所打印的,就是最后的主题词提取结果
下接
数据挖掘(二) Apriori算法的python实现

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/802110
推荐阅读
相关标签
  

闽ICP备14008679号