顯示具有 NLTK 標籤的文章。 顯示所有文章
顯示具有 NLTK 標籤的文章。 顯示所有文章

2022年4月10日 星期日

Colab 無法載入 NLTK 的 gutenberg 語料庫問題

今天在演練 "深度學習的 16 堂課" 第 11 章關於建立詞向量空間的語料庫預處理時, 發現在 Colab 上無法載入 gutenburg 語料庫, 首先輸入下列兩個前置指令 :

%matplotlib inline # 繪圖用
from google.colab import drive # 載入雲端硬碟模組
drive.mount('/content/drive') # 存取雲端硬碟下檔案用


然後匯入要用到的套件與模組 :

import nltk
from nltk import word_tokenize, sent_tokenize
from nltk.corpus import stopwords, gutenberg
from nltk.stem.porter import *
import string
import gensim
from gensim.models.phrases import Phraser, Phrases
from gensim.models.word2vec import Word2Vec
from sklearn.manifold import TSNE
import pandas as pd
from bokeh.io import output_notebook, output_file
from bokeh.plotting import show, figure




接著下載 guternberg 語料庫與停用字等 :

nltk.download('gutenburg'# 下載 gutenburg 語料庫
nltk.download('punkt')   # tokenizer
nltk.download('stopwords'# 停用字

但執行第一個下載指令時卻出現如下錯誤 :

"Error loading gutenburg: Package 'gutenburg' not found in index"




查詢 Stackoverflow 等論壇皆無果, 不知原因為何. Colab 雖然好好用, 但是有一些限制, 例如它沒辦法執行 GUI 程式也是一個問題. 看來只好在本機上執行了, 因我之前在筆電上有下載全部 NLTK 語料庫 (很大).

2021年11月14日 星期日

NLTK 學習筆記 (三) : nltk.book.text1~9 語料庫

NLTK 安裝以來一直沒有時間學習, 雖然我更想學較新的 SpaCy, 但 NLTK 是 NLP 很經典的自然語言學習套件, 所以還是要涉獵一番, 這樣在學 SpaCy 時也好有個比較的對象. 本篇主要是檢視 NLTK 語料庫中的 book.text1~9 這 9 個語料庫, 是最近閱讀下列這本書第一章的測試筆記 : 


本系列之前的文章參考 :



1. Text 物件的屬性與方法 :

在 nltk.book 子套件中收錄了 text1~text9 共九本書的語料庫, 它們都是 Text 物件, 首先從 nltk.book 匯入全部物件, 它會馬上回應 text1~textt9 這九本書的書名 :

>>> from nltk.book import *   
*** Introductory Examples for the NLTK Book ***
Loading text1, ..., text9 and sent1, ..., sent9
Type the name of the text or sentence to view it.
Type: 'texts()' or 'sents()' to list the materials.
text1: Moby Dick by Herman Melville 1851
text2: Sense and Sensibility by Jane Austen 1811
text3: The Book of Genesis
text4: Inaugural Address Corpus
text5: Chat Corpus
text6: Monty Python and the Holy Grail
text7: Wall Street Journal
text8: Personals Corpus
text9: The Man Who Was Thursday by G . K . Chesterton 1908

以內建函式 type() 檢查 nltk.book.text1~9 可知 text1~text9 均為 Text 物件, 呼叫 dir() 函式可檢視 Text 物件的成員, 以 text1 為例 : 

>>> type(text1)               # text1~9 都是 Text 物件 
<class 'nltk.text.Text'>   

將 text1~text9 傳入 dir() 會傳回 Text 物件的成員串列, 以 text1 為例 : 

>>> dir(text1)                 # 傳回 Text 物件的成員串列
['_CONTEXT_RE', '_COPY_TOKENS', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__len__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_context', '_train_default_ngram_lm', 'collocation_list', 'collocations', 'common_contexts', 'concordance', 'concordance_list', 'count', 'dispersion_plot', 'findall', 'generate', 'index', 'name', 'plot', 'readability', 'similar', 'tokens', 'vocab']

但從這些成員名稱無法得知那些是屬性, 哪些是方法, 這可以先將 dir() 傳回值指派給一個變數, 然後用迴圈以 print() 來檢視這些成員的內容, 例如 : 

>>> members=dir(text1)   
>>> type(members)    
<class 'list'>   
>>> for mbr in members:         # 走訪 Text 物件成員
    obj=eval('text1.' + mbr)        # 用 eval() 求值取得 text1.成員之參考
    if not mbr.startswith('_'):     # 走訪所有不是 "_" 開頭的成員
        print(mbr, type(obj))   
        
collocation_list <class 'method'>
collocations <class 'method'>
common_contexts <class 'method'>
concordance <class 'method'>
concordance_list <class 'method'>
count <class 'method'>
dispersion_plot <class 'method'>
findall <class 'method'>
generate <class 'method'>
index <class 'method'>
name <class 'str'>
plot <class 'method'>
readability <class 'method'>
similar <class 'method'>
tokens <class 'list'>
vocab <class 'method'>

此處在迴圈中先使用求值函式 eval() 來取得 text1.成員名稱之參考, 此法可用來將以字串表示之變動物件名稱轉成物件之參考, 對於需要在迴圈中存取一群物件非常好用. 除了使用 eval() 外也可以用 vars()[text] 或 locals()[text],  參考 :

接著用字串的 startswith() 濾掉所有以 '_' 開頭的成員, 留下屬性與方法, 結果中 class 是 'method' 者為方法, 其他則為屬性. 由上面的結果可知, nltk.book.text1~9  物件成員中只有 name 與 tokens 這兩個屬性, 其餘皆為方法 (method). 可用 for 迴圈來顯示這九本書的書名 :

>>> for i in range(1, 10):      
    text='text' + str(i)              # 利用求值函式 eval() 取得 text1~9 之物件參考
    print(f'{text} name={eval(text).name}')         # 印出 text1~9 的 name 屬性值
    
text1 name=Moby Dick by Herman Melville 1851
text2 name=Sense and Sensibility by Jane Austen 1811
text3 name=The Book of Genesis
text4 name=Inaugural Address Corpus
text5 name=Chat Corpus
text6 name=Monty Python and the Holy Grail
text7 name=Wall Street Journal
text8 name=Personals Corpus
text9 name=The Man Who Was Thursday by G . K . Chesterton 1908


2. 計算 token 數目 :

所謂的 token 是自然語言處理中用來指涉一串字元的術語, 它可以是英文字, 標點符號, 數字, 或特殊符號等, 並非只是英文字 (word) 而已. 以下將檢視 NLTK 內 book 子套件底下的 text1~text9 共九本書語料中的 token 數目. 

將變數 text1~text9 傳入 len() 即可計算每本書的 token 數 :

>>> len(text1)  
260819
>>> len(text2)  
141576
>>> len(text3)   
44764
>>> len(text4)  
149797
>>> len(text5)   
45010
>>> len(text6)  
16967
>>> len(text7)  
100676
>>> len(text8)   
4867
>>> len(text9)   
69213

這樣一步步呼叫 len() 很冗長, 可以用 for 迴圈配合求值函式 eval() 來做 : 

>>> for i in range(1, 10):   
    text='text' + str(i)   
    length=len(eval(text))            # 用 eval() 將字串 text 轉成變數
    print(f'total tokens of {text} : {length}')    
    
total tokens of text1 : 260819
total tokens of text2 : 141576
total tokens of text3 : 44764
total tokens of text4 : 149797
total tokens of text5 : 45010
total tokens of text6 : 16967
total tokens of text7 : 100676
total tokens of text8 : 4867
total tokens of text9 : 69213

注意, 此處必須先用 eval() 將字串求值以取得變數 text1~text9 的參考位址, 若用 len(text) 表示是計算 'text1', 'text2', ... 之長度, 因此將總是得到 5 (因 'text1' 字元數為 5), 而不是變數 text1~text9 內容的長度. 

由上述可知, text1~9 物件的 token 屬性值為 list, 它被用來紀錄語料中的所有 token, 因為串列的元素很多, 直接 print() 其實看不到全貌, 但可用迴圈顯示前 10 個元素, 例如 :

>>> type(text1.tokens)             # tokens 屬性的資料型態為串列
<class 'list'>   
>>> for i in range(1, 9):           # 顯示 text1~9 物件的前 10 個 token
    text=eval('text' + str(i))       # 利用 eval() 字串求值取得變數
    print(text.tokens[:10])         # 顯示 tokens 屬性前 10 個元素
    
['[', 'Moby', 'Dick', 'by', 'Herman', 'Melville', '1851', ']', 'ETYMOLOGY', '.']
['[', 'Sense', 'and', 'Sensibility', 'by', 'Jane', 'Austen', '1811', ']', 'CHAPTER']
['In', 'the', 'beginning', 'God', 'created', 'the', 'heaven', 'and', 'the', 'earth']
['Fellow', '-', 'Citizens', 'of', 'the', 'Senate', 'and', 'of', 'the', 'House']
['now', 'im', 'left', 'with', 'this', 'gay', 'name', ':P', 'PART', 'hey']
['SCENE', '1', ':', '[', 'wind', ']', '[', 'clop', 'clop', 'clop']
['Pierre', 'Vinken', ',', '61', 'years', 'old', ',', 'will', 'join', 'the']
['25', 'SEXY', 'MALE', ',', 'seeks', 'attrac', 'older', 'single', 'lady', ',']

可見 token 不僅僅是英文字而已, 還包括了數字與標點符號等等. 用 len() 檢查 text1~9 的 token 屬性可得到與上面用 len(text1)~len(text9) 相同的 token 數目, 例如 : 

>>> len(text1.tokens)    
260819
>>> len(text2.tokens)    
141576
>>> len(text3.tokens)   
44764
>>> len(text4.tokens)  
149797
>>> len(text5.tokens)  
45010
>>> len(text6.tokens)   
16967
>>> len(text7.tokens)  
100676
>>> len(text8.tokens)  
4867
>>> len(text9.tokens)    
69213

也可用迴圈來檢視 :

>>> for i in range(1, 10):      
    text='text' + str(i)      
    length=len(eval(text).tokens)                      # 用 eval() 將字串 text 轉成變數
    print(f'total tokens of {text} : {length}')   
    
total tokens of text1 : 260819
total tokens of text2 : 141576
total tokens of text3 : 44764
total tokens of text4 : 149797
total tokens of text5 : 45010
total tokens of text6 : 16967
total tokens of text7 : 100676
total tokens of text8 : 4867
total tokens of text9 : 69213

可見結果與上面用 len(text1) ~ len(text9) 是一樣的. 


3. 用 set() 去除重複的 token :

len() 所統計的 token 數並未排除重複的 token, 若要去除重複的 token, 可利用 Python 的集合型態, 因為集合的元素不可重複, 都是 unique 的. 因此只要把 text1~text9 的語料傳入 set() 即可剔除重複的 token, 再將集合傳給 len() 即可得到語料中不重複計算的 token 數, 例如 :

>>> text1_set=set(text1)   
>>> type(text1_set)   
<class 'set'>  
>>> len(text1_set)     
19317  
>>> len(text1)   
260819

可見 text1 總 token 數有 26 萬多, 但其中有許多 token 重複出現, 經過 set() 轉成集合剔除重複的 token 後, 真正獨一無二的 token 數才 1 萬 9 千多而已. 我們可用 for 迴圈來計算 uniqe token 數 : 

>>> for i in range(1, 10):     
    text='text' + str(i)      
    tokens=len(eval(text))     
    unique_tokens=len(set(eval(text)))      # 先將語料 text?  傳給 set() 轉成集合
    print(f'{text} : total tokens={tokens} unique tokens={unique_tokens}')    
    
text1 : total tokens=260819 unique tokens=19317
text2 : total tokens=141576 unique tokens=6833
text3 : total tokens=44764 unique tokens=2789
text4 : total tokens=149797 unique tokens=9913
text5 : total tokens=45010 unique tokens=6066
text6 : total tokens=16967 unique tokens=2166
text7 : total tokens=100676 unique tokens=12408
text8 : total tokens=4867 unique tokens=1108
text9 : total tokens=69213 unique tokens=6807

可見不重複的 token 數目就少很多了. 

2021年8月6日 星期五

NLTK 學習筆記 (二) : 離線安裝 NLTK 語料庫

最近在研究 Python 自然語言處理套件 SpaCy, 由於所用的電腦無法連網須離線安裝, 高達 24 個以上的相依套件來回搬移檔案真的很麻煩 (因為不知道有哪些相依檔案, 只能看錯誤訊息一次補一個),  過程太囉嗦了, 所以一邊安裝一邊將所有相依檔案與安裝順序記錄在下面這篇文章中 :


為了方便做比較, 我同時也安裝了 NLTK, 此套件與 SpaCy 不同之處在於所使用的相依套件較少, 只有 regex, joblib, click, tqdm, colorama 這五個, 除了 regex 外, 其他四個也是 SpaCy 的相依套件, 所以離線安裝時先安裝完 Spacy 後只要再下載複製 regex 即可完成 NLTK 的安裝. 本系列前一篇文章參考 :


安裝 NLTK 套件不難, 但要離線安裝 NLTK 的語料庫就比較麻煩了, 因為全部語料庫共 107 個, 總大小合計高達 3.18GB, 這些語料庫可從 nltk 官網逐一下載其 zip 檔 : 


但下載後須一個個解壓分門別類放到特定子目錄才能使用, 這更麻煩了. 最好的辦法是先在可連網電腦的 Python 環境下安裝 NLTK 套件, 再呼叫 nltk.download() 下載全部語料庫, 這些語料庫會放在例如 D:\nltk_data 的目錄下, 只要將這個目錄壓縮成 zip 檔 (約 1.8GB), 再複製到無法連網的電腦上, 解壓縮後於系統環境變數 path 中添加此 nltk_data 路徑即可.

我先在無法上網的電腦上離線安裝 NLTK, 匯入 nltk 後檢視 nltk.data.path 屬性, 可見 NLTK 會先掃描電腦有哪些 drive, 預先設定了可能的語料庫路徑 : 




然後去連網電腦上將 NLTK 語料庫的安裝目錄 D:\nltk_data 整個 (約 3.18GB) 壓縮成 nltk_data.zip 檔 (約 1.8GB), 然後用隨身碟複製到無法連網的電腦解壓縮在 D:\nltk_data (也可以是 C 或 E 碟都沒關係) : 




然後到 "控制台/系統/進階設定" 開啟環境變數頁面, 編輯系統變數 path, 在其最後面添加 "D:\nltk_data\" 這個目錄 :





然後回到 Python 環境, 輸入 from nltk.book import * 指令, 果然順利列出語料庫中的書目 : 




這樣就順利將 NLTK 語料庫順利移植到無法連網的電腦啦! 即使是可以連網的電腦, 如果用 nltk.download() 線上下載安裝資料庫也很花時間 (要幾小時), 所以線上安裝過一次後壓縮語料庫再複製到別台電腦的方式速度最快. 

參考 : 


2019年3月8日 星期五

NLTK 學習筆記 (一) : 安裝 NLTK 套件與語料庫

NLTK (Natural Language ToolKit) 是賓州大學資工系的 Steven Bird 與 Edward Loper 用 Python 所開發的自然語言處理工具套件軟體, 搭配所提供的豐富語料庫與文本資料集, 廣泛地被用在自然語言處理的研究與教學上. 作者同時也寫了一本操作說明書 (cookbook) 來作為輔助教材 (實體書由 Oreily 出版, 2009) :

http://www.nltk.org/book_1ed/

下面三篇 NLTK 文章整理得非常清楚 :

NLTK 初學指南(一):簡單易上手的自然語言工具箱-探索篇
NLTK 初學指南(二):由外而內,從語料庫到字詞拆解 — 上手篇
NLTK 初學指南(三):基於 WordNet 的語義關係表示法 — 上下位詞結構篇

我在十年前開始學習 Python 時便下載測試過 NLTK, 因為碩士論文原本想寫計算語言學領域的語料庫部分, 但最後卻挑了實驗語音學來做而與語料庫失之交臂, 畢業後仍然對計算語言學念念不忘.

以下按照其中第一篇文章安裝 NLTK 並小小測試一番以驗證安裝是否成功, 安裝 NLTK 用 pip 指令即可 :

D:\Python>pip3 install -U nltk 
Collecting nltk
  Downloading https://files.pythonhosted.org/packages/6f/ed/9c755d357d33bc1931e157f537721efb5b88d2c5
83fe593cc09603076cc3/nltk-3.4.zip (1.4MB)
Requirement not upgraded as not directly required: six in c:\python36\lib\site-packages (from nltk)
(1.11.0)
Collecting singledispatch (from nltk)
  Downloading https://files.pythonhosted.org/packages/c5/10/369f50bcd4621b263927b0a1519987a04383d4a9
8fb10438042ad410cf88/singledispatch-3.4.0.3-py2.py3-none-any.whl
Building wheels for collected packages: nltk
  Running setup.py bdist_wheel for nltk ... done
  Stored in directory: C:\Users\cht\AppData\Local\pip\Cache\wheels\4b\c8\24\b2343664bcceb7147efeb21c
0b23703a05b23fcfeaceaa2a1e
Successfully built nltk
Installing collected packages: singledispatch, nltk
Successfully installed nltk-3.4 singledispatch-3.4.0.3
You are using pip version 10.0.1, however version 19.0.3 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.

程式不大 (但語料庫很大), 一下子就安裝完成了. 安裝完後第一件事便是用 nltk.download() 下載語料庫 :

>>> import nltk   
>>> nltk.download()   
showing info https://raw.githubusercontent.com/nltk/nltk_data/gh-pages/index.xml   

新版 NLTK 會跳出 index.xml 呈現的視窗, 案需求依序點選要下載的語料庫後按左下角的 Download 鈕下載 : 





完成下載的項目在 Status 欄會顯示 Installed. 此次我是點選 all 以外的全部都下載, 但完成後 all 的狀態還是 partial, 難道想下載全部的話, 一開始就只要點 all 那一項嗎? 在別台電腦下載時再確認看看. 

下載的語料庫儲存在 C:\Users\user\AppData\Roaming\nltk_data 底下, AppData 是系統隱藏資料夾, 必須在 "組合管理/資料夾與搜尋選項/檢視" 中開啟顯示隱藏檔選項才找得到 :




語料庫資料量高達 3.18GB ! 下載完後點選 "File/Exit" 跳出下載視窗, 回到 Python Shell 視窗會看到 nltk.download() 回傳 True, 表示下載成功. 接著匯入 nltk.book 這個語料庫 :

>>> import nltk
>>> nltk.download() 
showing info https://raw.githubusercontent.com/nltk/nltk_data/gh-pages/index.xml
True
>>> from nltk.book import * 
*** Introductory Examples for the NLTK Book ***
Loading text1, ..., text9 and sent1, ..., sent9
Type the name of the text or sentence to view it.
Type: 'texts()' or 'sents()' to list the materials.
text1: Moby Dick by Herman Melville 1851
text2: Sense and Sensibility by Jane Austen 1811
text3: The Book of Genesis
text4: Inaugural Address Corpus
text5: Chat Corpus
text6: Monty Python and the Holy Grail
text7: Wall Street Journal
text8: Personals Corpus
text9: The Man Who Was Thursday by G . K . Chesterton 1908

可見此語料庫有 9 本書, 由於時間有限, 以下只測試其中的 concordance() :

>>> text3.concordance("lived")

結果如下 :




結果會以所搜尋的字為中心排列.

測試 nltk.corpus.brown :

>>> from nltk.corpus import brown 
>>> brown.words() 
['The', 'Fulton', 'County', 'Grand', 'Jury', 'said', ...]

先就此打住, 以後有時間再繼續學習 NLTK 的用法.

參考 :

https://www.nltk.org/api/nltk.corpus.html
https://www.lfd.uci.edu/~gohlke/pythonlibs/
Python如何运行pip和如何安装whl文件(以NLTK为例)
http://www.pitt.edu/~naraehan/presentation/cmu_dh_workshop_2017.html
Where can I find a 64-bit version of NLTK to use with 64-bit Python 3.4.2? Should I install 32-bit Python?


2019-06-27 :

沒錯, 下載 NLTK 資料庫時直接點 ALL 下載就不會出現 Partial 了, 今天在 Python 3.7 版重新下載結果是這樣 :



參考 :