Task2 特征提取

1. 基本文本处理技能

1.1 分词的概念(分词的正向最大、逆向最大、双向最大匹配法);

最大匹配法【Maximum Matching】MM

最大匹配是指以词典为依据,取词典中最长单词的字数量作为截取词的起始匹配长度,将截取后的最大长度的词与词典中的词进行比对(为提升扫描效率,还可以根据字数多少设计多个字典,然后根据字数分别从不同字典中进行扫描匹配), 直到还剩一个单字则终止,如果该单字无法切分,则作为未登录词处理(没有被收录在分词词表中但必须切分出来的词,包括各类专有名词(人名、地名、企业名等)、缩写词、新增词汇等等

举例:词典中最长词为“中华人民共和国”共7个汉字,则最大匹配起始字数为7个汉字。然后逐字递减,重新在对应的词典中循环比对

正向最大匹配法

从左往右地进行最大匹配法。尽可能地选择与词典中最长单词匹配的词作为目标分词,然后进行下一次匹配

举例:

待切分文本 计算语言学课程有意思

词典(表) {"计算", "计算语言学", "课程", "有", "意思"}(真实的词表中会有成千上万个平时我们使用的已经分好的词语)

匹配过程

确定最大匹配的起始子串字数为词典中最长单词的长度5

输入 计算语言学课程有意思

第一轮 取子串“计算语言学”,正向取词,如果匹配失败,每次去掉待匹配子串最后面的一个字

第1次. “计算语言学”,扫描词典表,匹配,输出“计算语言学”,输入变为“课程有意思”

第二轮 取子串“课程有意思”

第1次. “课程有意思”, 扫描词典表,不匹配,子串长度减一变为“课程有意”

第2次. “课程有意”, 扫描词典表,不匹配,子串长度减一变为“课程有”

第3次. “课程有”, 扫描词典表,不匹配,子串长度减一变为“课程”

第4次. “课程”, 扫描词典表,匹配,输出“课程”,输入变为“有意思”

第三轮 取子串“有意思”

第1次. “有意思”, 扫描词典表,不匹配,子串长度减一变为“有意”

第2次. “有意”, 扫描词典表,不匹配,子串长度减一变为“有”

第3次. “有”, 扫描词典表,匹配,输出“有”,输入变为“意思”

第四轮 取子串“意思”

第1次. “意思”,扫描词典表,匹配,输出“意思”,输入变为“”

输入长度为零,终止扫描。

最终分词结果为:计算语言学/课程/有/意思

逆向最大匹配算法 RMM

从右往左地进行最大匹配法。尽可能地选择与词典中最长单词匹配的词作为目标分词,然后进行下一次匹配。在实践中,逆向最大匹配算法性能通常优于正向最大匹配算法

栗子:

待切分文本 计算语言学课程有意思

词典(表) {"计算", "计算语言学", "课程", "有", "意思"}(真实的词表中会有成千上万个平时我们使用的已经分好的词语)

匹配过程

确定最大匹配的起始子串字数为词典中最长单词的长度5

输入 计算语言学课程有意思

第一轮 取子串“课程有意思”,逆向取词,如果匹配失败,每次去掉待匹配子串最前面的一个字

第1次. “课程有意思”,扫描词典表,不匹配,子串长度减一变为“程有意思”

第2次. “程有意思”,扫描词典表,不匹配,子串长度减一变为“有意思”

第3次. “有意思”,扫描词典表,不匹配,子串长度减一变为“意思”

第4次. “意思”,扫描词典表,匹配,输出“意思”,输入变为“计算语言学课程有”

第二轮 取子串“言学课程有”

第1次. “言学课程有”, 扫描词典表,不匹配,子串长度减一变为“学课程有”

第2次. “学课程有”, 扫描词典表,不匹配,子串长度减一变为“课程有”

第3次. “课程有”, 扫描词典表,不匹配,子串长度减一变为“程有”

第4次. “程有”, 扫描词典表,子串长度减一变为“有”

第5次. “有”, 扫描词典表,匹配,输出“有”,输入变为“计算语言学课程”

第三轮 取子串“语言学课程”

第1次. “语言学课程”, 扫描词典表,不匹配,子串长度减一变为“言学课程”

第2次. “言学课程”, 扫描词典表,不匹配,子串长度减一变为“学课程”

第3次. “学课程”, 扫描词典表,不匹配,子串长度减一变为“课程”

第4次. “课程”, 扫描词典表,匹配,输出“课程”,输入变为“计算语言学”

第四轮 取子串“计算语言学”

第1次. “计算语言学”,扫描词典表,匹配,输出“计算语言学”,输入变为“”

输入长度为零,终止扫描。

最终分词结果为:计算语言学/课程/有/意思

双向最大匹配法

两种算法都切一遍,然后根据大颗粒度词越多越好,非词典词(未登录词)和单字词越少越好的原则,选取其中一种分词结果输出

算法流程

  1. 比较正向最大匹配和逆向最大匹配结果

  2. 如果分词数量结果不同,那么取分词数量较少的那个

  3. 如果分词数量结果相同

    3.1 分词结果相同,可以返回任何一个

    3.2 分词结果不同,返回单字数比较少的那个

参考1

参考2

语言模型

  • unigram: 单word 也叫 词袋(bow Bag-Of-Word)
  • bigram: 双word
  • trigram: 3 word

举例

西安交通大学:

unigram形式为:北/京/交/通/大/学

bigram形式为: 北京/京交/交通/通大/大学

trigram形式为:北京交/安交通/交通大/通大学

1.2 词、字符频率统计;(可以使用Python中的collections.Counter模块,也可以自己寻找其他好用的库)

#coding=utf-8
import os
from collections import Counter
sumsdata=[]
for fname in os.listdir(os.getcwd()):
    if os.path.isfile(fname) and fname.endswith('.txt'):
        with open(fname,'r') as fp:
            data=fp.readlines()
            fp.close()
        sumsdata+=[line.strip().lower() for line in data]
cnt=Counter()
for word in sumsdata:
    cnt[word]+=1
cnt=dict(cnt)
for key,value in cnt.items():
    print(key+":"+str(value))

2. 语言模型

2.1 语言模型中unigram、bigram、trigram的概念;

unigram:是当n=1时,一个词的出现与它周围的词是独立的,称为unigram,一元语言模型。

bigram:是当n=2时,出现的词仅与前一个有关,称为bigram.二元语言模型。

trigram:当n=3时,出现的词仅与他前面的二个词有关,三元语言模型。

n-gram模型的参数就是条件概率P(Wi|Wi-n+1,...,Wi-1)。自由参数的数量级是n取值的指数倍,假设词表的大小为100,000,那么n-gram模型的参数数量为100,000^n。n越大效果越好,但随着n取值的增加,效果提升的幅度是在下降的。同时还涉及到一个可靠性和可区别性的问题,参数越多,可区别性越好,但同时单个参数的实例变少从而降低了可靠性。

2.2 unigram、bigram频率统计;(可以使用Python中的collections.Counter模块,也可以自己寻找其他好用的库)

3. 文本矩阵化:要求采用词袋模型且是词级别的矩阵化 步骤有: 分词(可采用结巴分词来进行分词操作,其他库也可以);去停用词;构造词表。 每篇文档的向量化。

3.1 分词

结巴中文分词涉及到的算法:
(1) 基于Trie树结构实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图(DAG); 
(2) 采用了动态规划查找最大概率路径, 找出基于词频的最大切分组合; 
(3) 对于未登录词,采用了基于汉字成词能力的HMM模型,使用了Viterbi算法。

结巴中文分词支持的3种分词模式: 

(1) 精确模式:试图将句子最精确地切开,适合文本分析; 
(2) 全模式:把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义问题; 
(3) 搜索引擎模式:在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。
核心代码:

import jieba

# 全模式
text = "我是计算机科学学院控制科学与工程研二的一名学生"
seg_list = jieba.cut(text, cut_all=True)
print(u"[全模式]: ", "/ ".join(seg_list))

# 精确模式
seg_list = jieba.cut(text, cut_all=False)
print(u"[精确模式]: ", "/ ".join(seg_list))

# 默认是精确模式
seg_list = jieba.cut(text)
print(u"[默认模式]: ", "/ ".join(seg_list))

# 搜索引擎模式
seg_list = jieba.cut_for_search(text)
print(u"[搜索引擎模式]: ", "/ ".join(seg_list))

3.2 新词识别

import jieba
#新词识别
seg_list = jieba.cut("我在广东万丈金数信息技术股份有限公司")
print(u"[新词识别]:","/".join(seg_list))
 

3.3 自定义词典

import jieba
jieba.load_userdict(file_name)
text = "故著名景点包括乾清宫、太和殿和黄琉璃瓦等"

# 全模式
seg_list = jieba.cut(text, cut_all=True)
print(u"[全模式]: ", "/ ".join(seg_list))

# 精确模式
seg_list = jieba.cut(text, cut_all=False)
print(u"[精确模式]: ", "/ ".join(seg_list))

# 搜索引擎模式
seg_list = jieba.cut_for_search(text)
print(u"[搜索引擎模式]: ", "/ ".join(seg_list))

3.5 关键词提取

import jieba
import jieba.analyse

# 导入自定义词典
jieba.load_userdict('F:\system\Anaconda3\Lib\site-packages\jieba\mydict.txt')

# 精确模式
text = "故宫的著名景点包括乾清宫、太和殿和午门等。其中乾清宫非常精美,午门是紫禁城的正门,午门居中向阳。"
seg_list = jieba.cut(text, cut_all=False)
print(u"分词结果:")
print("/".join(seg_list))

# 获取关键词
tags = jieba.analyse.extract_tags(text, topK=5)
print(u"关键词:")
print(" ".join(tags))

3.6 去除停用词

import jieba

# 导入自定义词典
jieba.load_userdict('F:\system\Anaconda3\Lib\site-packages\jieba\mydict.txt')

# 去除停用词
stopwords = {}.fromkeys(['的', '包括', '等', '是'])
text = "故宫的著名景点包括乾清宫、太和殿和午门等。其中乾清宫非常精美,午门是紫禁城的正门。"
# 精确模式
segs = jieba.cut(text, cut_all=False)
final = ''
for seg in segs:
    if seg not in stopwords:
        final += seg
print(final)

seg_list = jieba.cut(final, cut_all=False)
print("/ ".join(seg_list))

3.7构造词表

def build_vocab(train_dir, vocab_dir, vocab_size=5000):
    """根据训练集构建词汇表,存储"""
    data_train, _ = read_file(train_dir)

    all_data = []
    for content in data_train:
        all_data.extend(content)

    counter = Counter(all_data)
    count_pairs = counter.most_common(vocab_size - 1)
    words, _ = list(zip(*count_pairs))
    # 添加一个 <PAD> 来将所有文本pad为同一长度
    words = ['<PAD>'] + list(words)
    open_file(vocab_dir, mode='w').write('\n'.join(words) + '\n')

3.8 文档向量化

import jieba
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer


# 读取停用词
def read_stopword(filename):
    stopword = []
    fp = open(filename, 'r')
    for line in fp.readlines():
        stopword.append(line.replace('\n', ''))
    fp.close()
    return stopword


# 切分数据,并删除停用词
def cut_data(data, stopword):
    words = []
    for content in data['content']:
        word = list(jieba.cut(content))
        for w in list(set(word) & set(stopword)):
            while w in word:
                word.remove(w)
        words.append(' '.join(word))
    data['content'] = words
    return data


# 获取单词列表
def word_list(data):
    all_word = []
    for word in data['content']:
        all_word.extend(word)
    all_word = list(set(all_word))
    return all_word


# 计算文本向量
def text_vec(data):
    count_vec = CountVectorizer(max_features=300, min_df=2)
    count_vec.fit_transform(data['content'])
    fea_vec = count_vec.transform(data['content']).toarray()
    return fea_vec


if __name__ == '__main__':
    data = pd.read_csv('./cnews/test.txt', names=['title', 'content'], sep='\t')  # (10000, 2)

    stopword = read_stopword('./cnews/stopword.txt')
    data = cut_data(data, stopword)

    fea_vec = text_vec(data)
    print(fea_vec)

4. 参考 结巴分词介绍和使用:GitHub - fxsjy/jieba: 结巴中文分词

中文分词法https://blog.csdn.net/sysu63/article/details/80185555

中文分词 正向最大匹配法 逆向最大匹配法 双向最大匹配法http://blog.sina.com.cn/s/blog_53daccf401011t74.html

python实现统计文本中单词出现的频率https://blog.csdn.net/ls_6468/article/details/78519958

语言模型的基本概念https://www.cnblogs.com/Dream-Fish/p/3963028.html

自然语言处理之语言模型(LM)https://blog.csdn.net/qq_36330643/article/details/80143960

结巴中文分词介绍https://blog.csdn.net/haishu_zheng/article/details/80430106
 

猜你喜欢

转载自blog.csdn.net/yanyiting666/article/details/88169378