python 基于LDA算法的长文本主题提取分类并预测类别

python 基于LDA长文本主题提取并预测分类

导读

Lda算法原理,知乎上有很完善的算法介绍,这里就不多废话了。

本文主要是用来做文本主题提取,再根据这些主题对现有的文本进行分类。因为数据问题,效果一般,算法设计思路,仅供参考。

本文代码以及测试数据已上传github:仓库地址

数据准备

这一阶段主要是对你的问题本进行处理,清洗你的数据。中文文本预处理,主要包括去空格、去表单符号、去停用词、分词等。根据个人需求进行文本预处理。讲数据处理成下面数据格式即list套list的数据格式。

最初数据如下所示,一条一条文本,换行符分割。

在漆黑的夜空里看满天璀璨的星星,非常非常的密集,同时月亮也异常明亮。最主要的是在满天繁星中,靠近月亮的3颗星星排列成“勾”的样子,他们特别的明亮。

......................................................(省略好多数据)

沟里漂着很多死尸大人小孩都有,我顺着消流的方向走,看到臭水带着死尸流进了苹果园,我很怕!

经过初步处理后,也就是通过下文里面的deal_words()方法得到下面

 [['满天璀璨', '星星', '月亮', '明亮', '靠近', '排列'],........., ['沟里', '漂着', '死尸','大人小孩']]

具体数据处理可以参照:数据预处理

LDA模型实现

思路:

  1. 将训练数据和预测数据混合并提取词典库
  2. 利用词典库将训练数据转换成one-hot编码
  3. 利用gensim提供的API做模型提取主题
  4. 将混入的预测数据转换成one-hot编码
  5. 预测分类主题

这里模型采用gensim提供的API进行实现,代码如下:

def lad_model(train_data):
    # 读取预测分类数据
    test_data = deal_words(read_text_file('./data/set/test_text.txt'))
    # 拼接提取词典库
    contents = train_data + test_data
    # 根据文本获取词典
    dictionary = corpora.Dictionary(contents)
    # 词典创建语料库
    corpus = [dictionary.doc2bow(doc) for doc in train_data]
	#调用LDA模型,请求潜在主题数30;训练语料库2次
    lda = gensim.models.ldamodel.LdaModel(corpus, num_topics=30, id2word=dictionary,
                                          passes=2)
    #导出模型分类数量
    data = lda.print_topics(num_topics=3, num_words=5)
    # 打印主题,10个主题,20个单词
    for item in data:
        print(item) 
        print("--------------------split line---------------------")
    # 测试数据转换
    test_vec = [dictionary.doc2bow(doc) for doc in test_data]
	#预测并打印结果
    for i, item in enumerate(test_vec):
        topic = lda.get_document_topics(item)
        keys = target.keys()
        print('第',i+1,'条记录分类结果:',topic)

全部代码以及效果

lad模型代码以及处理数据代码。这里处理数据的核心代码text_deal.py,写在了同级目录(lda_demo)下面。

from lda_demo import text_deal as td
from gensim import corpora, models
import gensim

"""
读取text文件
intput:url
output:list结构的文本数据
"""


def read_text_file(url):
    dream_text = open(url, 'r+', encoding='utf-8')
    return dream_text.read().split("\n\n")


"""
停用词/分词
"""


def deal_words(contents):
    # 去除空格
    contents = td.remove_blank_space(contents)
    # 获取分词结果
    contents = td.cut_words(contents)
    # 去除停用词
    contents = td.drop_stopwords(contents)
    return contents

def lad_model(train_data):
    # 读取预测分类数据
    test_data = deal_words(read_text_file('./data/set/test_text.txt'))
    # 拼接提取词典库
    contents = train_data + test_data
    # 根据文本获取词典
    dictionary = corpora.Dictionary(contents)
    # 词典创建语料库
    corpus = [dictionary.doc2bow(doc) for doc in train_data]
	#调用LDA模型,请求潜在主题数30;训练语料库2次
    lda = gensim.models.ldamodel.LdaModel(corpus, num_topics=30, id2word=dictionary,
                                          passes=2)
    #导出模型分类数量
    data = lda.print_topics(num_topics=3, num_words=5)
    # 打印主题,10个主题,20个单词
    for item in data:
        print(item) 
        print("--------------------split line---------------------")
    # 测试数据转换
    test_vec = [dictionary.doc2bow(doc) for doc in test_data]
	#预测并打印结果
    for i, item in enumerate(test_vec):
        topic = lda.get_document_topics(item)
        keys = target.keys()
        print('第',i+1,'条记录分类结果:',topic)


  if __name__ == '__main__':
    # 据集读取
    contents = read_text_file('./data/set/train_text.txt')
    # 文本处理
    contents = deal_words(contents)
    # LDAmodel
    lad_model(contents)

