NLP基本步骤及原理

  • 本文目录
    • 第一章:文本预处理(Preprocess)
      • 1.1NLTK自然语言处理库
        • 1.1.1 NLTK自带语料库
    • 第二章:分词处理(Tokenize)
      • 2.1 NLTK分词
      • 2.2 结巴分词
      • 2.3 正则表达式分词
      • 2.4 词形处理
        • 2.4.1 Inflection变化——Stemming
        • 2.4.2 derivation引申——Lemmatization
      • 2.5 处理StopWords
    • 第三章:自然语言处理(Make Feature)
      • 3.1 情感分析
        • 3.1.1 Sentiment Dictionary(关键词打分)
        • 3.1.2 Machine Learning(朴素贝叶斯)
      • 3.2 文本相似度
        • 3.2.1 文本特征频率
      • 3.3 文本分类
        • 3.3.1 Term Frequency
        • 3.3.2 Inverse Document Frequency

文本处理的基本流程

  • 第一步:文本预处理(Preprocess)
  • 第二步:分词处理(Tokenize)
  • 第三步:生成对应特征向量(Make Feature)
  • 第四步:放入学习器学习(Machine Learning)
文本处理流程.png

第一章:文本预处理(Preprocess)

1.1 NLTK自然语言处理库

1.1.1 NLTK自带语料库

  1. 以下代码使用布朗大学语料库(nltk.corpus):
from nltk.corpus import brown
brown.categories()

输出:
['adventure', 'belles_lettres', 'editorial',
'fiction','government', 'hobbies','humor',
'learned', 'lore', 'mystery',
'news', 'religion', 'reviews',
'romance', 'science_fiction']

  1. 展示该语料库句子数
len(brown.sents())

输出:57340

  1. 展示该语料库单词数
len(brown.words())

输出 :1161192

第二章:分词处理(Tokenize)

将一段完整段落按词拆分,分词形式可分为以下两种:

  1. 启发式Heuristic(字典)
  2. 机器学习/统计方法:HMM、CRF

2.1 采用NLTK进行拆分

import nltk
sentence = "hello world"
tokens = nltk.wordpunct_tokenize(sentence)
tokens

输出: ['hello', 'world']

2.2 采用结巴分词进行拆分

import jieba
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))

输出:
Full Mode: 我/来到/北京/清华/清华大学/华大/大学
Default Mode: 我/来到/北京/清华大学
他,来到,网易,杭研,大厦
小明,硕士,毕业,于,中国,科学,学院,科学院,中国科学院,计算,计算所,,,后,在,日本,京都,大学,日本京都大

3.3 正则表达式

在博客和社交网络上,乱七八糟不合语法不和正常逻辑的语言有很多,比如表情,@某人,邮箱以及URL等,识别的方式是采用正则表达式。

不采用正则表达式分词

不采用正则表达式会将表情符号、话题以及URL等分开

from nltk.tokenize import word_tokenize
tweet = "RT @angelababy: love you baby! :D http://ah.love #168cm"
print(word_tokenize(tweet))

输出:['RT', '@', 'angelababy', ':', 'love', 'you', 'baby', '!', ':', 'D', 'http', ':', '//ah.love', '#', '168cm']

采用正则表达式分词

规定正则表达式:

  • emoticons_str:规定表情
  • regex_str:规定特殊字符串
import re
emoticons_str = r"""
    (?:
        [:=;] # 眼睛
        [oO\-]? # ⿐鼻⼦子
        [D\)\]\(\]/\\OpP] # 嘴
    )"""
regex_str = [
    emoticons_str,
    r'<[^>]+>', # HTML tags
    r'(?:@[\w_]+)', # @某⼈人
    r"(?:\#+[\w_]+[\w\'_\-]*[\w_]+)", # 话题标签
    r'http[s]?://(?:[a-z]|[0-9]|[$-_@.&amp;+]|[!*\(\),]|(?:%[0-9a-f][0-9a-f]))+', # URLs
    r'(?:(?:\d+,?)+(?:\.?\d+)?)', # 数字
    r"(?:[a-z][a-z'\-_]+[a-z])", # 含有 - 和 ‘ 的单词
    r'(?:[\w_]+)', # 其他
    r'(?:\S)' # 其他
]

匹配并分词

# re.VERBOSE代表允许你将注释写入re,这些注释会被引擎忽略
# re.IGNORECASE代表忽略大小写
tokens_re = re.compile(r'(' + '|'.join(regex_str) + ')', re.VERBOSE | re.IGNORECASE)
emoticons_re = re.compile(r'^' + emoticons_str + '$', re.VERBOSE | re.IGNORECASE)
# 找到符合正则表达式的所有字符串
def tokenize(s):
    return tokens_re.findall(s)
# 是否将找到的字符串进行大小写统一(表情除外)
def preprocess(s, lowercase=False):
    tokens = tokenize(s)
    if lowercase:
        tokens = [token if emoticons_re.search(token) else token.lower() for token in tokens]
    return tokens
tweet = "RT @angelababy: love you baby! :D http://ah.love #168cm"
print(preprocess(tweet))

输出:['RT', '@angelababy', ':', 'love', 'you', 'baby', '!', ':D', 'http://ah.love', '#168cm']

2.4 词形处理

  • Inflection变化:walk=>walking=>walked(都为动词,不影响词性)
    • Stemming词干提取:将不影响词性的词根去除
      • walking 除去ing=>walk
      • walked 除去ed =>walk
  • derivation引申:nation(n.)=>national(adj.)=>nationalize(v.)
    • Lemmatization词形归一:把各种类型的词的变形,都统一为一个形式
      • went归一 => go
      • are归一 => be

2.4.1 Stemming

使用Stemming可以进行Inflection

