【聊天機器人】NLP知識

一、文本處理工具庫:

1、NLTK

python上著名的自然語言處理庫。自帶語料庫,詞性分類看;自帶分類,分詞,等功能。有強大的社區支持,和N多的簡單版wrapper(eg.TextBlob)

2、TextBlob 包–英文分析

TextBlob是一個用於處理文本數據的Python庫。對NLTK的封裝。它爲常見的自然語言處理(NLP)任務提供了一個簡單的API,例如詞性標註,名詞短語提取,情感分析,分類,翻譯等。結果:(-1,1)GitHub鏈接:https://github.com/sloria/TextBlob

3、SnowNLP包–中文分析

SnowNLP是一個python寫的類庫,可以方便的處理中文文本內容,是受到了TextBlob的啓發而寫的,由於現在大部分的自然語言處理庫基本都是針對英文的,於是寫了一個方便處理中文的類庫,並且和TextBlob不同的是,這裏沒有用NLTK,所有的算法都是自己實現的,並且自帶了一些訓練好的字典。SnowNLP用於情感分析方面(現在訓練數據主要是買賣東西時的評價,所以對其他的一些可能效果不是很好),而且它的分詞能力並沒有jieba強大。

4、金融相關API:

彭博社Bloomberg API(30k一個月)、Thomson Reuters(15K)、 Wind、大智慧、同花順數據API。

二、NLTK的介紹

1、模塊

在這裏插入圖片描述

2、NLTK使用

from nltk.corpus import brown  #從nltk語料庫中引入brown
brown.categories()  #brown中有哪些類型
print(len(brown.sents()))  #brown中的句子總數
print(len(brown.words()))  #brown中的單詞總數

三、文本處理流程

在這裏插入圖片描述

1、分詞:

分詞方式:
(1)啓發式分詞:Heuristic。基於查字典進行分詞。類比於relu_based
(2)機器學習/統計方法:HMM、CRF、nn、LSTM、RNN等。基於data進行分詞(HMM、CRF傳統模型是由公式計算是一個單詞的概率是多少(概率P);nn、LSTM、RNN深度學習是黑盒子)。類比於Generative
中文的字(1000個覆蓋約92%,2000字覆蓋98%以上,3000字則已到99%)相當於英文的字母(26個)
(3)案例
英文分詞:Tokenize

>>> import nltk
>>> sentence = “hello, world"
>>> tokens = nltk.word_tokenize(sentence)
>>> tokens
['hello', ',', 'world']

中文分詞庫:jieba

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)

【全模式】: 我/ 來到/ 北北京/ 清華/ 清華⼤大學/ 華⼤大/ ⼤大學
【精確模式】: 我/ 來到/ 北北京/ 清華⼤大學
【新詞識別】:他, 來到, 了了, ⽹網易易, 杭研, ⼤大廈
(此處,“杭研”並沒有在詞典中,但是也被Viterbi算法識別出來了了)
【搜索引擎模式】: 小明, 碩士, 畢業, 於, 中國, 科學, 學院, 科學院, 中國科學院, 計算,計算所, 後, 在, 日本, 京都, 大學, 日本京都大學, 深造
特殊符號:

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’]
輸出內容@+人名、網址等都是不需要的;:D表情文本沒有表示出其含義。可以利用正則表達式re,對這些內容進行刪除或轉化。
(4)正則表達式對照表:
http://www.regexlab.com/zh/regref.htm

import re
#識別表情O(∩_∩)O
emoticons_str = r"""
        (?:
            [:=;] #眼睛
            [oO\-]? #鼻子
            [D\)\]\(\]/\\OpP] #嘴 
         )"""
#識別特殊符號
regex_str = [
    emticons_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)' # 其他
]

注:虛詞:語義處理裏沒有用,但對於文本表面(如寫作水平等)是有用的。分詞可根據需要保留
(5)社交網絡中的分詞案例

tokens_re = re.compile(r'('+'|'.join(regex_str)+')', re.VERBOSE | re.IGNORECASE) 
emoticon_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 emoticon_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、英文的詞形還原:

(1)將不同的詞性(但意思相同)規範爲同一個表達式。如
Inflection時態變化(不要影響詞性):walk ==> walking ==> walked
derivation引申(詞性的變化):nation(noun) ==> national(adjective) ==> nationalize(veb)
(2)詞形歸一化方法
Stemming詞幹提取:一般是吧不影響詞性的時態的小尾巴砍掉
walking ==> walk
walked ==> walk
Lemmatization詞形歸一:把各種類型的詞的變形(查表),都歸爲一個形式
went ==> go
are ==> be
(3)代碼實現

  • Stemming代碼實現:
