Skip to content

Latest commit

 

History

History
148 lines (91 loc) · 6.04 KB

File metadata and controls

148 lines (91 loc) · 6.04 KB

词级别的各种处理总结

对于实际场景中的文本信息,需要经过一系列预处理后才能用来作为原始特征进行加工和建模。基本的流程是:先去除非文字类的各种符号,比如emoji、各种外文字母、空格、标点等;然后对中文进行切词处理,然后去除停用词。最后还可以计算tf-idf对各个词语的特异性进行表征,可能用于后续建模中对词语赋权。

对于不同任务,可能还需要进行不同的处理。比如,在基于搜索query的物品推荐时,需要对切分的词进行词性过滤,保留名词、专有名词等,对于涉及到明星和节目的视频推荐时,需要提取人名、专名等。在提取地理位置相关的特征时,需要过滤出地名等等。

正则化提取中文/英文/数字

一般通过Unicode范围进行约束,比如过滤提取中文的函数如下:

def is_hanzi(char):
    if char >= u'\u4e00' and char <= u'\u9fa5':
        return True
    else:
        return False
      
def filter_hanzi(sentence):
    res = ''
    for c in sentence:
        if is_hanzi(c):
          res += c
    return res

中文分词

通常用jieba工具对文本分词,git repo:https://github.com/fxsjy/jieba

jieba中基本分词算法:

  • 前缀字典建图 + 动态规划
  • OOV时用HMM+Viterbi计算

jieba分词:参数与使用

jieba分词可以采用全模式、精确模式、搜索引擎模式。如下:

# encoding=utf-8
import jieba

jieba.enable_paddle()# 启动paddle模式。 0.40版之后开始支持,早期版本不支持
strs=["我来到北京清华大学","乒乓球拍卖完了","中国科学技术大学"]
for str in strs:
    seg_list = jieba.cut(str,use_paddle=True) # 使用paddle模式
    print("Paddle Mode: " + '/'.join(list(seg_list)))

seg_list = jieba.cut("我来到北京清华大学", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list))  # 全模式

seg_list = jieba.cut("我来到北京清华大学", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list))  # 精确模式

seg_list = jieba.cut("他来到了网易杭研大厦")  # 默认是精确模式
print(", ".join(seg_list))

seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造")  # 搜索引擎模式
print(", ".join(seg_list))

各结果如下:

  • 全模式jieba.cut(s, cut_all=True)表示将所有的可能的词语都列举出来,比如【清华】【大学】是可以的,而【华大】也是可以的,那么虽然两种是不同的分法,但是都被列举出来了。
  • 精确模式jieba.cut(s, cut_all=False)即正常的按照最精确的方式划分,一般的文本分析中都用精确模式。
  • 搜索引擎模式jieba.cut_for_search是在精确模式基础上,对长词语,比如【中国科学院】继续划分,得到【中国】【科学】【学院】【科学院】等一大批可能的词,这个切词方法一般用于搜索引擎(尽可能保召回),因此被称为搜搜引擎模式。
【全模式】: 我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学

【精确模式】: 我/ 来到/ 北京/ 清华大学

【新词识别】:他, 来到, 了, 网易, 杭研, 大厦    (此处,“杭研”并没有在词典中,但是也被Viterbi算法识别出来了)

【搜索引擎模式】: 小明, 硕士, 毕业, 于, 中国, 科学, 学院, 科学院, 中国科学院, 计算, 计算所, 后, 在, 日本, 京都, 大学, 日本京都大学, 深造

停用词处理

去除无意义的虚词,比如连词、语气词等。就是简单地根据停用词表对分好词的list进行过滤筛选。比较著名的如哈工大停用词表。

可以参考:https://github.com/goto456/stopwords

tf-idf(词频-逆文档频率)提取关键词

tf-idf是term frequency和inverse document frequency的乘积,代表着某个word对于所在的document的重要性。term frequency即该word在本doc中出现的频率:

$ tf_i = n_i / \sum_{k\in doc} n_k$

Inverse document frequency即文档频率的倒数。所谓文档频率,指的是在所有文档中,有该word的文档的比例。这个文档频率反映的是word的特异性,即是不是只在这一篇文章中有,还是在所有文档中都有。因为有些词,如“的”、“你”、“了”等,其实就是前面说的停用词,虽然词频很高,但是并没有太多代表性,因此需要对这类词进行降权,所以对文档频率取倒数,即inverse document frequency,来表示词的特异性和代表性。

$idf_i = \log NDoc / NDoc(has_i)$

这里由于总文档数一般较大,因此求了log,tf-idf即两者的乘积。

最终只需要按照tf-idf排序,即可得到一篇文章中各个词的重要性。

tfidf的计算在sklearn中已经有现成的api可调用:

class sklearn.feature_extraction.text.TfidfTransformer(*, norm='l2', use_idf=True, smooth_idf=True, sublinear_tf=False)

可以直接根据语料统计后的结果与词典,计算出tfidf编码后的结果。下面是官方文档的实例:

>>> from sklearn.feature_extraction.text import TfidfTransformer
>>> from sklearn.feature_extraction.text import CountVectorizer
>>> from sklearn.pipeline import Pipeline
>>> import numpy as np
>>> corpus = ['this is the first document',
...           'this document is the second document',
...           'and this is the third one',
...           'is this the first document']
>>> vocabulary = ['this', 'document', 'first', 'is', 'second', 'the',
...               'and', 'one']
>>> pipe = Pipeline([('count', CountVectorizer(vocabulary=vocabulary)),
...                  ('tfid', TfidfTransformer())]).fit(corpus)
>>> pipe['count'].transform(corpus).toarray()
array([[1, 1, 1, 1, 0, 1, 0, 0],
       [1, 2, 0, 1, 1, 1, 0, 0],
       [1, 0, 0, 1, 0, 1, 1, 1],
       [1, 1, 1, 1, 0, 1, 0, 0]])
>>> pipe['tfid'].idf_
array([1.        , 1.22314355, 1.51082562, 1.        , 1.91629073,
       1.        , 1.91629073, 1.91629073])
>>> pipe.transform(corpus).shape
(4, 8)