1. 程式人生 > >《用Python進行自然語言處理》第 1 章 語言處理與 Python

《用Python進行自然語言處理》第 1 章 語言處理與 Python

1. 將簡單的程式與大量的文字結合起來,我們能實現什麼?
2. 我們如何能自動提取概括文字風格和內容的關鍵詞和短語?
3. Python 程式語言為上述工作提供了哪些工具和技術?
4. 自然語言處理中的有哪些有趣的挑戰?

1.1 語言計算:文字和單詞

python入門

NLTK 入門

from nltk.book import *
import nltk
#找到這些文字
print(text1)
print(text2)
print(text3)

搜尋文字

#詞語索引檢視顯示一個指 定單詞的每一次出現,連同一些上下文一起顯示。
#查一下《白鯨記》中的詞 monstrous:
print(text1.concordance("monstrous"))
#使用 text2.concordance("affe ction")搜尋《理智與情感》中的詞 affection 
print(text2.concordance("affection"))


#還有哪些詞出現在相似的上下文中?我們可以通過在被查詢的 文字名後新增函式名 similar,然後在括號中插入相關的詞來查詢到。
print(text1.similar("monstrous"))
print(text2.similar("monstrous"))

#函式common_contexts允許我們研究兩個或兩個以上的詞共同的上下文
text2.common_contexts(["monstrous", "very"])
#圖. 美國總統就職演說詞彙分佈圖:可以用來研究隨時間推移語言使用上的變化
text4.dispersion_plot(["citizens", "democracy", "freedom", "duties", "America"])

計數詞彙

#文字中出現的詞和標點符號為單位算出文字從頭到尾的長度
print(len(text3))


##set(text3)  獲得 text3 的詞彙表
print(list(set(text3))[:10])


#得到一個詞彙項的排序表
#這個 表以各種標點符號開始,然後是以 A開頭的詞彙。大寫單詞排在小寫單詞前面。
print(list(sorted(set(text3)))[:10])
print(len(set(text3)))


# 對文字詞彙豐富度進行測量
#每個字平均被使用 了 16 次(我們需要確保 Python 使用的是浮點除法):
print(len(text3) / len(set(text3)))


#計數一個詞在文字中出現的次數,計算一個特定的詞
#在文字中佔據的百分比。
print(text3.count("smote"))
print(100 * text4.count("a") / len(text4))
#text5 中 lol 出現了多少次?它佔文字全部詞數的百分比是多少?
print(text5.count("lol"))
print(100 * text5.count("lol") / len(text5))


#定義函式
#對文字詞彙豐富度進行測量
def lexical_diversity(text):
    return len(text) / len(set(text))
#文字中佔據的百分比
def percentage(count, total):
    return 100 * count / total 
print(lexical_diversity(text3))
print(percentage(text4.count("a"), len(text4)))

1.2 近觀 Python:將文本當做詞連結串列

連結串列

#文字不外乎是詞和標點符號的序列
sent1 = ["Call", "me", "Ishmael", "."]
print(len(sent1))
print(lexical_diversity(sent1))


print(sent2)
print(sent3)


#連線
print(sent1 + sent4)


#追加
sent1.append("Some")
print(sent1)

索引列表

#索引
print(text4[173])


#也可以反過來做;找出一個詞第一次出現的索引
print(text4.index("awaken"))


#切片
print(text5[16715:16735])


#索引從零開始:第 0 個元素寫作 sent[0],其實是第 1 個詞“word1”;而句子的第 9 個元素是“word10”。
#原因很簡單:Python 從計算機記憶體中的連結串列獲取內容的時 候,我們要告訴它向前多少個元素。因此,向前 0 個元素使它留在第一個元素上。
sent = ['word1', 'word2', 'word3', 'word4', 'word5', 'word6', 'word7', 'word8', 'word9', 'word10']
print(sent[0])
print(sent[9])


sent[0] = "First"
sent[9] = "Last"
sent[1:9] = ["Second", "Third"]
print(sent)

1.3 計算語言:簡單的統計

saying = ['After', 'all', 'is', 'said', 'and', 'done', 'more', 'is', 'said', 'than', 'done']
tokens = set(saying)
print(tokens)
tokens = sorted(tokens)
print(tokens)
print(tokens[-2:])

頻率分佈

#我們如何能自動識別文字中最能體現文字的主題和風格的詞彙?
#使用 FreqDist 尋找《白鯨記》中最常見的 50 個詞
fdist1 = FreqDist(text1)
print(fdist1)


#注意:
##In Python 3 dict.keys() returns an iteratable but not indexable object
word_freq = [(word, freq) for (word, freq) in fdist1.most_common()]
print(word_freq[:5])