from nltk.stem.porter import PorterStemmer
porter_stemmer = PorterStemmer()
print(porter_stemmer.stem('maximum'))
print(porter_stemmer.stem('presumably'))
print(porter_stemmer.stem('multiply'))
print(porter_stemmer.stem('provision'))

輸出:
maximum
presum
multipli
provis

from nltk.stem import SnowballStemmer
snowball_stemmer = SnowballStemmer("english")
print(snowball_stemmer.stem('maximum'))
print(snowball_stemmer.stem('presumably'))
print(snowball_stemmer.stem('multiply'))
print(snowball_stemmer.stem('provision'))

maximum
presum
multipli
provis

from nltk.stem.lancaster import LancasterStemmer 
lancaster_stemmer = LancasterStemmer()
print(lancaster_stemmer.stem('maximum'))
print(lancaster_stemmer.stem('presumably'))
print(lancaster_stemmer.stem('multiply'))
print(lancaster_stemmer.stem('provision'))

輸出:
maxim
presum
multiply
provid

from nltk.stem.porter import PorterStemmer
p = PorterStemmer()
print(p.stem('went'))
print(p.stem('wenting'))

輸出:
went
went

  • Lemma代碼實現:
from nltk.stem import WordNetLemmatizer
wordnet_lemmatizer = WordNetLemmatizer()
print(wordnet_lemmatizer.lemmatize('dogs'))
print(wordnet_lemmatizer.lemmatize('churches'))
print(wordnet_lemmatizer.lemmatize('aardwolves'))
print(wordnet_lemmatizer.lemmatize('abaci'))
print(wordnet_lemmatizer.lemmatize('hardrock'))

輸出:
dog
church
aardwolf
abacus
hardrock

一般先使用詞性標註判斷出詞性,在使用Lemma進行詞形還原。
1、對於Went:v.go的過去是;n.英文名:溫特。直接使用Lemma無法正確還原
2、加入詞性後即可準確的進行詞形還原

#沒有POS Tag,默認爲NN 名詞
wordnet_lemmatizer.lemmatize('are')
wordnet_lemmatizer.lemmatize('is')

#加上POS Tag
wordnet_lemmatizer.lemmatize('are',pos='v')
wordnet_lemmatizer.lemmatize('is',pos='v')
  • NLTK詞性標註POS Tag:
import nltk
text = nltk.word_tokenize('what does the fox say')
print(text)
print(nltk.pos_tag(text))

輸出:
[‘what’, ‘does’, ‘the’, ‘fox’, ‘say’]
[(‘what’, ‘WDT’), (‘does’, ‘VBZ’), (‘the’, ‘DT’), (‘fox’, ‘NNS’), (‘say’, ‘VBP’)]

3、Stopwprds停用詞:

1、全體stopwords列表 http://www.ranks.nl/stopwords
2、nltk.download(‘stopwords’)
3、代碼實現

from nltk.corpus import stopwords 
# 先token,得到一個word_list 
# ... 
# 然後filter
filtered_words = [word for word in word_list if word not in stopwords.words('english')]

4、總結

文本的一般預處理流程:
除了NLTK外,斯坦福的:CORENLP庫指出中、英、西班牙文
在這裏插入圖片描述

四、文本表示----把句子按數字向量表達

機器學習:通過設定的規則去構造特徵。

1、True-False

步驟:建立字典、句子單詞出現即在字典對應記爲1
缺點:沒有考慮詞的重要性和順序關係

2、用元素頻率形式表示:

(1)含義
詞表位置需要固定,保持在一個空間內。文本表示相當於,每個詞都進行one-hot,在累加。
(2)優點:

  • 所有句子的向量長度都是一樣的,便於後期的機器學習
  • 向量的長度就是處理文本中不同的詞的個數
    (3)缺點:
    沒有考慮文本中詞與詞之間的順序關係。
    (4)步驟:
  • 建立字典
  • 句子單詞出現即在字典對應位置+1
  • 每個句子的維度變爲1*字典維度。語料庫字典是很重要的。
    如,
    he,he,he,we are happy
    he,he,he,we are
    you work
    每個句子對應的詞向量:
    在這裏插入圖片描述
    (5)代碼實現:
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)

#使用NLTK的FreqDist統計一下文字出現的頻率
fdist = FreqDist(tokens)
print(fdist)
print(fdist['is'])
#輸出最常見的50個單詞
standard_freq_vector = fdist.most_common(50)
size = len(standard_freq_vector)
print(size)
print(standard_freq_vector)
#按照詞頻大小,生成{詞:位置索引}字典
word_to_count = {}
for term in standard_freq_vector:
    word_to_count[term[0]] = term[1]
