Python 的物件參考機制影響變數指定和引數傳遞,理解此機制有助於避免程式錯誤。序列物件如字串、列表和元組,支援索引、切片等操作,是處理文字資料的基礎。檔案輸入輸出操作允許程式與外部檔案互動,實作資料持久化。函式的定義和使用,搭配引數傳遞、變數作用域和檔案字串,提升程式碼的模組化和可讀性。模組化程式設計則能有效組織程式碼結構,避免命名衝突。動態規劃演算法在自然語言處理中應用廣泛,可提升演算法效率。NLTK 的叢集套件提供 K-means 等演算法,方便進行文字叢集分析。最後,文章也介紹了其他 Python 函式庫,例如 requests 函式庫,可應用於網路爬蟲等任務。

Python 程式設計與自然語言處理基礎

物件參考與引數傳遞

Python 的變數指定和引數傳遞是透過物件參考來實作的。例如,當我們有一個列表 a,並將其指定給 b 時,ab 將參考同一個列表物件。因此,對 a 的任何修改都會影響到 b,反之亦然。

>>> a = [1, 2, 3]
>>> b = a
>>> a.append(4)
>>> print(b)
[1, 2, 3, 4]

內容解密:

在這個例子中,ab 都是對同一個列表物件的參考。因此,當我們修改 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。然後,我們列印了回應的狀態碼。

章節練習

  1. 使用 Python 的 help 功能來瞭解更多關於序列物件的資訊。
  2. 識別三個可以同時對元組和列表進行的操作。三個列表操作無法對元組進行。找出一個使用列表而不是元組會導致 Python 錯誤的情況。
  3. 瞭解如何建立一個只包含一個元素的元組。
  4. 將列表 ['is', 'NLP', 'fun', '?'] 轉換為 ['NLP', 'is', 'fun', '!'],先使用指定陳述式,然後使用元組指定。
  5. 閱讀 cmp 函式的說明,瞭解它與比較運算元的不同之處。
  6. 檢查用於建立 n-grams 的滑動視窗方法對於極限情況(n=1 和 n=len(sent))的行為是否正確。
  7. 在布林上下文中實驗不同的非布林表示式,看看它們是否評估為 True 或 False。
  8. 使用不等式運算元比較字串,並瞭解字典序排序的原理。
  9. 編寫程式碼來移除字串開頭和結尾的空白,並將單詞之間的空白標準化為單一空格字元。
  10. 編寫程式按長度對單詞進行排序。定義一個輔助函式 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]}")

內容解密:

  1. count_vowels 函式:計算給定詞彙中的母音數量。

    • 使用生成器運算式遍歷詞彙中的每個字元。
    • 將字元轉換為小寫以確保正確識別大寫母音。
    • 統計在母音集合中的字元數量。
  2. process_words 函式:處理詞彙列表並將結果儲存到二維陣列。

    • 首先計算詞彙列表中的最大長度和最大母音數量,以確定二維陣列的大小。
    • 初始化二維陣列 word_vowels,其大小根據最大長度和最大母音數量決定。
    • 遍歷詞彙列表,計算每個詞彙的長度和母音數量,並將其加入到對應的二維陣列位置。
  3. 結果列印:遍歷二維陣列並列印包含詞彙的專案。

技術分析

  • 使用二維陣列儲存不同長度和母音數量的詞彙,有助於快速查詢特定條件的詞彙。
  • 透過預先計算最大長度和最大母音數量,最佳化了記憶體使用。

實作 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)

內容解密:

  1. 文字分割:將輸入文字分割成詞彙列表。
  2. 計算閾值索引:確定文字的最後 10% 起始位置。
  3. 首次遍歷:將閾值索引之前的詞彙加入到已見集合中。
  4. 二次遍歷:遍歷閾值索引之後的詞彙,如果詞彙未在已見集合中,則列印並加入集合。

技術分析

  • 使用集合儲存已見詞彙,提高了查詢效率。
  • 僅遍歷文字兩次,保證了時間複雜度的合理性。

統計詞彙頻率

題目要求

撰寫程式,將句子分割成詞彙並統計詞彙頻率,以字母順序列印每個詞彙及其頻率。

實作程式碼

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)

內容解密:

  1. 文字分割:將輸入句子分割成詞彙列表。
  2. 統計頻率:使用 Counter 類別統計詞彙頻率。
  3. 排序與列印:對詞彙進行排序並列印其頻率。

技術分析

  • 使用 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"))

內容解密:

  1. gematria 函式:計算詞彙的 Gematria 值。

    • 使用字典 letter_vals 查詢字母對應的數值。
  2. count_gematria_666 函式:統計語料函式庫中 Gematria 值為 666 的詞彙數量。

    • 遍歷語料函式庫中的所有詞彙並統計符合條件的數量。
  3. decode 函式:隨機替換詞彙以模擬發現隱藏意義。

    • 簡單地將部分詞彙以括號標記,模擬替換效果。

技術分析

  • 使用預定義的字母數值對映表進行 Gematria 計算。
  • 對語料函式庫進行遍歷統計,保證了結果的準確性。