NLP原理及基础
以NLTK為基礎(chǔ)配合講解自然語(yǔ)言處理的原理
http://www.nltk.org/
Python上著名的自然語(yǔ)?處理庫(kù)
自帶語(yǔ)料庫(kù),詞性分類庫(kù)
自帶分類,分詞,等功能
強(qiáng)?的社區(qū)?持
還有N多的簡(jiǎn)單版wrapper,如 TextBlob
NLTK安裝
# Mac/Unix sudo pip install -U nltk # 順便便還可以裝個(gè)Numpy sudo pip install -U numpy # 測(cè)試是否安裝成功 >>> python >>> import nltk安裝語(yǔ)料庫(kù)
import nltk nltk.download()速度慢,可以在網(wǎng)頁(yè)https://raw.githubusercontent.com/nltk/nltk_data/gh-pages/index.xml里找鏈接,用迅雷下載
功能?覽表
NLTK?帶語(yǔ)料庫(kù)
>>> from nltk.corpus import brown >>> brown.categories() # 分類 ['adventure', 'belles_lettres', 'editorial', 'fiction', 'government', 'hobbies', 'humor', 'learned', 'lore', 'mystery', 'news', 'religion', 'reviews', 'romance', 'science_fiction'] >>> len(brown.sents()) # 一共句子數(shù) 57340 >>> len(brown.words()) # 一共單詞數(shù) 1161192文本處理流程
文本 -> 預(yù)處理(分詞、去停用詞) -> 特征工程 -> 機(jī)器學(xué)習(xí)算法 -> 標(biāo)簽
分詞(Tokenize)
把長(zhǎng)句?拆成有“意義”的?部件
>>> import nltk >>> sentence = “hello, world" >>> tokens = nltk.word_tokenize(sentence) >>> tokens ['hello', ‘,', 'world']中英文NLP區(qū)別:
英文直接使用空格分詞,中文需要專門的方法進(jìn)行分詞:
中文分詞:
import jieba seg_list = jieba.cut('我來(lái)到北京清華大學(xué)', cut_all=True) print('Full Mode:', '/'.join(seg_list)) # 全模式 seg_list = jieba.cut('我來(lái)到北京清華大學(xué)', cut_all=False) print('Default Mode:', '/'.join(seg_list)) # 精確模式 seg_list = jieba.cut('他來(lái)到了網(wǎng)易杭研大廈') # 默認(rèn)是精確模式 print('/'.join(seg_list)) seg_list = jieba.cut_for_search('小明碩士畢業(yè)于中國(guó)科學(xué)院計(jì)算所,后在日本京都大學(xué)深造') # 搜索引擎模式 print('搜索引擎模式:', '/'.join(seg_list)) seg_list = jieba.cut('小明碩士畢業(yè)于中國(guó)科學(xué)院計(jì)算所,后在日本京都大學(xué)深造', cut_all=True) print('Full Mode:', '/'.join(seg_list))Full Mode: 我/來(lái)到/北京/清華/清華大學(xué)/華大/大學(xué)
Default Mode: 我/來(lái)到/北京/清華大學(xué)
他/來(lái)到/了/網(wǎng)易/杭研/大廈 (jieba有新詞發(fā)現(xiàn)功能,“杭研”沒(méi)有在詞典中,但是也被Viterbi算法識(shí)別出來(lái)了)
搜索引擎模式: 小明/碩士/畢業(yè)/于/中國(guó)/科學(xué)/學(xué)院/科學(xué)院/中國(guó)科學(xué)院/計(jì)算/計(jì)算所/,/后/在/日本/京都/大學(xué)/日本京都大學(xué)/深造
Full Mode: 小/明/碩士/畢業(yè)/于/中國(guó)/中國(guó)科學(xué)院/科學(xué)/科學(xué)院/學(xué)院/計(jì)算/計(jì)算所///后/在/日本/日本京都大學(xué)/京都/京都大學(xué)/大學(xué)/深造
其他中文分詞工具:CoreNLP :java編寫,有命名實(shí)體識(shí)別、詞性標(biāo)注、詞語(yǔ)詞干化、語(yǔ)句語(yǔ)法樹(shù)的構(gòu)造還有指代關(guān)系等功能
對(duì)于 社交網(wǎng)絡(luò)上的文本,有很多不合語(yǔ)法不合正常邏輯的語(yǔ)言表達(dá):
@某人,表情符號(hào),URL,#話題符號(hào)(hashtag)等
如:Twitter上的語(yǔ)句推文
RT @angelababy: love you baby! :D http://ah.love #168cm
如果直接分詞:
from nltk.tokenize import word_tokenizetweet='RT @angelababy: love you baby! :D http://ah.love #168cm' print(word_tokenize(tweet))[‘RT’, ‘@’, ‘a(chǎn)ngelababy’, ‘:’, ‘love’, ‘you’, ‘baby’, ‘!’, ‘:’, ‘D’, ‘http’, ‘:’, ‘//ah.love’, ‘#’, ‘168cm’]
需要借助正則表達(dá)式,將表情符,網(wǎng)址,話題,@某人等作為一個(gè)整體,
對(duì)照表:http://www.regexlab.com/zh/regref.htm
[‘RT’, ‘@angelababy’, ‘:’, ‘love’, ‘you’, ‘baby’, ‘!’, ‘:D’, ‘http://ah.love‘, ‘#168cm’]
紛繁復(fù)雜的詞形
- Inflection 變化:walk=>walking=>walked 不影響詞性
- derivation 引申:nation(noun)=>national(adjective)=>nationalize(verb) 影響詞性
詞形歸一化
- Stemming 詞干提取(詞根還原):把不影響詞性的inflection 的小尾巴砍掉 (使用詞典,匹配最長(zhǎng)詞)
- walking 砍掉ing=>walk
- walked 砍掉ed=>walk
- Lemmatization 詞形歸一(詞形還原):把各種類型的詞的變形,都?xì)w一為一個(gè)形式(使用wordnet)
- went 歸一 => go
- are 歸一 => be
NLTK實(shí)現(xiàn)Stemming
from nltk.stem.lancaster import LancasterStemmer lancaster_stemmer=LancasterStemmer() print(lancaster_stemmer.stem('maximum')) print(lancaster_stemmer.stem('multiply')) print(lancaster_stemmer.stem('provision')) print(lancaster_stemmer.stem('went')) print(lancaster_stemmer.stem('wenting')) print(lancaster_stemmer.stem('walked')) print(lancaster_stemmer.stem('national'))maxim
multiply
provid
went
went
walk
nat
maximum
multipli
provis
went
went
walk
nation
maximum
multipli
provis
went
went
walk
nation
NLTK實(shí)現(xiàn) Lemmatization
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
問(wèn)題:Went v.是go的過(guò)去式 n.英文名:溫特
所以增加詞性信息,可使NLTK更好的 Lemmatization
are
is
be
be
NLTK標(biāo)注POS Tag
import nltk text=nltk.word_tokenize('what does the beautiful fox say') print(text) print(nltk.pos_tag(text))[‘what’, ‘does’, ‘the’, ‘beautiful’, ‘fox’, ‘say’]
[(‘what’, ‘WDT’), (‘does’, ‘VBZ’), (‘the’, ‘DT’), (‘beautiful’, ‘JJ’), (‘fox’, ‘NNS’), (‘say’, ‘VBP’)]
詞性符號(hào)對(duì)照表
Stopwords
一千個(gè) He 有一千種指代,一千個(gè) The 有一千種指示
對(duì)于注重理解文本【意思】的應(yīng)用場(chǎng)景來(lái)說(shuō)歧義太多
英文停止詞列表:https://www.ranks.nl/stopwords
NLTK有停用詞列表
[‘what’, ‘does’, ‘the’, ‘beautiful’, ‘fox’, ‘say’]
[‘beautiful’, ‘fox’, ‘say’]
?條typical的?本預(yù)處理流?線
根據(jù)具體task 決定,如果是文本查重、寫作風(fēng)格判斷等,可能就不需要去除停止詞
什么是自然語(yǔ)言處理?
自然語(yǔ)言——> 計(jì)算機(jī)數(shù)據(jù)
文本預(yù)處理讓我們得到了什么?
NLTK在NLP上的經(jīng)典應(yīng)?
- 情感分析
- 文本相似度
- 文本分類
應(yīng)用:情感分析
最簡(jiǎn)單的方法:基于情感詞典(sentiment dictionary)
類似于關(guān)鍵詞打分機(jī)制
like 1
good 2
bad -2
terrible -3
比如:AFINN-111
http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6010
預(yù)處理之后的詞: [‘I’, ‘went’, ‘Chicago’, ‘yesterday’, ‘,’, ‘fucking’, ‘day’, ‘!’]
該句子的情感得分: -4
消極
缺點(diǎn):新詞無(wú)法處理、依賴人工主觀性、無(wú)法挖掘句子深層含義
配上ML的情感分析
from nltk.classify import NaiveBayesClassifier# 隨手造點(diǎn)訓(xùn)練集 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):dic = ['this', 'is', 'a', 'good', 'book', 'awesome', 'bad', 'terrible']return {word: True if word in s else False for word in dic} # 返回句子的詞袋向量表示# 把訓(xùn)練集給做成標(biāo)準(zhǔn)形式 training_data = [[preprocess(s1), 'pos'],[preprocess(s2), 'pos'],[preprocess(s3), 'neg'],[preprocess(s4), 'neg']]# 喂給model吃 model = NaiveBayesClassifier.train(training_data) # 打出結(jié)果 print(model.classify(preprocess('this is a terrible book')))neg
文本相似度
使用 Bag of Words 元素的頻率表示文本特征
使用 余弦定理 判斷向量相似度
[‘this’, ‘is’, ‘my’, ‘sentence’, ‘this’, ‘is’, ‘my’, ‘life’, ‘this’, ‘is’, ‘the’, ‘day’]
3
[(‘this’, 3), (‘is’, 3), (‘my’, 2), (‘sentence’, 1), (‘life’, 1), (‘the’, 1), (‘day’, 1)]
{‘this’: 0, ‘is’: 1, ‘my’: 2, ‘sentence’: 3, ‘life’: 4, ‘the’: 5, ‘day’: 6}
[1, 1, 0, 0, 0, 0, 0]
應(yīng)用:文本分類
TF-IDF
TF:Term Frequency 衡量一個(gè)term 在文檔中出現(xiàn)得有多頻繁。
TF(t)=t出現(xiàn)在文檔中的次數(shù)文檔中的term總數(shù)
IDF:Inverse Document Frequency ,衡量一個(gè)term有多重要。
有些詞出現(xiàn)的很多,但明顯不是很有用,如 ‘is’’the’ ‘a(chǎn)nd’ 之類的詞。
IDF(t)=loge(文檔總數(shù)含有t的文檔總數(shù))
(如果一個(gè)詞越常見(jiàn),那么分母就越大,逆文檔頻率就越小越接近0。所以分母通常加1,是為了避免分母為0(即所有文檔都不包含該詞)。log表示對(duì)得到的值取對(duì)數(shù)。)
如果某個(gè)詞比較少見(jiàn),但是它在這篇文章中多次出現(xiàn),那么它很可能就反映了這篇文章的特性,正是我們所需要的關(guān)鍵詞。
TF?IDF=TF?IDF
NLTK實(shí)現(xiàn)TF-IDF
from nltk.text import TextCollection# 首先,把所有的文檔放到TextCollection類中 # 這個(gè)類會(huì)自動(dòng)幫你斷句,做統(tǒng)計(jì),做計(jì)算 corpus = TextCollection(['this is sentence one','this is sentence two',' is sentence three'])# 直接就能算出tfidf # (term:一句話中的某個(gè)term,text:這句話) print(corpus.tf_idf('this', 'this is sentence four'))# 對(duì)于每個(gè)新句子 new_sentence='this is sentence five' # 遍歷一遍所有的vocabulary中的詞: standard_vocab=['this' 'is' 'sentence' 'one' 'two' 'five'] for word in standard_vocab:print(corpus.tf_idf(word, new_sentence))得到了 TF-IDF的向量表示后,用ML 模型就行分類即可:
案例:關(guān)鍵詞搜索
kaggle競(jìng)賽題:https://www.kaggle.com/c/home-depot-product-search-relevance
Step1:導(dǎo)入所需
import numpy as np import pandas as pd from sklearn.ensemble import RandomForestRegressor, BaggingRegressor from nltk.stem.snowball import SnowballStemmer讀入訓(xùn)練/測(cè)試集
df_train = pd.read_csv('../input/train.csv', encoding="ISO-8859-1") df_test = pd.read_csv('../input/test.csv', encoding="ISO-8859-1") df_desc = pd.read_csv('../input/product_descriptions.csv') # 產(chǎn)品介紹看看數(shù)據(jù)們都長(zhǎng)什么樣子
df_train.head() df_desc.head() # 合并數(shù)據(jù)一起處理 df_all = pd.concat((df_train, df_test), axis=0, ignore_index=True) # 將產(chǎn)品描述根據(jù) product_uid 連接過(guò)來(lái) df_all = pd.merge(df_all, df_desc, how='left', on='product_uid') df_all.head()Step 2: 文本預(yù)處理
我們這里遇到的文本預(yù)處理比較簡(jiǎn)單,因?yàn)樽钪饕木褪强搓P(guān)鍵詞是否會(huì)被包含。
所以我們統(tǒng)一化我們的文本內(nèi)容,以達(dá)到任何term在我們的數(shù)據(jù)集中只有一種表達(dá)式的效果。
接下來(lái),把每一個(gè)column都跑一遍,以清潔所有的文本內(nèi)容
# 對(duì) 文字列進(jìn)行 詞干提取 df_all['search_term'] = df_all['search_term'].map(lambda x: str_stemmer(x)) df_all['product_title'] = df_all['product_title'].map(lambda x: str_stemmer(x)) df_all['product_description'] = df_all['product_description'].map(lambda x: str_stemmer(x))Step 3: 自制文本特征
# 關(guān)鍵詞的長(zhǎng)度 df_all['len_of_query'] = df_all['search_term'].map(lambda x:len(x.split())).astype(np.int64) # 標(biāo)題中有多少關(guān)鍵詞重合 df_all['commons_in_title'] = df_all.apply(lambda x:str_common_word(x['search_term'],x['product_title']), axis=1) # 描述中有多少關(guān)鍵詞重合 df_all['commons_in_desc'] = df_all.apply(lambda x:str_common_word(x['search_term'],x['product_description']), axis=1)把不能被『機(jī)器學(xué)習(xí)模型』處理的column給drop掉
df_all = df_all.drop(['search_term','product_title','product_description'],axis=1)Step 4: 重塑訓(xùn)練/測(cè)試集
總體處理完之后,再將訓(xùn)練集合測(cè)試集分開(kāi)
df_train = df_all.loc[df_train.index] df_test = df_all.loc[df_test.index]記錄下測(cè)試集的id
留著上傳的時(shí)候 能對(duì)的上號(hào)
分離出y_train
y_train = df_train['relevance'].values把原集中的label給刪去
X_train = df_train.drop(['id','relevance'],axis=1).values X_test = df_test.drop(['id','relevance'],axis=1).valuesStep 5: 建立模型
from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import cross_val_score # 用CV結(jié)果保證公正客觀性,調(diào)試不同的alpha值 params = [1, 3, 5, 6, 7, 8, 9, 10] test_scores = [] for param in params:clf = RandomForestRegressor(n_estimators=30, max_depth=param)test_score = np.sqrt(-cross_val_score(clf, X_train, y_train, cv=5, scoring='neg_mean_squared_error'))test_scores.append(np.mean(test_scores))畫個(gè)圖來(lái)看看:
import matplotlib.pyplot as plt %matplotlib inline plt.plot(params, test_scores) plt.title("Param vs CV Error");大概6~7的時(shí)候達(dá)到了最優(yōu)解
Step 6: 上傳結(jié)果
rf = RandomForestRegressor(n_estimators=30, max_depth=6) rf.fit(X_train, y_train) y_pred = rf.predict(X_test) pd.DataFrame({"id": test_ids, "relevance": y_pred}).to_csv('submission.csv',index=False)總結(jié):
這一篇教程中,雖然都是用的最簡(jiǎn)單的方法,但是基本框架是很完整的。
同學(xué)們可以嘗試修改/調(diào)試/升級(jí)的部分是:
文本預(yù)處理步驟: 你可以使用很多不同的方法來(lái)使得文本數(shù)據(jù)變得更加清潔
自制的特征: 相處更多的特征值表達(dá)方法(關(guān)鍵詞全段重合數(shù)量,重合比率,等等)
更好的回歸模型: 根據(jù)之前的課講的Ensemble方法,把分類器提升到極致
總結(jié)
- 上一篇: 可汗学院统计学17-24课笔记
- 下一篇: 学生表 成绩表 课程表 教师表