print(word_to_count)
#對於任意句子
sentence = 'this is cool'
#分詞
tokens = nltk.word_tokenize(sentence)
sentence_vector = []
for word in tokens:
    sentence_vector.append(word_to_count.get(word,0))

3、TF-IDF

單用頻率表示,無法真實表達出詞在該文本中的重要性,如某些公有詞雖然在文本中出現的次數多,可能在整個語料庫中都出現很多。
(1)TF: Term Frequency, 衡量⼀個term在⽂檔中出現得有多頻繁。
TF(t) = (t出現在⽂檔中的次數) / (⽂檔中的term總數)。
(2)IDF: Inverse Document Frequency, 衡量⼀個term有多重要。有些詞出現的很多,但是明顯不是很有卵⽤。⽐如’is’,’the‘,’and‘之類
的。爲了平衡,我們把罕見的詞的重要性(weight)搞⾼,把常見詞的重要性搞低。
IDF(t) = log_e(⽂檔總數 / 含有t的⽂檔總數).
(3)TFIDF=TFIDFTF-IDF = TF * IDF
(4)例子:

現在有10M的文檔,baby出現在其中的1000個文檔中。
IDF(baby) = log(10000000/1000) = 4
那麼來了一個文檔有100個單詞,其中單詞baby出現3次。
TF(baby) = (3/100) = 0.03
所以,TF-IDF(baby) = TF(baby) * IDF(baby) = 0.03 * 4 = 0.12

(5)代碼實現

from nltk.text import TextCollection
#首先, 把所有的⽂文檔放到TextCollection類中。 
#這個類會⾃自動幫你斷句句, 做統計, 做計算
corpus = TextCollection(['this is sentence one',
                        'this is sentence two',
                        'this is sentence three'])
#直接就能算出tfidf 
#(term:一句話中的某個term,text:這句話) 
print(corpus.tf_idf('this','this is sentence four'))

五、NLP經典案例

1、情感分析

案例一:簡單的情感詞字典

(1)介紹
一句話分詞後通過情感詞字典,對每個詞進行打分,最後得出句子情感得分。例如:like:1,good:2,bad:-2,terrible:-3。這代表着like的情感正面程度分值爲1,good的情感正面程度爲2,bad的情感正面程度爲-2,terrible的情感正面程度爲-3。
AFINN-111就是一個典型的情感字典:http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6010
下載後如圖:
在這裏插入圖片描述
(2)使用NLTK完成簡單的情感分析代碼實現:

#NLTK進行情感分析
import nltk


#建立情感字典
sentiment_dictionary ={}
for line in open('you_file\AFINN-111.txt'):
    word,score = line.split(' ')
    sentiment_dictionary[word] = int(score)  #構建{單詞:得分}字典

sentence_1 ='i love you!'
sentence_2 ='i hate you!'  
#分詞  
word_list1 = nltk.word_tokenize(sentence_1)
word_list2 = nltk.word_tokenize(sentence_2)
#遍歷每個句子,把每個詞的情感得分相加,不在情感字典中的詞分數全部置0
s1_score = sum(sentiment_dictionary.get(word,0) for word in word_list1)
s2_score = sum(sentiment_dictionary.get(word,0) for word in word_list2)
print('我是句子'+sentence_1+'的正面情感得分:',s1_score)
print('我是句子'+sentence_2+'的正面情感得分:',s2_score)

輸出結果:
我是句子i love you!的正面情感得分:3
我是句子i hate you!的正面情感得分:-3
(3)存在的問題:

  • 出現網絡新詞不在字典裏怎麼辦?
  • 出現特殊詞彙怎麼辦?
  • 更深層的語義怎麼理解?

案例二:配上ML的情感分析

from nltk.classify import NaiveBayesClassifier
from nltk import word_tokenize
#簡單手造的訓練集
s1 = 'i am a good boy'
s2 = 'i am a handsome boy'
s3 = 'he is a bad boy'
s4 = 'he is a terrible boy'

#預處理後得到字典類型:
#key表示fname對應句子中出現的單詞
#value表示每個文本單詞對應的值
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)
new_s1 = 'i am a good girl'
new_s2 = 'she is a terrible girl'
#輸出預測結果
print('我在預測 '+new_s1+' 結果是:',model.classify(preprocess(new_s1)))
print('我在預測 '+new_s2+' 結果是:',model.classify(preprocess(new_s2)))

