Python 如何數一篇文章中最常出現的英文詞語
日常中,我們可能需要統計一篇文章最常出現的英文詞語,這時可以使用內置的 Counter 工具。
Counter 的用法如下:
from collections import Counter most_words = Counter(words).most_common(20)
以下以愛麗斯夢遊仙境為例子。我們從 Gutenberg 網站取得愛麗斯的第一段文字,放到一個純文字檔案中,命名為 alice-chapter-1.txt,放到我們的項目資料夾中。
接著在 Python 編程環境中,我們在同一項目資料夾中建立一個 Jupyter Notebook 互動編程環境。
載入文字檔案
with open("alice-chapter-1.txt") as file_obj: chapter_1 = file_obj.read()
有目標文字,數一數一段文字中出現了多少次此文字
chapter_1.count("Alice") # result: 28
可見,第一章中出現 Alice 字詞共 28 次。
使用 split 把文字拆成列表
有些時候,上述方法不夠用。我們會將字串分柝成列表。例如當我們需要使用 Counter 來數一數文字中出現最多的是哪幾個字時,就需要列表。又或者進一步分析文字,例如進行 NLP 語言分析及預計下一個文字時,也需要先將字串分柝成列表再進行計算。
將文字分柝成列表,我們可以使用 split。
我們若直接將 chapter_1 按空白來分柝,得出的結果不如 28。
words = chapter_1.split() words.count("Alice") # result: 20
注:split 可以按我們提供的文字進行分割。例如 "2022-01-02".split("-")
可以得出 ['2022', '01', '02']
等。而沒有提供參數時,則是用空白符號(包括跳行)作為分割字符。
為何列表數會數少了?因為我們把文字用空格分柝成列表時,會包括了標點符號等,所以 "Alice" 不同於 "Alice." 亦不同於 "Alice's",但字串不會這樣考慮,所以文字若不經過預處理,使用空格分柝的成果未必如意。
預處理 chapter_1 文字
一般的文字預處理分為以下步驟。
- 把文字轉為細楷
- 移除 's 的所有格
- 移除標點符號
轉細楷,可以使用 lower
函數,移除特定文字,可以使用 replace
函數。標點符號,通用的可以在 string.punctuation
中找到,當中包括以下標點符號:
!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~
英文文本亦會常出現文學引號而非上述程序用的引號,亦會有破折號出現,所以我一般會加上以下六個符號,分別是雙引號、單引號、短破折號(En Dash)及長破折號(Em Dash): “”‘’–—
如是者,以下代碼將 chapter_1 按上述步驟處理,處理後再 split
分柝,可以數到 28 個 "alice" 字詞。
# 把文字轉為細楷 chapter_1 = chapter_1.lower() # 移除 's 的所有格 chapter_1 = chapter_1.replace("'s'","").replace("’s","") # 移除標點符號 import string punctuations = string.punctuation + "“”‘’–—" for punctuation in punctuations: chapter_1 = chapter_1.replace(punctuation, "") # 分柝及數 "alice" words = chapter_1.split() words.count("alice") # result: 28
使用 Counter 數數列表中出現最多次數的字詞
這麼大費周章得出原本 chapter_1.count("Alice") 就可以得出的數字,用法當然不止於此。變成列表後,其中一個用法是使用 Counter 數數最常出現的字詞有哪些。
from collections import Counter most_words = Counter(words).most_common(20) print(most_words) # Result: [('the', 90), ('she', 79), ('to', 74), ('and', 65), ('it', 65), ('was', 53), ('a', 52), ('of', 41), ('i', 30), ('alice', 28), ('that', 27), ('her', 26), ('in', 26), ('down', 23), ('very', 23), ('for', 21), ('had', 20), ('but', 20), ('you', 18), ('not', 16)]
使用 Pandas 繪製棒型圖
就上述的結果,我們可以進一步使用 Pandas 及 Matplotlib 來繪圖。
首先,我們將上述的結果轉為 Pandas 的 DataFrame 類型。
於 Jupyter Notebook 中使用 DataFrame 有一個優勢,就是可以用較易閱讀的方式打印出數據內容。
import pandas as pd df = pd.DataFrame(most_words, columns=("Word","Count")) df # 在 Jupyter Notebook 中印出 DataFrame 數據
得出以下數據:
為準備繪圖,我們將當中的 Word 欄位設定為 Index。
df.set_index("Word", inplace=True) df
我們將會使用 barh
繪製橫向棒型圖。橫向棒型圖的一個特點是排序會上下倒轉,所以我們會先做一次排序。
df.sort_values(by="Count", ascending=True, inplace=True) df
為標記 "alice" 的所在位置,我們設定一個 Color 欄位,將除了 alice 以外的都設定為淺灰色。
DataFrame 的特性是隨時可以加欄位,而我們要設定特定一格,可以用 loc[index, column]
來按 index 取得那行記錄,再按 column 定位一格。
df["Color"] = "lightgrey" df.loc["alice", "Color"] = "blue" df
經過上述的資料準備,我們可以就 Count 欄位畫出棒型圖,並設定用 Color 欄位作為顏色。
df["Count"].plot(kind="barh", color=df["Color"], figsize=(8,8), title="Count of Alice in chapter 1")
後續:將文字預處理定義為函數重用
上述的文字預處理,於其他文字亦有使用需要。我們可以將當中的處理抽取定義成函數。
def process_text(content): import string content = content.lower() content = content.replace("'s'","").replace("’s","") punctuations = string.punctuation + "“”‘’–—" for punctuation in punctuations: content = content.replace(punctuation, "") return content process_text("Test. This is Thomas' toy. That’s Alice's toy.")
舉一反三:對網絡文字數出現最多的文字
套用上述的處理及 Counter 用法,我們可以應用於其他網頁上的文章,例如我以一篇澳門光影節新聞為例子:
https://www.gcs.gov.mo/detail/en/N21LdGKSOM?2
使用 Requests 及 BeautifulSoup 爬取網站內容成為內容結構樹,並按此網站的內容結構找出主文章文字,並按上述方式處理及數數。
import requests from bs4 import BeautifulSoup from collections import Counter url = "https://www.gcs.gov.mo/detail/en/N21LdGKSOM?2" # 下載網站內容 res = requests.get(url) # 把網站內容分析成內容結構樹 soup = BeautifulSoup(res.text) # 按網站的內容結構,主內容位置 class=mainBody 的 class=asideBody 元素內 element = soup.select_one(".mainBody .asideBody") # 將主內容元素的文章內容處理 article = element.text article = process_text(article) # 處理後數出最常出現的 40 個字詞 words = article.split() Counter(words).most_common(40)
中文如何?
以上做法,只適合用空格來隔開文字的外文,並不適合中文,因為中文不能通過簡單的 split
來達成。 中文需要其他庫來達成分詞,例如「結巴」分詞庫。
稍後我們在另一篇介紹中文數最常出現字詞的範例。
— 麥誠 Makzan,2022-01-08。
我是麥誠軒(Makzan),除了正職外,平常我要麼辦本地賽與辦世界賽,要麼任教編程與網站開發的在職培訓。現正轉型將面授培訓內容寫成電子書、網上教材等,至今撰寫了 7 本書, 2 個視頻教學課程。
如果我的文章有價值,請左下角 👍🏻按讚支持,或訂閱贊助我持續創作及分享。