1,基本文本处理技能
1.1 分词的概念
最大匹配法,最大匹配是指以词典为依据的,去词典罪当单词的第一次取字数量的扫描串。在词典中进行扫描(为提升扫描效率,还可以根据字数多少设计多个字典,然后根据字数分别从不同字典中进行扫描,下面以“我们在野生动物园玩’'为例说明一下这几种匹配方法。
- 分词的正向最大
正向即从前往后取词,每次减一个字,知道词典命中或剩下1个单字。
正向即从前往后取词,从7->1,每次减一个字,直到词典命中或剩下1个单字。
第1次:“我们在野生动物”,扫描7字词典,无
第2次:“我们在野生动”,扫描6字词典,无
。。。。
第6次:“我们”,扫描2字词典,有
扫描中止,输出第1个词为“我们”,去除第1个词后开始第2轮扫描,即:
第2轮扫描:
第1次:“在野生动物园玩”,扫描7字词典,无
第2次:“在野生动物园”,扫描6字词典,无
。。。。
第6次:“在野”,扫描2字词典,有
扫描中止,输出第2个词为“在野”,去除第2个词后开始第3轮扫描,即:
第3轮扫描:
第1次:“生动物园玩”,扫描5字词典,无
第2次:“生动物园”,扫描4字词典,无
第3次:“生动物”,扫描3字词典,无
第4次:“生动”,扫描2字词典,有
扫描中止,输出第3个词为“生动”,第4轮扫描,即:
第4轮扫描:
第1次:“物园玩”,扫描3字词典,无
第2次:“物园”,扫描2字词典,无
第3次:“物”,扫描1字词典,无
扫描中止,输出第4个词为“物”,非字典词数加1,开始第5轮扫描,即:
第5轮扫描:
第1次:“园玩”,扫描2字词典,无
第2次:“园”,扫描1字词典,有
扫描中止,输出第5个词为“园”,单字字典词数加1,开始第6轮扫描,即:
第6轮扫描:
第1次:“玩”,扫描1字字典词,有
扫描中止,输出第6个词为“玩”,单字字典词数加1,整体扫描结束。
正向最大匹配法,最终切分结果为:“我们/在野/生动/物/园/玩”,其中,单字字典词为2,非词典词为1。 - 逆向最大
逆向即从后往前取词,其他逻辑和正向相同。即:
第1轮扫描:“在野生动物园玩”
第1次:“在野生动物园玩”,扫描7字词典,无
第2次:“野生动物园玩”,扫描6字词典,无
。。。。
第7次:“玩”,扫描1字词典,有
扫描中止,输出“玩”,单字字典词加1,开始第2轮扫描
第2轮扫描:“们在野生动物园”
第1次:“们在野生动物园”,扫描7字词典,无
第2次:“在野生动物园”,扫描6字词典,无
第3次:“野生动物园”,扫描5字词典,有
扫描中止,输出“野生动物园”,开始第3轮扫描
第3轮扫描:“我们在”
第1次:“我们在”,扫描3字词典,无
第2次:“们在”,扫描2字词典,无
第3次:“在”,扫描1字词典,有
扫描中止,输出“在”,单字字典词加1,开始第4轮扫描
第4轮扫描:“我们”
第1次:“我们”,扫描2字词典,有
扫描中止,输出“我们”,整体扫描结束。
逆向最大匹配法,最终切分结果为:“我们/在/野生动物园/玩”,其中,单字字典词为2,非词典词为0。 - 双向最大匹配法
正向最大匹配法和逆向最大匹配法,都有其局限性,我举得例子是正向最大匹配法局限性的例子,逆向也同样存在(如:长春药店,逆向切分为“长/春药店”),因此有人又提出了双向最大匹配法,双向最大匹配法。即,两种算法都切一遍,然后根据大颗粒度词越多越好,非词典词和单字词越少越好的原则,选取其中一种分词结果输出。
如:“我们在野生动物园玩”
正向最大匹配法,最终切分结果为:“我们/在野/生动/物/园/玩”,其中,两字词3个,单字字典词为2,非词典词为1。
逆向最大匹配法,最终切分结果为:“我们/在/野生动物园/玩”,其中,五字词1个,两字词1个,单字字典词为2,非词典词为0。
非字典词:正向(1)>逆向(0)(越少越好)
单字字典词:正向(2)=逆向(2)(越少越好)
总词数:正向(6)>逆向(4)(越少越好)
因此最终输出为逆向结果。
2.1 unigram、bigram、trigram的概念
unigram 一元分词,把句子分成一个一个的汉字
bigram 二元分词,把句子从头到尾每两个字组成一个词语
trigram 三元分词,把句子从头到尾每三个字组成一个词语
- 文本矩阵化:要求采用词袋模型且是词级别的矩阵化
步骤有:
3.1 分词(可采用结巴分词来进行分词操作,其他库也可以);
3.2 去停用词;构造词表。
3.3 每篇文档的向量化。
词向量矩阵生成过程
词向量矩阵生成按照以下过程:
加载数据集->分词->生成词汇表->生成word_index->加载预训练词向量模型->生成词向量矩阵
以下过程以THUCnews 数据集为例
\# -*- coding: utf-8 -*-
"""
Created on Mon Jun 24 17:31:21 2019@author: Administrator
NLP 第2天的学习任务
"""import pandas as pd
import numpy as np
train_file = 'cnews/cnews.train.txt'
val_file = 'cnews/cnews.val.txt'
test_file = 'cnews/cnews.test.txt'test_data = pd.read_csv(test_file,sep='\t',engine='python',names=['label','content'],encoding='UTF-8')
test_data = test_data.iloc[:100,:]
train_data = pd.read_csv(train_file,sep='\t',engine='python',names=['label','content'],encoding='UTF-8')
train_data = train_data.iloc[:100,:]
validation_data = pd.read_csv(val_file,sep='\t',engine='python',names=['label','content'],encoding='UTF-8')
train_data = train_data.iloc[:100,:]from multiprocessing import Pool, cpu_count
import re
import pkusegremove = re.compile('[\s\d,。?!~:“”;,.:?"!~$%^&@#¥#*()()、|/]')
def parallelize_dataframe(df, func):df_split = np.array_split(df, cpu_count())pool = Pool(cpu_count())df = pd.concat(pool.map(func, df_split))pool.close()pool.join()return df
seg = pkuseg.pkuseg()
def pku_cut(df):df['content'] = df['content'].apply(lambda x: re.sub(remove, '', str(x).strip()))#去除一些符号df['content'] = df['content'].apply(lambda x: seg.cut(x))#分词return df##分词
test_data = parallelize_dataframe(test_data, pku_cut)
train_data = parallelize_dataframe(train_data, pku_cut)
validation_data = parallelize_dataframe(validation_data, pku_cut)\## 去停词
stop_word_file='cnews/中文停用词表.txt'
def get_stop_words(filename=stop_word_file):stop_word=[]for line in open(filename,'r',encoding='utf-8'):stop_word.append(line.strip())return stop_word
stop_word = get_stop_words()
test_data['content']=test_data['content'].apply(lambda x:[w for w in x if w not in stop_word])
train_data['content']=train_data['content'].apply(lambda x:[w for w in x if w not in stop_word])
validation_data['content']=validation_data['content'].apply(lambda x:[w for w in x if w not in stop_word])##标签转id
categories = ['体育', '财经', '房产', '家居', '教育', '科技', '时尚', '时政', '游戏', '娱乐']
cat_to_id = dict(zip(categories, range(len(categories))))
train_data['label_id']=train_data["label"].apply(lambda x:cat_to_id[x])
test_data['label_id']=test_data["label"].apply(lambda x:cat_to_id[x])
validation_data['label_id']=validation_data["label"].apply(lambda x:cat_to_id[x])##保存好分词后的数据
import pickle
with open('train.pickle', 'wb') as handle: pickle.dump(train_data, handle, protocol=pickle.HIGHEST_PROTOCOL)
with open('test.pickle', 'wb') as handle: pickle.dump(test_data, handle, protocol=pickle.HIGHEST_PROTOCOL)
with open('val.pickle', 'wb') as handle: pickle.dump(validation_data, handle, protocol=pickle.HIGHEST_PROTOCOL)\## 加载数据
train = pickle.load( open ( 'train.pickle', "rb" ))
test = pickle.load( open ( 'test.pickle', "rb" ))
val = pickle.load( open ( 'val.pickle', "rb" ))all_content = pd.concat([train['content'],test['content'],val['content']]).values\## 计算词汇表与词频
from collections import defaultdict
def build_vocab(sentences):vocab = defaultdict(int) #将词汇表初始化为一个字典for i, sentence in enumerate(sentences):for word in sentence: ## split的原因是我读取的数据每一行是一个字符串,要将其分开,转为listvocab[word] += 1 #记录每个词出现的次数return vocab
vocab = build_vocab(all_content)vocab_list = [ key for key,value in vocab.items() ]
w2i = {w:i for i,w in enumerate(vocab_list)}
##将w2i存起来
import pickle
with open('cnews_w2i.pickle', 'wb') as handle: pickle.dump(w2i, handle, protocol=pickle.HIGHEST_PROTOCOL) vocab_sort= sorted(vocab.items(), key=lambda d:d[1], reverse = True)
vocab_list = [ key for key,value in vocab_sort]
vocab_list = vocab_list=vocab_list[:7000]