word = [word for (word, freq) in fdist1.most_common()]
print(word[:5])

freq = [freq for (word, freq) in fdist1.most_common()]
print(freq[:5])

print(word.index("whale"))

#《白鯨記》中 50 個最常用詞的累積頻率圖,這些詞佔了所有識別符號的將近一半
fdist1.plot(50, cumulative=True)

細粒度的選擇詞

#對於詞彙表 V 中的每一個詞 w,我們檢查 len(w)是否大於 15;所有其他詞彙將被忽略。
V = set(text1)
long_words = [w for w in V if len(w) > 15]
print(sorted(long_words)[:5])
V = set(text5)
long_words = [word for word in V if len(word) > 15]
print(sorted(long_words)[:5])


#尋找文字特徵詞彙的任務
#以下是聊天語料庫中所有長度超過 7 個字元出現次數超過 7 次的詞
#len(w) > 7 保證詞長都超過七個字母,fdist5[w]> 7保證這些詞出現超過 7 次。
fdist5 = FreqDist(text5)
print(sorted([w for w in set(text5) if len(w) > 7 and fdist5[w] > 7])[:5])

詞語搭配和雙連詞( bigrams)

#文字中出現的搭配很能體現文字的風格
#一個搭配是異乎尋常的經常在一起出現的詞序列。red wine 是一個搭配而 the wine 不是。 
#一個搭配的特點是其中的詞不能被類似的詞置換。例如: maroon wine(粟色酒)聽起來就 很奇怪。


#要獲取搭配,我們先從提取文字詞彙中的詞對也就是雙連詞開始。使用函式 bigrams() 很容易實現。
a = bigrams(['more', 'is', 'said', 'than', 'done'])  #生成器
print(list(a))


#除非我們更加註重包含不常見詞的的情況,搭配基本上就是頻繁的雙連詞。
#特別的,我們希 望找到比我們基於單個詞的頻率預期得到的更頻繁出現的雙連詞。
#collocations()函式為我 們做這些
print(text4.collocations())

計數其他東西

#檢視文字中詞長的分佈
print([len(w) for w in text1][:5])




#通過創造一長串數字的連結串列的 FreqDist,其中每個數字是文字中對應詞的長度。
fdist = FreqDist([len(w) for w in text1])
length_freq = [(length, freq) for (length, freq) in fdist.most_common()]
print(length_freq[:5])


length = [length for (length, freq) in fdist.most_common()]
print(length[:5])


freq = [freq for (length, freq) in fdist.most_common()]
print(freq[:5])


#最頻繁的詞長度是 3
print(fdist.max())
#長度為 3 的詞有 50,000 多個
print(fdist[3])
#頻率
print(fdist.freq(3))


fdist.plot()

NLTK頻率分佈類中定義的函式

fdist = FreqDist(samples)  建立包含給定樣本的頻率分佈

fdist.inc(sample)  增加樣本

fdist['monstrous']  計數給定樣本出現的次數

fdist.freq('monstrous')  給定樣本的頻率
fdist.N()   樣本總數
fdist.keys()  以頻率遞減順序排序的樣本連結串列
for sample in fdist:  以頻率遞減的順序遍歷樣本
fdist.max()  數值最大的樣本
fdist.tabulate()  繪製頻率分佈表
fdist.plot()  繪製頻率分佈圖
fdist.plot(cumulative=True)  繪製累積頻率分佈圖
fdist1 < fdist2  測試樣本在fdist1 中出現的頻率是否小於fdist2

1.4 回到 Python:決策與控制

條件

print(sent7)
print([w for w in sent7 if len(w) < 4])
print([w for w in sent7 if len(w) <= 4])
print([w for w in sent7 if len(w) == 4])
print([w for w in sent7 if len(w) != 4])
s.startswith(t)    測試 s 是否以 t 開頭
s.endswith(t)      測試 s 是否以 t 結尾
t in s             測試 s 是否包含 t
s.islower()        測試 s 中所有字元是否都是小寫字母
s.isupper()        測試 s 中所有字元是否都是大寫字母
s.isalpha()        測試 s 中所有字元是否都是字母
s.isalnum()        測試 s 中所有字元是否都是字母或數字
s.isdigit()        測試 s 中所有字元是否都是數字
s.istitle()        測試 s 是否首字母大寫(s 中所有的詞都首字母大寫)

#測試 s 是否以 t 開頭 s.startswith(t)
print(sorted([w for w in set(text1) if w.startswith('aba')])[:5])

#測試 s 是否以 t 結尾   s.endswith(t)
print(sorted([w for w in set(text1) if w.endswith('ableness')])[:5])