text_deal.py代码如下:

"""
自然语言处理---文本预处理
"""
import jieba
import pandas as pd

"""
加载初始数据信息
str:文件传输路径
index:所需真实值索引列表
"""


def read_data(str, index):
    dream_data = pd.read_csv(str)
    return dream_data.values[:, index]


"""
去掉文本中的空格
input:our_data为list文本数据
output:去除空格后的文本list
"""


def remove_blank_space(contents):
    contents_new = map(lambda s: s.replace(' ', ''), contents)
    return list(contents_new)


"""
判断单词是否为中文
input:word单个单词
output:是中文True,不是中文False
"""


def is_chinese(word):
    if word >= u'\u4e00' and word <= u'\u9fa5':
        return True
    else:
        return False


"""
判断短句是否为纯中文
input:words短句
output:是中文True,不是中文False
"""


def is_chinese_words(words):
    for word in words:
        if word >= u'\u4e00' and word <= u'\u9fa5':
            continue
        else:
            return False
    return True


"""
将文本数据格式化去除非中文字符
input:contents list结构的文本数据
output:去除非中文字符的数据
"""


def format_contents(contents):
    contents_new = []
    for content in contents:
        content_str = ''
        for i in content:
            if is_chinese(i):
                content_str = content_str + i
        contents_new.append(content_str)
    return contents_new


"""
对文本进行jieba分词
input:contents文本list
output:分词后的文本list
"""


def cut_words(contents):
    cut_contents = map(lambda s: list(jieba.lcut(s)), contents)
    return list(cut_contents)


"""
去除停用词/标点符号
input:contents文本list(list中保存list)
output:去除停用词后的文本list
"""


def drop_stopwords(contents):
    # 初始化获取停用词表
    stop = open('./data/word_deal/stop_word_cn.txt', encoding='utf-8')
    stop_me = open('./data/word_deal/stop_one_mx.txt', encoding='utf-8')
    key_words = open('./data/word_deal/key_words.txt', encoding='utf-8')
    #分割停用词/自定义停用词/关键词
    stop_words = stop.read().split("\n")
    stop_me_words = stop_me.read().split("\n")
    key_words = key_words.read().split("\n")
    #定义返回后的结果
    contents_new = []
    #遍历处理数据
    for line in contents:
        line_clean = []
        for word in line:
            if (word in stop_words or word in stop_me_words) and word not in key_words:
                continue
            if is_chinese_words(word):
                line_clean.append(word)
        contents_new.append(line_clean)
    return contents_new

运行效果

(1, '0.023*"说" + 0.018*"怀孕" + 0.016*"父亲" + 0.014*"里" + 0.011*"岁"')
--------------------split line---------------------
(25, '0.023*"说" + 0.012*"办公室" + 0.010*"是不是" + 0.009*"朋友" + 0.009*"大门"')
--------------------split line---------------------
(20, '0.014*"同学" + 0.010*"跑" + 0.010*"培训" + 0.010*"骑" + 0.009*"机构"')
--------------------split line---------------------
第 1 条记录分类结果: [(4, 0.24392343), (8, 0.1395505), (10, 0.09619252), (18, 0.16527545), (21, 0.17173427), (23, 0.11055296)]
第 2 条记录分类结果: [(5, 0.124014), (13, 0.28862998), (16, 0.099018164), (19, 0.09216843), (24, 0.12537746), (29, 0.22633219)]
第 3 条记录分类结果: [(7, 0.101059936), (10, 0.37497482), (21, 0.15868592), (23, 0.19114888), (29, 0.12510397)]
第 4 条记录分类结果: [(1, 0.082532495), (4, 0.17312291), (14, 0.072532885), (17, 0.38016438), (19, 0.050784156), (21, 0.21228231)]
  1. 文本处理根据自己需求一定要做好,清洗掉不必要的数据;否则影响主题分类。
  2. 语料库全面结果会更加友好吧,在语料库范围内分类效果还是比较好的,但是新数据效果一般。

欢迎批评指正!

猜你喜欢

转载自blog.csdn.net/m0_47220500/article/details/105765841