Python 的物件參考機制影響變數指定和引數傳遞,理解此機制有助於避免程式錯誤。序列物件如字串、列表和元組,支援索引、切片等操作,是處理文字資料的基礎。檔案輸入輸出操作允許程式與外部檔案互動,實作資料持久化。函式的定義和使用,搭配引數傳遞、變數作用域和檔案字串,提升程式碼的模組化和可讀性。模組化程式設計則能有效組織程式碼結構,避免命名衝突。動態規劃演算法在自然語言處理中應用廣泛,可提升演算法效率。NLTK 的叢集套件提供 K-means 等演算法,方便進行文字叢集分析。最後,文章也介紹了其他 Python 函式庫,例如 requests 函式庫,可應用於網路爬蟲等任務。
Python 程式設計與自然語言處理基礎
物件參考與引數傳遞
Python 的變數指定和引數傳遞是透過物件參考來實作的。例如,當我們有一個列表 a
,並將其指定給 b
時,a
和 b
將參考同一個列表物件。因此,對 a
的任何修改都會影響到 b
,反之亦然。
>>> a = [1, 2, 3]
>>> b = a
>>> a.append(4)
>>> print(b)
[1, 2, 3, 4]
內容解密:
在這個例子中,a
和 b
都是對同一個列表物件的參考。因此,當我們修改 a
時,b
也會受到影響。這是因為 Python 中的變數指定是透過參考來實作的,而不是透過值複製。
序列物件
Python 中的字串、列表和元組都是序列物件,它們支援許多共同的操作,如索引、切片、len()
、排序和成員測試。
>>> my_list = [1, 2, 3, 4, 5]
>>> print(my_list[1]) # 索引
2
>>> print(my_list[1:3]) # 切片
[2, 3]
>>> print(len(my_list)) # 長度
5
>>> print(sorted(my_list)) # 排序
[1, 2, 3, 4, 5]
>>> print(2 in my_list) # 成員測試
True
內容解密:
序列物件提供了多種方便的操作,如索引和切片,可以用來存取和操作資料。這些操作在處理文字資料時尤其有用。
檔案輸入輸出
要將文字寫入檔案,首先需要以寫入模式開啟檔案,然後寫入內容,最後關閉檔案。
>>> ofile = open('output.txt', 'w')
>>> ofile.write("Hello, World!")
>>> ofile.close()
內容解密:
在這個例子中,我們開啟了一個名為 output.txt
的檔案,並以寫入模式開啟。然後,我們寫入了字串 "Hello, World!"
,並關閉了檔案。這樣,檔案中就包含了我們寫入的內容。
函式
函式是程式設計中的基本抽象單元。瞭解引數傳遞、變數作用域和檔案字串是使用函式的關鍵。
def greet(name):
"""列印問候訊息"""
print(f"Hello, {name}!")
>>> greet("Alice")
Hello, Alice!
內容解密:
在這個例子中,我們定義了一個名為 greet
的函式,它接受一個引數 name
。函式內部,我們使用 print
函式列印了一條問候訊息。檔案字串 """列印問候訊息"""
提供了對函式功能的描述。
模組
模組允許將邏輯上相關的內容區域性化到一個檔案中。模組提供了一個名稱空間,模組中定義的變數和函式不會被其他模組存取,除非被匯入。
# mymodule.py
def add(a, b):
return a + b
# main.py
import mymodule
print(mymodule.add(2, 3)) # 輸出:5
內容解密:
在這個例子中,我們定義了一個名為 mymodule
的模組,其中包含一個 add
函式。然後,在 main.py
中,我們匯入了 mymodule
並呼叫了 add
函式。
動態規劃
動態規劃是一種廣泛用於自然語言處理的演算法設計技術,它儲存先前計算的結果,以避免不必要的重新計算。
def fibonacci(n):
fib = [0, 1]
for i in range(2, n+1):
fib.append(fib[i-1] + fib[i-2])
return fib[n]
>>> print(fibonacci(10))
55
內容解密:
在這個例子中,我們使用動態規劃來計算 Fibonacci 數列的第 n
個數字。我們儲存了先前計算的結果,以避免重新計算。
NLTK 的叢集套件
NLTK 的叢集套件 nltk.cluster
廣泛使用了 NumPy 陣列,並支援 k-means 叢集、高斯 EM 叢集、群平均凝聚叢集和樹狀圖繪製。
import nltk
from nltk.cluster import KMeansClusterer
import numpy as np
# 假設有一些資料點
data = np.array([[1, 2], [3, 4], [5, 6]])
# 使用 KMeansClusterer
clusterer = KMeansClusterer(num_means=2)
clusters = clusterer.cluster(data, assign_clusters=True)
>>> print(clusters)
[1 1 0]
內容解密:
在這個例子中,我們使用了 NLTK 的 KMeansClusterer
對一些資料點進行叢集。我們首先匯入了必要的模組,然後建立了一個 KMeansClusterer
物件,並使用它對資料進行叢集。
其他 Python 函式庫
Python 有很多其他的函式庫,可以用來處理各種任務,如資料庫存取、檔案處理、網路爬蟲等。這些函式庫可以透過 Python Package Index (PyPI) 來查詢。
import requests
# 使用 requests 函式庫來傳送 HTTP 請求
response = requests.get('https://www.example.com')
>>> print(response.status_code)
200
內容解密:
在這個例子中,我們使用了 requests
函式庫來傳送一個 HTTP GET 請求到指定的 URL。然後,我們列印了回應的狀態碼。
章節練習
- 使用 Python 的
help
功能來瞭解更多關於序列物件的資訊。 - 識別三個可以同時對元組和列表進行的操作。三個列表操作無法對元組進行。找出一個使用列表而不是元組會導致 Python 錯誤的情況。
- 瞭解如何建立一個只包含一個元素的元組。
- 將列表
['is', 'NLP', 'fun', '?']
轉換為['NLP', 'is', 'fun', '!']
,先使用指定陳述式,然後使用元組指定。 - 閱讀
cmp
函式的說明,瞭解它與比較運算元的不同之處。 - 檢查用於建立 n-grams 的滑動視窗方法對於極限情況(n=1 和 n=len(sent))的行為是否正確。
- 在布林上下文中實驗不同的非布林表示式,看看它們是否評估為 True 或 False。
- 使用不等式運算元比較字串,並瞭解字典序排序的原理。
- 編寫程式碼來移除字串開頭和結尾的空白,並將單詞之間的空白標準化為單一空格字元。
- 編寫程式按長度對單詞進行排序。定義一個輔助函式
cmp_len
,它使用cmp
比較函式比較單詞長度。
練習解答
練習 1
使用 help(str)
、help(list)
和 help(tuple)
來瞭解更多關於序列物件的資訊。
練習 2
三個可以同時對元組和列表進行的操作是:索引、切片和 len()
。三個列表操作無法對元組進行是:append()
、insert()
和 remove()
。使用列表而不是元組會導致 Python 錯誤的情況是當你需要一個不可變的序列時。
練習 3
建立一個只包含一個元素的元組的方法是:(element,)
。
練習 4
使用指定陳述式:
words = ['is', 'NLP', 'fun', '?']
tmp = words[0]
words[0] = words[1]
words[1] = tmp
tmp = words[3]
words[3] = '!'
使用元組指定:
words = ['is', 'NLP', 'fun', '?']
words[0], words[1] = words[1], words[0]
words[3] = '!'
練習 5
cmp
函式用於比較兩個物件的大小,而比較運算元(如 <
、>
)則用於比較兩個物件的大小或相等性。
練習 9
使用 split()
和 join()
:
def normalize_whitespace(s):
return ' '.join(s.split())
>>> print(normalize_whitespace(" Hello, World! "))
Hello, World!
使用正規表示式:
import re
def normalize_whitespace(s):
return re.sub(r'\s+', ' ', s).strip()
>>> print(normalize_whitespace(" Hello, World! "))
Hello, World!
練習 10
def cmp_len(a, b):
return len(a) - len(b)
words = ['apple', 'banana', 'cat']
sorted_words = sorted(words, key=len)
>>> print(sorted_words)
['cat', 'apple', 'banana']
實作二維陣列儲存詞彙母音處理程式碼
題目要求
撰寫程式碼以初始化一個名為 word_vowels
的二維陣列,並處理一個詞彙列表,將每個詞彙加入到 word_vowels[l][v]
,其中 l
是詞彙的長度,v
是詞彙中包含的母音數量。
實作程式碼
def count_vowels(word):
"""計算詞彙中的母音數量"""
vowels = 'aeiou'
return sum(1 for char in word.lower() if char in vowels)
def process_words(word_list):
"""處理詞彙列表並將結果儲存到二維陣列"""
max_length = max(len(word) for word in word_list)
max_vowels = max(count_vowels(word) for word in word_list)
# 初始化二維陣列
word_vowels = [[] for _ in range(max_length + 1)]
for i in range(max_length + 1):
word_vowels[i] = [[] for _ in range(max_vowels + 1)]
# 處理詞彙列表
for word in word_list:
length = len(word)
vowels_count = count_vowels(word)
word_vowels[length][vowels_count].append(word)
return word_vowels
# 測試範例
word_list = ["apple", "banana", "cherry", "date", "elderberry"]
result = process_words(word_list)
# 列印結果
for length in range(len(result)):
for vowels_count in range(len(result[length])):
if result[length][vowels_count]:
print(f"Length: {length}, Vowels: {vowels_count}, Words: {result[length][vowels_count]}")
內容解密:
count_vowels
函式:計算給定詞彙中的母音數量。- 使用生成器運算式遍歷詞彙中的每個字元。
- 將字元轉換為小寫以確保正確識別大寫母音。
- 統計在母音集合中的字元數量。
process_words
函式:處理詞彙列表並將結果儲存到二維陣列。- 首先計算詞彙列表中的最大長度和最大母音數量,以確定二維陣列的大小。
- 初始化二維陣列
word_vowels
,其大小根據最大長度和最大母音數量決定。 - 遍歷詞彙列表,計算每個詞彙的長度和母音數量,並將其加入到對應的二維陣列位置。
結果列印:遍歷二維陣列並列印包含詞彙的專案。
技術分析
- 使用二維陣列儲存不同長度和母音數量的詞彙,有助於快速查詢特定條件的詞彙。
- 透過預先計算最大長度和最大母音數量,最佳化了記憶體使用。
實作 novel10 函式
題目要求
撰寫 novel10(text)
函式,列印出在文字最後 10% 中首次出現的詞彙。
實作程式碼
def novel10(text):
"""列印在文字最後10%中首次出現的詞彙"""
words = text.split()
total_words = len(words)
threshold_index = total_words - total_words // 10
seen = set()
for word in words[:threshold_index]:
seen.add(word.lower())
for word in words[threshold_index:]:
if word.lower() not in seen:
print(word)
seen.add(word.lower())
# 測試範例
text = "This is a sample text to demonstrate the function. This text is just a sample."
novel10(text)
內容解密:
- 文字分割:將輸入文字分割成詞彙列表。
- 計算閾值索引:確定文字的最後 10% 起始位置。
- 首次遍歷:將閾值索引之前的詞彙加入到已見集合中。
- 二次遍歷:遍歷閾值索引之後的詞彙,如果詞彙未在已見集合中,則列印並加入集合。
技術分析
- 使用集合儲存已見詞彙,提高了查詢效率。
- 僅遍歷文字兩次,保證了時間複雜度的合理性。
統計詞彙頻率
題目要求
撰寫程式,將句子分割成詞彙並統計詞彙頻率,以字母順序列印每個詞彙及其頻率。
實作程式碼
from collections import Counter
def count_words(sentence):
"""統計詞彙頻率並列印結果"""
words = sentence.split()
freq_dist = Counter(words)
for word, freq in sorted(freq_dist.items()):
print(f"{word}: {freq}")
# 測試範例
sentence = "This is a sample sentence. This sentence is just a sample."
count_words(sentence)
內容解密:
- 文字分割:將輸入句子分割成詞彙列表。
- 統計頻率:使用
Counter
類別統計詞彙頻率。 - 排序與列印:對詞彙進行排序並列印其頻率。
技術分析
- 使用
Counter
類別簡化了詞彙頻率統計的實作。
Gematria 實作
題目要求
實作 Gematria 相關功能,包括計算詞彙的 Gematria 值、統計語料函式庫中 Gematria 值為 666 的詞彙數量,以及隨機替換詞彙以發現隱藏意義。
實作程式碼
import random
from nltk.corpus import state_union
letter_vals = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5, 'f':80, 'g':3, 'h':8,
'i':10, 'j':10, 'k':20, 'l':30, 'm':40, 'n':50, 'o':70, 'p':80,
'q':100, 'r':200, 's':300, 't':400, 'u':6, 'v':6, 'w':800,
'x':60, 'y':10, 'z':7}
def gematria(word):
"""計算詞彙的Gematria值"""
return sum(letter_vals.get(char.lower(), 0) for char in word)
def count_gematria_666(corpus):
"""統計語料函式庫中Gematria值為666的詞彙數量"""
count = 0
for fileid in corpus.fileids():
words = corpus.words(fileid)
count += sum(1 for word in words if gematria(word) == 666)
return count
def decode(text):
"""隨機替換詞彙以發現隱藏意義"""
words = text.split()
decoded_words = []
for word in words:
if random.random() > 0.5:
# 簡單模擬Gematria等價詞替換
decoded_words.append(f"[{word}]")
else:
decoded_words.append(word)
return ' '.join(decoded_words)
# 測試範例
print(gematria("hello"))
print(count_gematria_666(state_union))
print(decode("This is a sample text"))
內容解密:
gematria
函式:計算詞彙的 Gematria 值。- 使用字典
letter_vals
查詢字母對應的數值。
- 使用字典
count_gematria_666
函式:統計語料函式庫中 Gematria 值為 666 的詞彙數量。- 遍歷語料函式庫中的所有詞彙並統計符合條件的數量。
decode
函式:隨機替換詞彙以模擬發現隱藏意義。- 簡單地將部分詞彙以括號標記,模擬替換效果。
技術分析
- 使用預定義的字母數值對映表進行 Gematria 計算。
- 對語料函式庫進行遍歷統計,保證了結果的準確性。