#測試 s 是否包含 tt in s
print(sorted([term for term in set(text4) if 'gnt' in term])[:5])

#測試 s 中所有字元是否都是小寫字母     s.islower()
print(sorted(item for item in set(text4) if item.islower() and len(item) > 15)[:5])

#測試 s 是否首字母大寫(s 中所有的詞都首字母大寫)       s.istitle()
print(sorted([item for item in set(text4) if item.istitle() and len(item) > 13])[:5])

對每個元素進行操作

#鏈式推導
print([len(w) for w in text1][:5])
print([w.upper() for w in text1 if len(w) > 15][:5])


print(len(text1))
print(len(set(text1)))
#過濾掉所有非字母元素,從詞彙表中消除數字和標 點符號。
print(len(set(word.lower() for word in text1 if word.isalpha())))

巢狀程式碼塊

word = 'cat'
if len(word) < 5:
    print("word length is less than 5")

    
word = 'cat'
if len(word) >= 5:
    print("word length is more than 5")
else:
    print("word length is less than 5")
    
    
#一個 if 語句叫做一個 控制結構 ,因為它控制縮排塊中的程式碼是否執行。另一個控制結構是 for 迴圈
for word in ['Call', 'me', 'Ishmael', '.']:
    print(word)    

條件迴圈

sent1 = ['Call', 'me', 'Ishmael', '.']
for xyzzy in sent1:
    if xyzzy.endswith('l'):
        print(xyzzy)
        
        
#首先,我們建立一個包含 cie 或者 c ei 的詞的連結串列,
#然後迴圈輸出其中的每一項。
tricky = sorted([w for w in set(text2) if 'cie' in w or 'cei' in w])
print(tricky[:5])
for word in tricky:
    print(word)
    break

1.5 自動理解自然語言

詞意消歧

在詞意消歧中,我們要算出特定上下文中的詞被賦予的是哪個意思

指代消解

一種更深刻的語言理解是解決“誰對誰做了什麼”,即檢測主語和動詞的賓語

處理這個問題的 計算技術包括指代消解(anaphora resolution)——確定代詞或名詞短語指的是什麼和 語義角色標註(semantic role labeling)——確定名詞短語如何與動詞相關聯(如施事,受 事,工具等)。

自動生成語言

如果我們能夠解決自動語言理解等問題,我們將能夠繼續那些包含自動生成語言的任 務,如自動問答和機器翻譯。

機器翻譯

給出一個德 文和英文雙語的文件或者一個雙語詞典,我們就可以自動配對組成句子,這個過程叫做文字 對齊。
一旦我們有一百萬或更多的句子對,就可以檢測出相應的詞和短語,並建立一個能用 來翻譯新文字的模型。

人機對話系統

文字的含義

NLP的侷限性

自然語言處理研究的一個重要目標一直是使 用淺顯但強大的技術代替無邊無際的知識和推理能力,促進構建“ 語言理解”技術的艱鉅任務 的不斷取得進展。
事實上,這是本書的目標之一,我們希望你能掌握這些知識和技能,構建 有效的自然語言處理系統,併為構建智慧機器這一長期的理想做出貢獻。

1.6 小結


在 Python 中文字用連結串列來表示: ['Monty', 'Python'] 。我們可以使用索引、分片和 len()函式對連結串列進行操作。
詞“token”(識別符號)是指文字中給定詞的特定出現;
詞“type ”(型別)則是指詞作為一 個特定序列字母的唯一形式。
我們使用 len(text)計數詞的識別符號,使用 len(set(text)) 計數詞的型別。
我們使用 sorted(set(t))獲得文字 t 的詞彙表。

我們使用[f(x) for x in text]對文字的每一專案進行操作。

為了獲得沒有大小寫區分和忽略標點符號的詞彙表,我們可以使用 set([w.lower() for w in text if w.isalpha()])。

我們使用 for 語句對文字中的每個詞進行處理,例如 for w in t:或者 for word in text:.後面必須跟冒號和一塊在每次迴圈被執行的縮排的程式碼。

我們使用 if 語句測試一個條件:if len(word)<5:。後面必須跟冒號和一塊僅當條件為真時執行的縮排的程式碼。

頻率分佈是專案連同它們的頻率計數的集合 (例如:一個文字中的詞與它們出現的頻率)

函式是指定了名字並且可以重用的程式碼塊。函式通過 def 關鍵字定義,例如在 def mult(x, y)中 x 和 y 是函式的引數,起到實際資料值的佔位符的作用。

函式是通過指定它的名字及一個或多個放在括號裡的實參來呼叫,就像這樣:mult(3,4)或者 len(text1)。