从jieba分词到BERT-wwm——中文自然语言处理(NLP)基础分享系列(3)

中文的分词和文档的数字表示

要让电脑或是任何NLP 模型理解一篇新闻标题在说什么,我们不能将自己已经非常习惯的语言文字直接扔给电脑,而是要转换成它熟悉的形式:数字。

中文的分词

这里我们将一篇新闻标题视为一个“文档”,在中文的语言特征里,文档的基本单位主要由词构成。不同于英文的是,中文句子中没有词的界限,因此进行中文文档的数字表示时,通常需要先做分词以及词的编码。
常见的基于中文分词算法有:正向最大匹配法、逆向最大匹配法、双向匹配法、最优匹配法、联想-回溯法等。

借助 Jieba 这个中文分词工具,可以轻松实现中文的分词。

import jieba.posseg as pseg   

text = '一片大蒜轻松鉴别地沟油'  
words = pseg . cut ( text ) 
[ word for word in words ]  
Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\HP\AppData\Local\Temp\jieba.cache
Loading model cost 0.677 seconds.
Prefix dict has been built successfully.


[pair('一片', 'm'),
 pair('大蒜', 'n'),
 pair('轻松', 'a'),
 pair('鉴别', 'v'),
 pair('地沟油', 'n')]
TRAIN_CSV_PATH = "./train.csv" 
import pandas as pd 
train = pd . read_csv ( TRAIN_CSV_PATH , index_col = 0 ) 
cols = [ 'title1_zh' , 'title2_zh' , 'label' ] 
train = train . loc [:, cols ] 
train_nan = train[train[['title1_zh','title2_zh']].isnull().any(axis=1)] #训练集空值检查 
train_nan['title2_zh'].apply(lambda x: pd.isna(x)) 
id
48473     True
64312     True
220922    True
243368    True
247695    True
259536    True
291779    True
Name: title2_zh, dtype: bool

我们可以利用 Pandasapply 函数,将一个自定义的函数 jieba_tokenizer 套用到所有新闻标题A 以及B 之上,做文本分词:

def jieba_tokenizer ( text ): 
     if not(pd.isna(text)): 
            words = pseg . cut ( text ) 
            return ' ' . join ([ word for word , flag in words if flag != 'x' ]) ##标点符号去除 
     return ' ' 

train [ 'title1_tokenized' ] = \
     train . loc [:, 'title1_zh' ] \
          . apply ( jieba_tokenizer ) 
train [ 'title2_tokenized' ] = \
     train . loc [:, 'title2_zh' ] \
          . apply ( jieba_tokenizer )  

分词过程出乎意料的漫长,我们用 pickle 把结果持久化保存下来,以便之后可以继续快速使用。

import pickle 
 
pkl_file = open('./save_file', 'wb') 
pickle.dump(train,pkl_file,pickle.HIGHEST_PROTOCOL) 
pkl_file.close() 
 
pkl_file_rb = open(r'./save_file', 'rb') 
new_data =pickle.load(pkl_file_rb) 
new_data.head(2) 
title1_zh title2_zh label title1_tokenized title2_tokenized
id
0 2017养老保险又新增两项,农村老人人人可申领,你领到了吗 警方辟谣“鸟巢大会每人领5万” 仍有老人坚持进京 unrelated 2017 养老保险 又 新增 两项 农村 老人 人人 可 申领 你 领到 了 吗 警方 辟谣 鸟巢 大会 每人 领 5 万 仍 有 老人 坚持 进京
3 "你不来深圳,早晚你儿子也要来",不出10年深圳人均GDP将超香港 深圳GDP首超香港?深圳统计局辟谣:只是差距在缩小 unrelated 你 不 来 深圳 早晚 你 儿子 也 要 来 不出 10 年 深圳 人均 GDP 将 超 香港 深圳 GDP 首 超 香港 深圳 统计局 辟谣 只是 差距 在 缩小

下面一段内容我们先从李孟博士的博客里绕开,尝试一些更为简洁的NLP方法。

TF-IDF文档向量表示

完成分词之后,就可以进行文档的数字化表示。
可用的方法有很多,我们首先从常用的 TF-IDF文档向量表示方法入手。TF-IDF是一种向量空间模型(VSM:Vector Space Model),VSM中每个文档d可以用词典标引项向量来表示V(d)=(W1,W2,…Wm),Wi对应第i个标引词的权重。
VSM中权重的计算有:布尔权重(下图中的示例,仅标识文档中是否包含某词)、词频权重、TF-IDF权重、熵权重等,其中最广泛采用的便是TF-IDF权重。

从jieba分词到BERT-wwm——中文自然语言处理(NLP)基础分享系列(3)_第1张图片

TF-IDF的主要思想是,如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
TF词频(Term Frequency)指的是某一个给定的词语在该文件中出现的次数。
IDF逆文档频率(Inverse Document Frequency)的主要思想是:如果包含词条的文档越少,IDF越大,则说明词条具有很好的类别区分能力。
将TF和IDF相乘,形成TF-IDF度量:TF-IDF(d,t)= TF(d,t) * IDF(t) 。

我们可以使用 sklearn 包中的 TfidfVectorizer 函数实现文档的TF-IDF向量化表示。

from sklearn.feature_extraction.text import TfidfVectorizer 
 
corpus = pd.concat([train . title1_tokenized, train . title2_tokenized]) 
corpus = [c for c in corpus] 
corpus 
['2017 养老保险 又 新增 两项 农村 老人 人人 可 申领 你 领到 了 吗',
 '你 不 来 深圳 早晚 你 儿子 也 要 来 不出 10 年 深圳 人均 GDP 将 超 香港',
 '你 不 来 深圳 早晚 你 儿子 也 要 来 不出 10 年 深圳 人均 GDP 将 超 香港',
 '你 不 来 深圳 早晚 你 儿子 也 要 来 不出 10 年 深圳 人均 GDP 将 超 香港',
 '用 大蒜 鉴别 地沟油 的 方法 怎么 鉴别 地沟油',
 '你 不 来 深圳 早晚 你 儿子 也 要 来 不出 10 年 深圳 人均 GDP 将 超 香港',
 '吃 榴莲 的 禁忌 吃 错会 致命',
 ...]
vectorizer = TfidfVectorizer(min_df=1) 
vectorizer.fit_transform(corpus) 
<641104x67243 sparse matrix of type ''
	with 5064277 stored elements in Compressed Sparse Row format>

我们看到,通过训练得到了一个包含67243 个标引词的词典,每个新闻标题被转换为一个67243维的TF-IDF 向量表示。


好了,就到这儿。

本系列共12期,将分6天发布。相关代码已全部分享在我的github项目(moronism189/chinese-nlp-stepbystep)下,急的可以先去那里下载。

你可能感兴趣的:(python,机器学习,中文分词,nlp)