---
# System prepended metadata

title: 文字前處理（Text Preprocessing）-1
tags: [NLP]

---

## 介紹文字前處理（Text Preprocessing）
自然語言處理（NLP, Natural Language Processing）中的文字前處理（Text Preprocessing）是將原始文本轉換為結構化數據的關鍵步驟，這個過程能夠使電腦更好地理解和處理人類語言。

完整的文字前處理流程包含 Tokenization（分詞）、Stopwords（停用詞移除）、POS Tagging（詞性標註）、Named Entity Recognition（命名實體識別，NER）、Stemming（詞幹提取）或 Lemmatization（詞形還原）等技術，這些步驟彼此相輔相成，共同提升 NLP 任務的準確性和可解釋性。

![image](https://hackmd.io/_uploads/BkvO8WOqke.png)

## 重要專業術語解釋
1. Corpus：大量文本數據的集合，語料庫可以來自不同來源，例如新聞、書籍、對話記錄、社群媒體等，並且可能涵蓋單一語言或多種語言。
2. Document：語料庫中的一個文本單位，可以是文章、句子集合、段落，甚至是對話記錄，例如在社交媒體語料庫中，每則貼文或推文（tweet）可以視為一個 document。
4. Volcabulary：語料庫中出現的所有獨特詞彙（Unique Words），並過濾掉罕見詞、停用詞（Stopwords）等。
5. Words：語言的基本單位，在 NLP 中，每個單詞都是語意的載體。在不同語境下，單詞的含義可能會有所變化，這使得 NLP 模型需要考慮上下文來解析語義。

## Tokenization：將文本拆解為基本單位
Tokenization 是 NLP 任務中最基本的步驟，它的目的是將文本拆分為更小的單位，例如將一篇文章拆分成段落、句子或文字，甚至在英文中能拆分成子詞（Subword），例如 unhappiness 由常見的字母組合成的子詞 un、happi 和 ness，透過 Tokenization 可以讓電腦對文本進行標準化處理，進而應用於機器學習或深度學習模型。

Tokenization 有多種方式，其中最簡單的方法是基於空格和標點符號的拆分，然而，這種方法可能會導致複合詞（如 "New York"）被錯誤拆解成 New 以及 York，可能會影響語意理解。為了克服這個問題，通常會使用 Lexicon-based Tokenization 方法。

### Lexicon-based Tokenization
Lexicon-based Tokenization 是一種基於詞庫（Lexicon）的分詞方法，依賴預先建立的詞典來識別單詞或詞組，以確保正確的 Tokenization，這種方法特別適合處理複合詞（compound words）、專有名詞（proper nouns）或多詞組表達（multi-word expressions），如 "New York"、"ice cream"、"machine learning" 等，例如 NLTK 和 spaCy 等 NLP 庫的 Tokenization 方法內建詞庫，能夠處理複合詞與專有名詞。

```PY=
from nltk.tokenize import word_tokenize

text = "I live in New York City."
tokens = word_tokenize(text)
print(tokens)  
# 輸出: ['I', 'live', 'in', 'New', 'York', 'City', '.']
```
NLTK 會自動識別常見詞組，但仍然可能拆開複合詞。
```PY=
import spacy

nlp = spacy.load("en_core_web_sm")
text = "I live in New York City."
doc = nlp(text)

tokens = [token.text for token in doc]
print(tokens)
# 輸出: ['I', 'live', 'in', 'New York', 'City', '.']
```
spaCy 的 Tokenizer 透過內建的詞庫識別複合詞，確保 "New York" 被視為一個整體。


### Byte Pair Encoding（BPE）
Byte Pair Encoding（BPE）是一種基於統計的子詞（Subword）Tokenization 技術，最初用於數據壓縮，後來被應用於自然語言處理（NLP）領域，例如 GPT。BPE 透過合併最常見的字母或子詞對（byte pairs）來逐步建立詞彙表，使得模型能夠更有效地處理未知詞（OOV, Out-of-Vocabulary），並減少詞彙表大小。

```PY=
# 將文本中的單詞拆分為單個字符序列，並在每個字符之間加上空格
"happiness" → ["h", "a", "p", "p", "i", "n", "e", "s", "s"]
# 合併最常見的字母對，並將其作為新的子詞單位
["h", "a", "pp", "i", "n", "e", "ss"]
["h", "a", "pp", "i", "n", "ess"]
# 重複步驟，直到達到預設的子詞數量
["h", "appi", "n", "ess"]
```
## Stopwords：移除停用詞，提升語意資訊密度
在自然語言中，一些詞彙頻繁出現，但對於語意分析幫助不大，例如 "the"、"is"、"in"、"and" 等，這些詞被稱為 stopwords，移除這些詞可以減少處理文本的冗餘資訊，提高計算效率，並讓語意分析更聚焦於關鍵詞。

然而，在某些應用中，停用詞仍可能具有重要意義，例如在情感分析任務中，"not" 可能會影響句子的情緒傾向，因此在實際應用時，應根據具體任務來決定是否移除特定的停用詞。

## POS Tagging：詞性標註，理解語法結構
POS Tagging（詞性標註）是為文本中的每個單詞指定其詞性，如名詞（Noun）、動詞（Verb）、形容詞（Adjective）等，這對於語言理解至關重要，因為同一個詞可能具有不同的詞性，影響其語意。例如，"run" 可以是動詞（"I run every morning."），也可以是名詞（"He went for a run."）。

```PY=
import nltk
from nltk import pos_tag
from nltk.tokenize import word_tokenize

nltk.download("averaged_perceptron_tagger")

text = "The quick brown fox jumps over the lazy dog."
tokens = word_tokenize(text)
pos_tags = pos_tag(tokens)

print(pos_tags)

# [('The', 'DT'), ('quick', 'JJ'), ('brown', 'JJ'), ('fox', 'NN'), ('jumps', 'VBZ'), ('over', 'IN'), ('the', 'DT'), ('lazy', 'JJ'), ('dog', 'NN')]
```

## Named Entity Recognition（NER）：識別專有名詞
Named Entity Recognition（NER, 命名實體識別）是 NLP 中的一項關鍵技術，用於識別文本中的特定名稱，如人名（Person）、地名（Location）、組織（Organization）、時間（Date/Time）等。NER 在資訊檢索、問答系統、金融分析等領域有著廣泛的應用。

例如，在句子 "Elon Musk is the CEO of Tesla." 中，NER 系統可以識別：
* Elon Musk → PERSON（人名）
* Tesla → ORG（組織名稱）

透過 NER，可以更有效地提取關鍵資訊，使文本分析更加智能化。

## Stemming：將單詞還原為詞幹
Stemming 是將單詞還原為其詞幹（stem），通常是透過去除詞尾變化來達成，這種方法的核心目標是減少單詞的變化形式，使得具有相同語意的詞彙能夠被視為相同的字詞，例如，"running" 會被轉換為 "run"，"flies" 可能會被簡化為 "fli"。

在 NLP 中，最常用的 Stemming 方法包括 Porter Stemmer 和 Lancaster Stemmer。

### Porter Stemmer
它基於一組有規則的詞尾刪減規則（suffix-stripping rules），透過多個步驟來去除詞尾，使詞幹保持較接近原始單詞的形式，這種方法的優勢在於詞幹的可讀性較高，適合一般 NLP 任務，例如文本分類、資訊檢索等。然而，Porter Stemmer 仍然可能導致語意錯誤，例如將 "argue" 轉換為 "argu"，或將 "happiness" 轉換為 "happi"，這可能影響模型對語義的理解。
```PY=
from nltk.stem import PorterStemmer

stemmer = PorterStemmer()
print(stemmer.stem("running"))   # 輸出: run
print(stemmer.stem("happiness")) # 輸出: happi
print(stemmer.stem("flies"))     # 輸出: fli
```
### Lancaster Stemmer
它與 Porter Stemmer 不同，Lancaster Stemmer 在處理單詞時刪減的程度更強，因此運行速度更快，適合需要高效處理大規模文本的場景。然而，由於 Lancaster Stemmer 過於激進，可能會導致詞幹過短，使其變得難以識別。例如，"happiness" 可能會被還原為 "happy"，而 "argue" 則可能被過度簡化為 "arg"。這種簡化雖然對於某些資訊檢索系統可能有幫助，但在語意分析等需要更精確語義理解的任務中，可能會產生問題。

:::info
當選擇 Stemming 方法時，應根據應用場景來決定。如果需要更精確的詞形處理，或者需要保持詞彙的語意完整性，則可以考慮使用詞形還原（Lemmatization）來替代 Stemming，以獲得更準確的詞彙標準化效果。
:::

## Lemmatization：詞形還原，取得詞彙原型
Lemmatization 和 Stemming 類似，都是為了標準化單詞，但 Lemmatization 的處理方式更為精確，不同於 Stemming 只是去除詞尾，Lemmatization 會將單詞還原為字典中的詞形（lemma），並且能夠考慮單詞的詞性。例如，"running" 會被正確還原為 "run"，"flies" 會被還原為 "fly"，"better" 則會轉換為 "good"。

Lemmatization 的準確性高於 Stemming，但需要提供詞性（POS, Part-of-Speech）資訊來確保正確的還原，例如，"saw" 可以是動詞 "see" 的過去式，也可以是名詞 "鋸子"。透過詞性標註（POS tagging），系統可以準確判斷該詞應該還原為 "see" 還是保持原型 "saw"。

## WordNetLemmatizer
WordNetLemmatizer 是最常見的 Lemmatization 方法之一，它基於 WordNet 詞庫來查找單詞的詞形。WordNet 是一個大型的詞彙資料庫，包含英語單詞之間的語義關係，例如同義詞、反義詞和詞形變化等。

WordNetLemmatizer 透過匹配單詞的詞性，確保 Lemmatization 的結果更自然、更符合語法。例如，如果不指定詞性，"better" 可能無法被正確還原，但若提供詞性標註，它將被還原為 "good"。

```py=
from nltk.stem import WordNetLemmatizer
from nltk.corpus import wordnet

lemmatizer = WordNetLemmatizer()

# 單純進行詞形還原
print(lemmatizer.lemmatize("running"))  # 預設為名詞，輸出: running
print(lemmatizer.lemmatize("running", pos="v"))  # 指定為動詞，輸出: run

# 處理形容詞
print(lemmatizer.lemmatize("better", pos=wordnet.ADJ))  # 輸出: good
print(lemmatizer.lemmatize("flies", pos="n"))  # 指定為名詞，輸出: fly
print(lemmatizer.lemmatize("flies", pos="v"))  # 指定為動詞，輸出: fly
```

---
:::info
以上就是這篇文章「文字前處理（Text Preprocessing）」的所有內容，第一次看的人會花比較多時間消化吸收，這是很正常的事情，若有任何問題，歡迎在下方與我聯繫、討論，接下來也會繼續分享相關文章，敬請期待。