中文文本分类1

简介: 文本挖掘(Text Mining)是从非结构化文本信息中获取用户感兴趣或者有用的模式的过程。文本挖掘是指从大量文本数据中抽取事先未知的、可理解的、最终可用的知识的过程,同时运用这些知识更好地组织信息以便将来参考。

文本挖掘(Text Mining)是从非结构化文本信息中获取用户感兴趣或者有用的模式的过程。


文本挖掘是指从大量文本数据中抽取事先未知的、可理解的、最终可用的知识的过程,同时运用这些知识更好地组织信息以便将来参考


img_f3c118cef797d8260ccb5df801b839d4.png
img_29945fe6bb53c4973d49121b2e863149.png


img_0bbdae328e0845e1f5f77f2c059a7481.png


文本预处理

文本处理的核心任务是把非结构化和半结构化的文本转换为结构化的形式,即向量空间模型。

具体步骤:

1. 选择处理的文本范围

选择恰当的范围取决于文本挖掘任务的目标:

  • 对于分类聚类的任务,往往把整个文档作为处理单位;
  • 对于情感分析文档自动摘要信息检索,段落或章节可能更合适。

2. 建立分类文本语库

  • 训练集语料:已经分好类的文本资源。
  • 测试集语料:待分类的文本语料,可以是训练集的一部分,也可以是外部来源的文本语料。

中文语料库

img_7b5362399dc781ba44edb3e24671b45c.png
img_25fd5925fe97cfadeaa19d1d2b792827.png

3. 文本格式转换

img_16cf0138a02c901ca58e5931aa8a964e.png
img_d35a1952f6810c530ed290b4b4b473f5.png

import sys  
import os
import time
from lxml import etree, html
from sklearn.datasets.base import Bunch
import pickle
from time import time

root = 'D:/MLBook' + '/chapter02'
# htm文件路径,以及读取文件
path = root + "/1.htm"
with open(path, "rb") as fp:
    content = fp.read().decode()
    