from nltk.stem.porter import PorterStemmer
porter_stemmer = PorterStemmer()
porter_stemmer.stem('multiply')
porter_stemmer.stem('provision')

输出:maximum、provis

from nltk.stem import SnowballStemmer
snowball_stemmer = SnowballStemmer("english")
snowball_stemmer.stem("maximum")
snowball_stemmer.stem("presumably")

输出:maximum、presum

2.4.2 Lemmatization

使用Lemmatization可以进行derivation

from nltk.stem import WordNetLemmatizer
wordnet_lemmatizer = WordNetLemmatizer()
wordnet_lemmatizer.lemmatize('knives')
# wordnet_lemmatizer.lemmatize('abaci')

输出:'knife'

需要注意以下情况

# 默认作为名词,所以没有这个单词,返回自己本身
wordnet_lemmatizer.lemmatize('are')
wordnet_lemmatizer.lemmatize('is')

输出:'is'

wordnet_lemmatizer.lemmatize('is', pos='v') # 指定为动词

输出:'be'
通过nltk可以对词性进行标注

import nltk
text = nltk.wordpunct_tokenize('what does the fox say')
nltk.pos_tag(text)

输出:
[('what', 'WDT'),
('does', 'VBZ'),
('the', 'DT'),
('fox', 'NNS'),
('say', 'VBP')]

2.5 处理StopWords

StopWords是指像中文当中“的、地、得、它、她和他”以及英文中"the"等停止词语,对文章意义没有用处的词语

from nltk.corpus import stopwords
# 先进行token分词,得到⼀个word_list
# ...
# 然后进行过滤filter
filtered_words = [word for word in word_list if word not in stopwords.words('english')]

文本预处理以及分词过程总结

文本预处理流水线.png

第三章:生成对应特征向量(自然语言处理)

将人能理解的语言转换为计算机语言即将词语转换为特征向量


自然语言处理.png

自然语言处理一般包括以下三方面应用:

  1. 情感分析
  2. 文本相似度
  3. 文本分类

3.1 情感分析

3.1.1 Sentiment Dictionary(关键词打分)

like 1分
good 2分
bad -2分
terrible -3分
打分机制:AFINN-111

sentiment_dictionary = {}
for line in open('data/AFINN-111.txt')
      word, score = line.split('\t')     sentiment_dictionary[word] = int(score)
# 把这个打分表记录在⼀一个Dict上以后
# 跑⼀一遍整个句句⼦子,把对应的值相加
total_score = sum(sentiment_dictionary.get(word, 0) for word in words) # 有值就是Dict中的值,没有就是0
# 于是你就得到了了⼀一个 sentiment score

缺点:太简单,不能增加新词,特殊词汇无法避免

3.1.2 配合Machine Learning

from nltk.classify import NaiveBayesClassifier
# 随⼿手造点训练集
s1 = 'this is a good book'
s2 = 'this is a awesome book'
s3 = 'this is a bad book'
s4 = 'this is a terrible book'
def preprocess(s):
    return {word: True for word in s.lower().split()}
# 把训练集给做成标准形式
training_data = [[preprocess(s1), 'pos'],
[preprocess(s2), 'pos'],
[preprocess(s3), 'neg'],
[preprocess(s4), 'neg']]
# 使用朴素贝叶斯算法
model = NaiveBayesClassifier.train(training_data)
# 打出结果
print(model.classify(preprocess('this is a good book')))

3.2 文本相似度

3.2.1 文本特征频率

第一步:频率统计
we you he work happy are
1 0 3 0 1 1
1 0 2 0 1 1
0 1 0 1 0 0
第二步:计算向量相似度(余弦定理)

\cos (\theta)=\frac{A \cdot B}{\|A\|\|B\|}

# 频率统计
import nltk
from nltk import FreqDist
corpus = 'this is my sentence ''this is my life ''this is the day'
tokens = nltk.word_tokenize(corpus)
print(tokens)

输出:['this', 'is', 'my', 'sentence', 'this', 'is', 'my', 'life', 'this', 'is', 'the', 'day']

fdist = FreqDist(tokens)
print(fdist['is'])

输出:3

#可以把最常⽤用的50个单词拿出来
standard_freq_vector = fdist.most_common(50)
size = len(standard_freq_vector)
print(standard_freq_vector)

输出:[('this', 3), ('is', 3), ('my', 2), ('sentence', 1), ('life', 1), ('the', 1), ('day', 1)]

将从大到小的顺序记录下来

def position_lookup(v):
    res={}
    counter = 0
    for word in v:
        res[word[0]] = counter
        counter += 1
    return res
standard_freq_dict = position_lookup(standard_freq_vector)
print(standard_freq_dict)

输出:{'this': 0, 'is': 1, 'my': 2, 'sentence': 3, 'life': 4, 'the': 5, 'day': 6}

sentence = "this is cool"
freq_vector = [0]*size
tokens = nltk.word_tokenize(sentence)
for word in tokens:
    try:
        freq_vector[standard_freq_dict[word]] += 1
    except KeyError:
        continue
print(freq_vector)

输出:[1, 1, 0, 0, 0, 0, 0]

3.3 文本分类

3.3.1 TF:Term Frequency,衡量一个term在文档中出现频率

TF\left( t \right) =\frac{t\text{在文档中的次数}}{\text{文档中的}term\text{总数}}

3.3.2 IDF:Inverse Document Frequency,衡量一个term有多重要

IDF\left( t \right) =\log \left( \text{文档总数/含}t\text{的文档总数} \right)

from nltk.text import TextCollection
corpus = TextCollection(['this is sentence one',
                        'this is sentence two',
                        'this is sentence three'])
print(corpus.tf_idf('this', 'this is sentence four'))

机器学习

可以使用各类机器学习或深度学习算法进行学习

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容