---
# System prepended metadata

title: Stanza實作課程教學

---

# Stanza實作課程教學

{%preview https://stanfordnlp.github.io/stanza/tutorials.html %}

---

## 課程概述
**課程名稱**: Stanza - Python自然語言處理實作課程  
**適用對象**: 對NLP有基礎了解的研究生和開發者  
**先備知識**: Python基礎程式設計、基本NLP概念  

----

## 課程目標
1. 理解Stanza的架構和核心概念
2. 熟練使用Stanza進行各種NLP任務
3. 實作完整的文本分析專案
4. 針對中文文本進行專業的語言分析

---

## 第一部分：Stanza簡介

### 1.1 什麼是Stanza？
- Stanford NLP Group開發的Python NLP工具包
- 支援70+種人類語言
- 完全神經網路架構的處理管道
- 支援從分詞、詞性標註到依存句法與實體識別等任務

---

### 1.2 Stanza的核心特色
- **多語言支援**: 統一的API處理多種語言
- **神經網路架構**: 基於PyTorch的深度學習模型
- **模組化設計**: 靈活組合不同的處理器
- **高準確度**: 在多個基準測試中表現優異

---

### 1.3 安裝與設置
```python
# 安裝Stanza
pip install stanza

# 下載語言模型
import stanza
stanza.download('zh-hant')  # 繁體中文
stanza.download('zh-hans')  # 簡體中文
stanza.download('en')       # 英文
```

---

### 1.4 處理管道 (Pipeline) 概念
- 什麼是NLP處理管道？
    - 自然語言處理 (NLP) 管道是一種系統化的文本處理方法，它將多個語言分析任務按照邏輯順序連接起來，前一個任務的輸出作為下一個任務的輸入，形成一個完整的處理流程。
![image](https://hackmd.io/_uploads/rkGttbSixx.png)

---

- 核心概念：
    1. 序列化與依賴性：管道以既定順序執行，如 tokenize → pos → lemma → depparse → ner，確保後續任務能利用前一步的結構訊息與標註結果。
    2. 模組化處理器：每個子任務是可插拔的處理器，可按需選擇與組合，達成「只開啟需要的任務以換取效能」的配置策略。
    
    4. 資料物件與標註：管道將原始文字轉為文件/句子/詞的資料物件，並在其上附加詞性、形態、依存關係與實體等標註，方便下游程式直接取用。

---

- Stanza管道的組成元件
    ![image](https://hackmd.io/_uploads/HJvT5WHjle.png)

---

- 主要處理器說明：
    1. tokenize (分詞處理器)
        - 功能: 將原始文本分割為句子和詞語
        - 依賴: 無 (管道的起點)
        - 輸出: sentences, tokens
        - 重要性: 所有後續處理的基礎

    2. pos (詞性標註)
        - 功能: 為每個詞語標註詞性 (名詞、動詞、形容詞等)
        - 依賴: tokenize, mwt
        - 輸出: upos (通用詞性), xpos (語言特定詞性)

----

3. lemma (詞形還原)
    - 功能: 找出詞語的原始形式或詞根
    - 依賴: tokenize, mwt, pos
    - 輸出: lemma (詞根形式)

4. depparse (依存句法分析)
    - 功能: 分析詞語間的語法依賴關係，構建句法樹
    - 依賴: tokenize, mwt, pos, lemma
    - 輸出: head (語法中心詞), deprel (依存關係)

----

5. ner (命名實體識別)
    - 功能: 識別文本中的命名實體 (人名、地名、組織名等)
    - 依賴: tokenize (可獨立運行)
    - 輸出: entities, ner_tags

---

- 處理器 (Processors) 的概念
![image](https://hackmd.io/_uploads/ryqD4-Sslg.png)

---

 - 可以自由組合需要的處理器
```python
nlp_basic = stanza.Pipeline('zh-hant', processors='tokenize,pos')
nlp_full = stanza.Pipeline('zh-hant', processors='tokenize,pos,lemma,depparse,ner')
nlp_custom = stanza.Pipeline('zh-hant', processors='tokenize,ner')  # 只要分詞和實體識別
```

---

## 第二部分：核心功能實作

---

### 2.1 文本分詞與句子分割 
**實作目標**: 理解中文分詞的重要性和實現方式

```python
import stanza

# 建立處理管道
nlp = stanza.Pipeline('zh-hant', processors='tokenize')
# 範例文本
text = "自然語言處理是人工智慧的重要分支，它研究如何讓電腦理解人類語言。"
# 處理文本
doc = nlp(text)

# 查看分詞結果
for sentence in doc.sentences:
    print("分詞結果:", [token.text for token in sentence.tokens])
```
```
分詞結果: ['自然', '語言', '處理', '是', '人工', '智慧', '的', '重要', '分支', '，', '它', '研究', '如何', '讓', '電腦', '理解', '人類', '語言', '。']
```

---

**重點**:
- 中文分詞的挑戰
    - 中文句子沒有像英文單詞之間的空格分隔，詞與詞的邊界全靠機器決定，容易發生分詞歧義（如「全台大停電」可分「全台／大／停電」或「全／台大／停電」）。

----

- 分詞挑戰包含：「分詞標準不一致」（如「還要」分作「還／要」或「還要」）、「同詞多義」以及「新詞無法辨識」等。

- 分詞演算法常用：詞典匹配（基於最大匹配與Trie樹）、統計/機器學習方法（HMM/Viterbi）、深度學習（BiLSTM+CRF序列標註），但皆有歧義、新詞、標準差異的困難。

---

- Token vs Word的區別

    - Token指的是模型初步切割的最小單位，可能是詞、字、甚至標點符號。例如在分詞時，「台積電2025年」可以被分成 token：「台積電」、「2025」、「年」。
    
    - Word則更貼近語言學上的「詞語」，是語句真正的語意單位。中文分詞有時 token 和 word 重疊，如「人工智慧」，Token 可能原先是每個字，而Word則是詞組。
    - 許多NLP工具會先分出token，再進行詞性標註、句法分析以產生詞（word）的描述。

---

- 句子邊界識別
    - 中文句子不像英文一樣靠「.」明確分句，常用標點包含「。」「！」「？」「；」「……」等，甚至逗號在語意上有多重分隔功能。
    
    - 標點符號意涵多元，模型會誤判語意停頓為新句（如台灣口語逗號分句情境）。
    - 長句複合結構、引用/省略標點時，模型很難正確斷句。

---

### 2.2 詞性標註 (Part-of-Speech Tagging)
**實作目標**: 識別每個詞的文法角色

```python
# 加入詞性標註
nlp = stanza.Pipeline('zh-hant', processors='tokenize,pos')

text = "小明在陽明交通大學學習電腦科學。"
doc = nlp(text)

print("詞性標註結果:")
for sentence in doc.sentences:
    for word in sentence.words:
        print(f"{word.text:8} -> {word.upos}")
```
```
詞性標註結果:
小明       -> PROPN
在        -> VERB
陽明       -> PROPN
交通       -> NOUN
大學       -> NOUN
學習       -> VERB
電腦       -> NOUN
科學       -> NOUN
。        -> PUNCT
```

---

**重點**:
- Universal POS標籤系統
    - Universal POS (Part-of-Speech) 標籤系統是由 Universal Dependencies 提議的一套語言無關、統一詞性標註集。
    
    - 其目的是為不同語言的NLP工具及語料庫提供一致的詞性標註，是國際主流語言學研究及自動化語言分析的標準。

----

- 常見 Universal POS 標籤有：
    - NOUN（名詞）
    - VERB（動詞）
    - ADJ（形容詞）
    - ADV（副詞）
    - PRON（代名詞）
    - PROPN（專有名詞）、ADP（介詞）
    - CONJ（連接詞）、DET（限定詞）
    - PUNCT（標點）、NUM（數詞）
    - PART（助詞）、INTJ（感嘆詞）
    - SYM（符號）、X（其他）。

---

### 中文詞性的特殊性:

- 中文獨特詞性包括：語法助詞（如「的」「了」「著」）、多詞合併（如「正在學習」），使詞性標註在中文應用上比英文更為複雜。

- 中文中的「名詞」、「動詞」通常可重疊使用或互相轉化，存在詞性模糊現象（如「喝水」：水可為名詞/動詞詞組）。

----

- 專有名詞（PROPN）、量詞（NUM/CL）、語氣詞（PART）、成語/固定搭配、複合詞的標註也有特殊標準；中文詞性粒度比英文更細，且口語/書面有差異。

- NLP標註時需考慮語境、詞組邊界及切詞結果對詞性標註的影響。

---

- 詞性標註的應用場景
    - 命名實體識別（NER）：精確詞性分辨可輔助標註人名地名等類型，提高準確率。
    
    - 關鍵詞提取與摘要：可以根據詞性提取主題詞（名詞、動詞等），產生精準摘要。
    - 情感分析：分辨形容詞/副詞等情感強詞，提升評論極性判斷。

---

### 2.3 命名實體識別 (Named Entity Recognition)
**實作目標**: 識別文本中的重要實體

```python
nlp = stanza.Pipeline('zh', processors='tokenize,ner')

text = "蘋果公司的執行長提姆·庫克將於明天訪問台北101大樓。"
doc = nlp(text)

print("命名實體識別結果:")
for sentence in doc.sentences:
    for ent in sentence.ents:
        print(f"實體: {ent.text:12} 類型: {ent.type}")
```
```
命名實體識別結果:
實體: 蘋果公司         類型: ORG
實體: 提姆           類型: PERSON
實體: 庫克將          類型: PERSON
實體: 於明天          類型: DATE
實體: 台北101大樓      類型: FAC
```

---

- 命名實體包含多種語意類型，常見分類如下：
    ```
    * 人名 (PERSON)：「王小明」、「蔡英文」
    * 地緣政治 (GPE)：「台北」、「美國」
    * 地名 (LOC)：、「喜馬拉雅山」、「日月潭」
    * 組織名 (ORG)：「台積電」、「蘋果公司」、「世界衛生組織」
    * 日期/時間 (DATE/TIME)：「2025年」、「上午九點」、「下週」
    * 貨幣、百分比 (MONEY/PERCENT)：「新台幣一萬元」、「25%」
    * 產品 (PRODUCT)：「iPhone 15」
    * 事件 (EVENT)：「奧運會」、「總統大選」
    * 設施 (FAC)：「台北101」
    * 語言 (LANG)：「中文」、「英語」
    * 基數（CARDINAL）：「一百」、「三十」
    * 序數（ORDINAL）：「第一」、「第十」
    * 數量＋單位（QUANTITY）：「三十公里」、「五公升」
    * 其他：所屬關係、法律、藝術品等
    ```
中文NER系統可辨識十幾種實體類別，依應用場景可擴充更多領域（如醫療、金融、法律專業術語等）。

---

### NER在資訊抽取中的應用

- 關鍵資訊自動抽取：如新聞中自動標記人物、事件，協助摘要與索引，快速掌握內容核心。

- 問答系統與聊天機器人：精準分類輸入中的實體，讓系統針對人物、地點、產品進行互動、回答或推薦。
- 文本分類/知識圖譜建構：從大量文件中將實體及其關係提取，用於建構知識網絡或知識資料庫。
- 情感分析/大數據分析：針對特定實體自動分析輿情、口碑、消費者回饋等。

---

- 中文NER的挑戰
    - 無空格切詞困難：中文句子缺乏明顯詞語界線，NER模型高度依賴分詞準確度。
    
    - 同形異義／合成詞現象：如「台灣高鐵」同時有地名／組織詞性、「小米」可指人名／品牌／產品，辨識困難。
    - 新專名／流行語／外來詞：新興品牌、地名、網路用語出現速度快，現有語料庫難及時涵蓋。

----

- 標準語料缺乏／語言知識Domain Gap：高品質中文NER語料少、各大領域有各自標註標準，或特殊專業術語。

- 語法結構複雜／長詞多詞成分重疊：中文多有省略、疊詞、複合詞等句法現象，讓NER模型設計更具挑戰。

---

### 2.4 依存句法分析 (Dependency Parsing)

https://stanza.stanford.edu/

**實作目標**: 分析句子的語法結構

```python
nlp = stanza.Pipeline('zh-hant', processors='tokenize,pos,lemma,depparse')

text = "學生們在圖書館裡認真地讀書。"
doc = nlp(text)

print("依存句法分析:")
for sentence in doc.sentences:
    for word in sentence.words:
        print(f"{word.text} -> {word.head} ({word.deprel})")
```
```
依存句法分析:
學生 -> 2 (compound)
們 -> 9 (nsubj)
在 -> 5 (case)
圖書 -> 5 (compound)
館 -> 9 (obl)
裡 -> 5 (case)
認真 -> 9 (advmod)
地 -> 7 (mark:adv)
讀書 -> 0 (root)
。 -> 9 (punct)
```

---

### 短語結構語法
- 短語結構語法（Phrase Structure Grammar）：以「成分關係」為基礎，將句子分成層層嵌套的短語單位（如名詞短語NP、動詞短語VP等）；樹狀結構由自上而下分析句子，是傳統語言學如 Chomsky 句法理論的主流。
    - 例：S → NP + VP；NP → DET + N
    - 樹上的每個節點都代表短語或其組成部分，句法成分強調「組合關係」。
    - “食物非常好吃。”
    - ![image](https://hackmd.io/_uploads/BJvadMSsxg.png)

---

### 依存語法
- 依存語法（Dependency Grammar）：強調詞彙之間的依賴關係，不關心短語層級，直接以「詞→詞」為基礎形成樹型結構；每個詞只和另一個詞（其語法中心詞head）有關聯，所有關係都由中心詞主導。
    - 例：「小明愛看書」：root(愛)，nsubj(愛, 小明)，obj(愛, 書)
    - 樹上的每個節點是單一詞彙，強調「依賴關係」。
    - 例：「食物非常好吃」：
    - ![image](https://hackmd.io/_uploads/BJoydfBiex.png)

----

- 依存關係的類型
    - 主語（nsubj）：主語與謂語，例如「我」→「看」。
    - 賓語（obj/dobj/pobj）：謂語的賓語，如「看」→「書」。
    - 修飾語（amod/advmod/nmod）：形容詞、副詞、名詞間修飾，如「非常」→「好吃」。
    - 時間修飾（nmod:tmod）：如「昨天」→「看書」。
    - 限定詞（det）：如「一本」→「書」。
    - 依存句法關係還包括：aux（助動詞）、case（介詞）、conj（並列）、mark（標記）、vocative（呼格）、cc（連詞）、xcomp（補語）、clf（量詞）等。

---

### 句法樹的視覺化

- 短語結構樹：由上而下分解成分，每個分支代表一個短語組成部分，終端為詞彙本身。常用於語言學、翻譯等領域。
    - ```
        S
        ├── NP
        │ ├── DET
        │ └── NN
        └── VP
        ├── VBD
        └── PP
        └── NP…
        ```

----

- 依存關係樹：每個詞為節點，箭頭代表語法依賴，標注依存類型（如主語、賓語），使語法結構一目了然，便利於資訊抽取和語意理解。
    - 例：「小明昨天在圖書館讀書。」

```
root(讀書)
├── nsubj(小明, 讀書)
├── nmod:tmod(昨天, 讀書)
├── nmod(圖書館, 讀書)
``` 
        
---

---

## 第三部分：進階應用與專案實作

---

### 3.1 批量文本處理
**實作目標**: 高效處理大量文檔

```python
# 準備多個文檔
documents = [
    "人工智慧將改變未來的工作方式。",
    "深度學習在影像識別方面取得重大突破。",
    "自然語言處理讓機器能理解人類語言。"
]

# 批量處理
in_docs = [stanza.Document([], text=d) for d in documents]
out_docs = nlp(in_docs)

# 分析結果
for i, doc in enumerate(out_docs):
    print(f"文檔 {i+1} 的實體:")
    for sent in doc.sentences:
        for ent in sent.ents:
            print(f"  {ent.text} ({ent.type})")
```

---

### 3.2 情感分析實作
**實作目標**: 分析文本的情感傾向

```python
# 英文情感分析
en_nlp = stanza.Pipeline('en', processors='tokenize,sentiment')

reviews = [
    "This product is amazing! I love it.",
    "The service was terrible and disappointing.",
    "It's okay, nothing special but not bad either."
]

sentiment_labels = {0: "負面", 1: "中性", 2: "正面"}

for review in reviews:
    doc = en_nlp(review)
    for sentence in doc.sentences:
        print(f"評論: {sentence.text}")
        print(f"情感: {sentiment_labels[sentence.sentiment]}\n")
```

```
評論: This product is amazing!
情感: 正面

評論: I love it.
情感: 正面

評論: The service was terrible and disappointing.
情感: 負面

評論: It's okay, nothing special but not bad either.
情感: 正面
```

---

### 3.3 完整專案：新聞文本分析系統
**實作目標**: 整合所有功能的實際應用

```python
def analyze_news_text(text, nlp_pipeline):
    """完整的新聞文本分析函數"""
    doc = nlp_pipeline(text)
    
    analysis_result = {
        'entities': [],
        'key_words': [],
        'sentence_count': len(doc.sentences),
        'word_count': sum(len(sent.words) for sent in doc.sentences)
    }
    
    for sentence in doc.sentences:
        # 收集命名實體
        for ent in sentence.ents:
            analysis_result['entities'].append({
                'text': ent.text,
                'type': ent.type
            })
        
        # 收集關鍵詞（名詞和動詞）
        for word in sentence.words:
            if word.upos in ['NOUN', 'VERB'] and len(word.text) > 1:
                analysis_result['key_words'].append(word.text)
    
    return analysis_result

# 使用範例
news_text = """
台積電今日宣布，將在美國亞利桑那州建設新的晶圓廠。
這項投資計畫總額高達120億美元，預計將創造1600個就業機會。
台積電董事長劉德音表示，此舉將強化公司在全球半導體產業的領導地位。
"""

nlp = stanza.Pipeline('zh-hans', processors='tokenize,pos,ner')
result = analyze_news_text(news_text, nlp)

print("新聞分析結果:")
print(f"句子數量: {result['sentence_count']}")
print(f"詞彙數量: {result['word_count']}")
print(f"命名實體: {[ent['text'] for ent in result['entities']]}")
print(f"關鍵詞: {list(set(result['key_words']))}")
```
```
新聞分析結果:
句子數量: 3
詞彙數量: 65
命名實體: ['台積電', '今日', '美國', '亞利桑那州', '120億美元', '1600個', '台積電', '劉', '德音']
關鍵詞: ['宣布', '建設', '強化', '今日', '表示', '領導', '公司', '晶圓', '地位', '全球', '董事', '投資']
```

---

## 附錄

### A. 常用處理器列表
- tokenize: 分詞和句子分割
- mwt: 多詞標記展開
- pos: 詞性標註
- lemma: 詞形還原
- depparse: 依存句法分析
- ner: 命名實體識別
- sentiment: 情感分析

---- 

### B. 語言代碼對照
- zh-hant: 繁體中文
- zh-hans: 簡體中文
- en: 英文
- ja: 日文
- ko: 韓文

----

### C. 實用程式碼片段
```python
# 快速設置
def quick_setup(lang='zh-hant'):
    return stanza.Pipeline(lang, processors='tokenize,pos,ner,depparse')

# 實體抽取函數
def extract_entities(text, nlp):
    doc = nlp(text)
    entities = []
    for sent in doc.sentences:
        for ent in sent.ents:
            entities.append((ent.text, ent.type))
    return entities

# 詞性分析函數  
def pos_analysis(text, nlp):
    doc = nlp(text)
    pos_counts = {}
    for sent in doc.sentences:
        for word in sent.words:
            pos_counts[word.upos] = pos_counts.get(word.upos, 0) + 1
    return pos_counts
```

---