page = html.document_fromstring(content) # 解析文件
text = page.text_content() # 去除所有标签
print(text[:100]) # 输出去除标签后解析结果
百度百科_百度百科(function(){window.PDC={_timing:{},_opt:{sample:0.01},_analyzer:{loaded:false,url:"http://s

4. 检测句子边界:标记句子的结束

img_05c24e44a15d55b891c8de6dc765bb87.png
img_7f926a0463e8f87f8933b3137e57154a.png

完全解决中文分词的算法是基于概率图模型的条件随机场(CRF)
img_1aed9402a13dfb0db2700c8fde5ebbad.png

import jieba

seg_list = jieba.cut("小明1995年毕业于北京清华大学", cut_all=False)
print("Default Mode:", " ".join(seg_list))  # 默认模式

seg_list = jieba.cut("小明1995年毕业于北京清华大学")
print("  ".join(seg_list))

seg_list = jieba.cut("小明1995年毕业于北京清华大学", cut_all=True)
print("Full Mode:", "/ ".join(seg_list))  # 全模式

seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,\
后在日本京都大学深造")  # 搜索引擎模式
print("/  ".join(seg_list))
Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\q7356\AppData\Local\Temp\jieba.cache
Loading model cost 0.992 seconds.
Prefix dict has been built succesfully.


Default Mode: 小明 1995 年 毕业 于 北京 清华大学
小明  1995  年  毕业  于  北京  清华大学
Full Mode: 小/ 明/ 1995/ 年/ 毕业/ 于/ 北京/ 清华/ 清华大学/ 华大/ 大学
小明/  硕士/  毕业/  于/  中国/  科学/  学院/  科学院/  中国科学院/  计算/  计算所/  ,/  后/  在/  日本/  京都/  大学/  日本京都大学/  深造
seg_list = jieba.cut("小明终于在1995年从北京清华大学毕业了。")
print("  ".join(seg_list))
小明  终于  在  1995  年  从  北京  清华大学  毕业  了  。
os.listdir(root+ '/train_corpus_seg')
['art',
 'computer',
 'economic',
 'education',
 'environment',
 'medical',
 'military',
 'politics',
 'sports',
 'traffic']
class Segment:
    def __init__(self, root):
        self.root = root
    
    def save_file(self, save_path, content):
        '''
        保存文件
        '''
        with open(save_path, 'wb') as fp:
            fp.write(content.encode())
            
    def read_file(self, path):
        with open(path, 'rb') as fp:
            content = fp.read().decode()
        return content
    
    def get_seg(self, corpus_path, seg_path):
        '''
        获取每个目录下所有的文件 mydir in catelist
        catelist = os.listdir(corpus_path)

        参数
        =====
        corpus_path::未分词分类语料库路径,例如:"train_corpus_small/"
        seg_path::分词后分类语料库路径,例如:"train_corpus_seg/"
        '''
        corpus_path = self.root + corpus_path
        seg_path = self.root + seg_path
        catelist = os.listdir(corpus_path)
        start = time()
        for i, mydir in enumerate(catelist):
            class_path = corpus_path + mydir + "/"    # 拼出分类子目录的路径
            seg_dir = seg_path + mydir + "/"          # 拼出分词后语料分类目录
            if not os.path.exists(seg_dir):           # 是否存在目录,如果没有创建
                os.makedirs(seg_dir)
            file_list = os.listdir(class_path)        # 获取 class_path 下的所有文件
            for k, file_path in enumerate(file_list):               # 遍历类别目录下文件
                fullname = class_path + file_path        # 拼出文件名全路径
                content = self.read_file(fullname).strip()     # 读取文件内容
                content = content.replace("\r\n", "")     # 删除换行和多余的空格
                content_seg = jieba.cut(content.strip())       # 为文件内容分词
                self.save_file(seg_dir + file_path, " ".join(content_seg))  # 将处理后的文件保存到分词后语料目录
                if k == 0 and i == 0:
                    print('保存分词后语料中......')
                    print('--' * 20)
            if i == 0:
                print('  完成语料分词的类别依次为:')
            print('\t%i: %s'%(i, mydir))
        print('--' * 20)
        print("总计花费时间 %g 秒,中文语料分词结束!!!"%(time() - start))
        
    def get_bunch(self, wordbag_path, seg_path):
        '''
        获取每个目录下所有的文件 mydir in catelist
        catelist = os.listdir(corpus_path)

        参数
        =====
        wordbag_path::分词语料 Bunch 对象持久化路径,例如:"train_word_bag/train_set.dat"
        seg_path::分词后分类语料库路径,例如:"train_corpus_seg/"
        '''
        wordbag_path = self.root + wordbag_path
        seg_path = self.root + seg_path
        catelist = os.listdir(seg_path)
        bunch = Bunch(target_name=[], label=[], filenames=[], contents=[])
        bunch.target_name.extend(catelist)        # 将类别信息保存到 Bunch 对象
        start = time()
        for i, mydir in enumerate(catelist):
            class_path = seg_path + mydir + "/"    # 拼出分类子目录的路径
            file_list = os.listdir(class_path)        # 获取 class_path 下的所有文件
            for k, file_path in enumerate(file_list):               # 遍历类别目录下文件
                fullname = class_path + file_path        # 拼出文件名全路径
                bunch.label.append(mydir)                # 保存当前文件的分类标签
                bunch.filenames.append(fullname)          # 保存当前文件的文件路径
                bunch.contents.append(self.read_file(fullname).strip())    # 保存文件词向量
                if k == 0 and i == 0:
                    print('构建文本对象中......')
                    print('--' * 20)
            if i == 0:
                print('  文本对象构建的类别依次为:')
            print('\t%i: %s'%(i, mydir))
        print('--' * 20)
        # 对象持久化                                                                                              
        with open(wordbag_path, "wb") as file_obj:
            pickle.dump(bunch, file_obj)  
        print("总计花费时间 %g 秒,构建文本对象结束!!!"%(time() - start))
        print("")
        return bunch
root = 'D:/MLBook/chapter02/'
corpus_path = "train_corpus_small/"  # 未分词分类语料库路径
seg_path = "train_corpus_seg/"      # 分词后分类语料库路径

S = Segment(root)
S.get_seg(corpus_path, seg_path)
保存分词后语料中......
----------------------------------------
  完成语料分词的类别依次为:
    0: art
    1: computer
    2: economic
    3: education
    4: environment
    5: medical
    6: military
    7: politics
    8: sports
    9: traffic
----------------------------------------
总计花费时间 19.8525 秒,中文语料分词结束!!!

在实际应用中,为了后续生成向量空间模型的方便,这些分词后的文本信息还要转换为文本向量信息并对象化。这里我们使用 Scikit-Learn 库的 Bunch 数据结构:

  • Bunch 类提供一种 (key, value) 的对象形式
  • target_name:所有分类集名称列表
  • label:每个文件的分类标签列表
  • filenames:文件路径
  • contents:分词后文件词向量形式
from sklearn.datasets.base import Bunch

将分好词的文本转换并持久化为 Bunch 类形式:

wordbag_path = "train_word_bag/train_set.dat"  # 分词语料 Bunch 对象持久化路径
seg_path = "train_corpus_seg/"      # 分词后分类语料库路径

S = Segment(root)
bunch = S.get_bunch(wordbag_path, seg_path)
构建文本对象中......
----------------------------------------
  文本对象构建的类别依次为:
    0: art
    1: computer
    2: economic
    3: education
    4: environment
    5: medical
    6: military
    7: politics
    8: sports
    9: traffic
----------------------------------------
总计花费时间 0.891003 秒,构建文本对象结束!!!

这样就在目录下生成了一个 train_set.dat 文件。此文件保存了所有训练集文件的所有分类信息,以及每个文件的文件名、文件所属分类和词向量。

Scikit-Learn 简介

img_737bb520c80ca71fe742b71a9e0ce6a2.png

向量空间模型

img_f60eaa3657d04b9cc851cde159aef82a.png

为节省存储空间和提高搜索效率,在文本分类之前会自动过滤掉某些字或词,这些字或词被称为停用词。这些词一般都是意义模糊的常用词和语气助词,通常它们对文本起不了分类特征的意义。

权重策略——TF-IDF 方法

文本1:My dog ate my homework
文本2:My cat ate the sandwich
文本3:A dolphin ate the homework
a = 'My dog ate my homework '
b = 'My cat ate the sandwich '
c = 'A dolphin ate the homework '
def str2list(s):
    return s.lower().strip(' ').split(' ')

def wordbag(*args):
    wb = []
    for t in args:
        wb.extend(str2list(t))
    return set(wb)

def word2vec(wb, t):
    a2 = []
    for k in wb:
        if k in str2list(t):
            a2.append(1)
        else:
            a2.append(0)
    return a2
wb = wordbag(*[a, b, c])
wb
{'a', 'ate', 'cat', 'dog', 'dolphin', 'homework', 'my', 'sandwich', 'the'}

将上述文本信息转换为词向量:

a2 = word2vec(wb, a)
b2 = word2vec(wb, b)
c2 = word2vec(wb, c)

print('文本1:', a2)
print('文本2:', b2)
print('文本3:', c2)
文本1: [1, 1, 0, 0, 1, 0, 0, 1, 0]
文本2: [0, 1, 1, 0, 0, 0, 1, 1, 1]
文本3: [1, 0, 0, 1, 0, 1, 1, 1, 0]

词频统计

def get_word_stat(w):
    d = {}
    for v in str2list(w):
        d[v] = d.get(v, 0) + 1
    return d

def word2vec(wb, t):
    L = []
    for k in wb:
        d = get_word_stat(t)
        if k in d.keys():
            L.append(d[k])
        else:
            L.append(0)
    return L
a2 = word2vec(wb, a)    # 'my' 出现了两次
b2 = word2vec(wb, b)
c2 = word2vec(wb, c)

print('文本1:', a2)
print('文本2:', b2)
print('文本3:', c2)
文本1: [1, 2, 0, 0, 1, 0, 0, 1, 0]
文本2: [0, 1, 1, 0, 0, 0, 1, 1, 1]
文本3: [1, 0, 0, 1, 0, 1, 1, 1, 0]

对词向量进行归一化,将其转换为概率分布

import numpy as np

def TF(t):
    a3 = np.array(t)
    return a3 / a3.sum()
a3 = TF(a2)    # 'my' 出现了两次
b3 = TF(b2)
c3 = TF(c2)

print('文本1:', a3)
print('文本2:', b3)
print('文本3:', c3)
文本1: [ 0.2  0.4  0.   0.   0.2  0.   0.   0.2  0. ]
文本2: [ 0.   0.2  0.2  0.   0.   0.   0.2  0.2  0.2]
文本3: [ 0.2  0.   0.   0.2  0.   0.2  0.2  0.2  0. ]

词频信息变成了概率分布,这就是文档的 TF 信息。
img_196022c9d4297abaa034fedbfe19afde.png
img_bf27bb6eb57088450315a9fb6b101434.png

def word2vec2(wb, t):
    L = []
    for k in wb:
        D = get_word_stat(a + b + c)
        d = get_word_stat(t)
        if k in d.keys():
            L.append(D[k])
        else:
            L.append(0)
    return L

def IDF(wb, t):
    e = word2vec2(wb, t)
    g = 3 / (np.array(e) + 1) 
    return np.log(g)
a4 = IDF(wb, a)    
b4 = IDF(wb, b)
c4 = IDF(wb, c)
TFIDF1 = a3 * a4
TFIDF2 = b3 * b4
TFIDF3 = c3 * c4
TFIDF1
array([ 0.        , -0.11507283,  0.        ,  0.        ,  0.08109302,
        0.        ,  0.        , -0.05753641,  0.        ])

下面我们使用 Scikit-Learn 包来实现 TF-IDF 算法:

def read_file(path):
    '''
    读取停用词表
    '''
    with open(path, "rb") as fp:
        content = fp.read()
    return content.decode()  # 转换为 string

class Word2Vector:
    
    def __init__(self, root):
        self.root = root
        
    def read_bunch(self, path):
        '''
        读取 bunch 对象
        '''
        with open(self.root + path, "rb") as file_obj:
            bunch = pickle.load(file_obj) 
        return bunch
    
    def write_bunch(self, path, bunchobj):
        '''
        写入 bunch 对象
        '''
        with open(self.root + path, "wb") as file_obj:
            pickle.dump(bunchobj, file_obj) 
            
    def read_stopword(self, stopword_path):
        '''
        读取停用词表
        
        示例
        =======
        path = "train_word_bag/hlt_stop_words.txt"
        '''
        return read_file(self.root + stopword_path).splitlines()
    
    def tfidf(self, stopword_path, path, space_path):
        '''
        参数
        ======
        stopword_path::停用词路径
        path::bunch 保存路径
        space_path::词向量词袋保存路径
        '''
        start = time()
        # 1. 读取停用词表
        stpwrdlst = self.read_stopword(stopword_path)

        # 2. 导入分词后的词向量 bunch 对象
        bunch = self.read_bunch(path)

        # 3. 构建 tf-idf 词向量空间对象
        tfidfspace = Bunch(target_name=bunch.target_name, label=bunch.label, 
                           filenames=bunch.filenames, tdm=[], vocabulary={})

        # 4. 使用 TfidfVectorizer 初始化向量空间模型 
        vectorizer = TfidfVectorizer(stop_words=stpwrdlst, sublinear_tf = True, max_df = 0.5)
        transformer = TfidfTransformer() # 该类会统计每个词语的 tf-idf 权值

        # 文本转为词频矩阵,单独保存字典文件 
        tfidfspace.tdm = vectorizer.fit_transform(bunch.contents)
        tfidfspace.vocabulary = vectorizer.vocabulary_

        # 创建词袋的持久化
        self.write_bunch(space_path, tfidfspace)
        print("花费时间:%g 秒,TF-IDF 词向量空间创建成功!!!"%(time() - start))
from sklearn import feature_extraction  
from sklearn.feature_extraction.text import TfidfTransformer  
from sklearn.feature_extraction.text import TfidfVectorizer  
WV = Word2Vector(root)
path = "train_word_bag/train_set.dat"        # 词向量空间保存路径
stopword_path = "train_word_bag/hlt_stop_words.txt"
space_path = "train_word_bag/tfdifspace.dat"        # 词向量空间保存路径

WV.tfidf(stopword_path, path, space_path)
花费时间:1.6075 秒,TF-IDF 词向量空间创建成功!!!
探寻有趣之事!
目录
相关文章
|
7月前
|
机器学习/深度学习 自然语言处理
机器翻译中的词性标注
机器翻译中的词性标注
84 2
|
7月前
|
机器学习/深度学习 自然语言处理 算法
机器翻译中的分词
机器翻译中的分词
104 2
|
机器学习/深度学习 JSON 自然语言处理
bert中文文本摘要代码(2)
bert中文文本摘要代码(2)
324 0
|
人工智能 自然语言处理 安全
中文竞技场-中文大模型比比看
今天,大语言模型正在各个应用领域引起巨大的变革,并已经在搜索、金融、办公、安全、教育、游戏、电商、社交媒体等领域迅速普及和应用。例如微软将 GPT4应用于必应搜索引擎和 Office 办公软件。几乎每个企业都试图探索如何将AI融入业务和技术中去。但以中文为主的语言大模型却缺少应有的关注,今天让我们聚焦中文竞技场,看看各种中文大语言模型的表现吧~
63720 1
中文竞技场-中文大模型比比看
|
7月前
|
机器学习/深度学习 自然语言处理 Java
中文自然语言处理相关资料 | Chinese NLP Toolkits 中文NLP工具
中文自然语言处理相关资料 | Chinese NLP Toolkits 中文NLP工具
|
存储 自然语言处理 PyTorch
bert中文文本摘要代码(1)
bert中文文本摘要代码(1)
142 0
|
存储 自然语言处理 并行计算
bert中文文本摘要代码(3)
bert中文文本摘要代码(3)
137 0
bert中文文本摘要代码(3)
|
人工智能
中文大语言模型的分析
为了体现分析的逻辑性,将会采用序数词排序对三个领域进行报告测评。
231 0
|
人工智能 自然语言处理
|
自然语言处理 Python
基于ERNIE3.0的中文评论分类
基于ERNIE3.0的中文评论分类
376 0
基于ERNIE3.0的中文评论分类
下一篇
DataWorks