輸出結果:
我在預測 i am a good girl 結果是: pos
我在預測 she is a terrible girl 結果是: neg

2、文本相似度

在句子被向量化後,我們根據餘弦定理便可計算出句子的相似度
similarity=cos(θ)=ABAB\displaystyle similarity=cos( \theta ) =\frac{A\cdot B}{\| A\| \cdot \| B\| }

3、文本分類

文本表示稱爲向量後,通過及其學習模型,對分類任務進行預測。
在這裏插入圖片描述

五、深度學習文本表示:讓機器去學習句子表達向量,而不是人爲的規定特徵

1、詞向量表示工具:

gensim:word2vec、tensorflow

2、詞編碼:

英文、ASII編碼(英文)、Unicode中文、自定義一個index編碼、電報編碼等,在進行深度學習時,輸入的詞約原始越好。

3、詞向量表達方式

(1)Auto-Encoder
無監督學習,工業上主要用於降維。
在這裏插入圖片描述
**(2)Word2vec:**單詞本身不是單獨存在於句子中間的,而是由周圍的詞決定。

4、文本相似度的表示:

(1)Full document: TF-IDF
(2)Window: co-occurrence matrix + SVD(2個單詞都出現的矩陣計算)不光關注在文章中出現的頻率,重點關注詞與詞之間的相關性
a.貢獻計數表
在這裏插入圖片描述
b.構建SVD矩陣:把任何形狀的矩陣, 都轉化爲三個向量相乘的矩陣。個性特徵:每一行代表自己的特有特徵
在這裏插入圖片描述
c.將特徵值取出,放在空間平面裏。做詞向量表達
在這裏插入圖片描述
應爲SVD計算複雜度很高,所以想到用兩邊定義中間的形式,去表達。

5、Word2vec

(1)Skip-gram:數據量少,經常出現稀有單詞時適合使用

(2)CBOW:比Skip-gram快,對於高頻詞的預測精度高

在這裏插入圖片描述
在這裏插入圖片描述

(3)步驟:

  • 文本預處理:去停用詞、小寫化、用正則表達式去除特殊符號或文本。進行分詞。文本處理後的形式,輸入到Word2Vec中:[[‘hello’, ‘how’], [‘fine’, ‘thank’]]
  • 文本表示
    1)使用from gensim.models import word2vec庫;
    2)設定參數(num_features最多多少個不不同的features、min_word_count⼀一個word,最少出現多少次 才被計⼊入、多少thread⼀一起跑(快⼀一點⼉兒)、embeding_size、windom_size前後觀察多⻓長的“語境)
    3)跑模型。生成每個次的詞向量
model = word2vec.Word2Vec(sentences, size=size, workers=num_workers, size=num_features, min_count = min_word_count, window = window)

(4)應用:

  • 輸出單詞在空間中的位置向量。詞向量表示
model['computer']

輸出:
array([-0.00449447, -0.00310097, 0.02421786, …], dtype=float32)

  • 求兩個詞的senmatics相似度
model.similarity('woman', 'man')

輸出:0.73723527

  • 通過語義,利用空間距離計算。單詞和概率。
#woman + king - man = queen
model.most_similar(positive=['woman', 'king'], negative=['man'])

輸出:
[(‘queen’, 0.50882536), …]

六、機器人應用:intents

在這裏插入圖片描述
“你好嗎?”——>向量,“你最近怎麼樣”——>向量
通過word2vec、tf-idf等形式,把句子把句子表達爲向量形式。
無監督學習:KNN做聚類,計算兩個句子的距離是否小於某個閾值,如果小於則認爲屬於一類,可以使用同一個回答
有監督學習:分類問題。
根據網上的語料庫,輸入詞向量,確定它屬於那個標籤。
在這裏插入圖片描述

七、思考:

這個時候你會發現,我們的vec是針對每個word的。而我們的訓練集是sen和label互相對應的,
工業上,到了這一步,有三種解決方案:
1、平均化一個句子裏所有詞的vec。
sen_vec = [vec, vec, vec, …] / n
2、排成一個大matrix (M * N),等着CNN進行特徵提取。
[ vec | vec | vec | vec | … ]
3、用Doc2Vec。這是基於句子的vec,跟word2vec差不多思路路,用起來也差不多。
只對長篇 大文章效果好。對頭條新聞,twitter這種的東西,就不行了。每一篇的就太少。
具體可以看gensim。

參考文獻:文本爲七月在線《自動聊天機器人項目班》學習筆記

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章