# 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 ``` ---