iT邦幫忙

2025 iThome 鐵人賽

DAY 2
0
AI & Data

從RAG到EmoRAG:讓AI真正聽懂你的心聲系列 第 2

第2天:文字預處理與基礎情緒辨識

  • 分享至 

  • xImage
  •  

文本預處理是指對原始文本資料進行清理和轉換,使其更適合進一步的分析與建模。它主要包括去除雜訊、標準化格式、分詞、詞性標註、去除停用詞、詞幹提取與詞形還原等步驟,目的是提高文字資料的質量與模型的準確性。

分詞

分詞是文本預處理中將連續的語句切分成詞語或詞組的過程,對於後續的語意分析、詞頻統計及模型訓練等任務至關重要。不同語言有不同的分詞方式和工具。

針對英文語句,常用工具如Transformers的Tokenizer和nltk的word_tokenize,這些工具能將句子按自然語言特性切分成單詞及標點符號。

text="The weather is very hot today, so I bought an ice cream from a convenience store."
nltk.word_tokenize(text)
# output=['The', 'weather', 'is', 'very', 'hot', 'today',',', 'so', 'I', 'bought', 'an', 'ice', 'cream', 'from', 'a', 'convenience', 'store','.']

而中文語句沒有明顯的詞邊界,需用像jieba這類分詞庫來切分詞語。jieba還支持自定義詞典以提高特定領域分詞的準確性。

strs = "今天天氣晴時多雲偶陣雨,我想從台南公園回到台南公園圖書館避雨,雨停後,搭露天觀光巴士去火車站"
# Jieba 自定義詞典
jieba.load_userdict('myText.txt')

seg_list = jieba.lcut(strs)#lcut():斷詞後直接放到list
print(seg_list)
# output=['今天', '天氣', '晴時多雲偶陣雨', ',', '我', '想', '從', '台南公園', '回到', '台南', '公園圖書館', '避雨', ',', '雨停', '後', ',', '搭', '露天觀光巴士', '去', '火車站']

停用詞

停用詞是指在文本中出現頻率高但對語義貢獻較低的詞語,例如英文中的「this」、「that」、「a」、「an」、「the」等。移除停用詞可以減少噪音,提升後續文本分析和機器學習模型的效能。

以下是利用Python的nltk庫進行停用詞移除的範例程式碼:

import nltk
nltk.download('stopwords')
nltk.download('punkt_tab')
# 讀取停用詞
stop_word = ["this", "that", "a", "an", "the"]
text="Today is a great day. It is even better than yesterday." + \
     " And yesterday was the best day ever."

# 移除停用詞(Removing Stopwords)
def remove_stopwords(text, is_lower_case=False):
    if is_lower_case:
        text = text.lower()
    tokens = nltk.word_tokenize(text)
    tokens = [token.strip() for token in tokens]
    filtered_tokens = [token for token in tokens if token not in stop_word]
    filtered_text = ' '.join(filtered_tokens)
    return filtered_text, filtered_tokens

filtered_text, filtered_tokens = remove_stopwords(text)
filtered_text
# output='Today is great day . It is even better than yesterday . And yesterday was best day ever .'

詞形還原(Lemmatization)/詞幹提取(Stemming):正規化

詞形還原(Lemmatization)與詞幹提取(Stemming)都是文本預處理中常用的正規化技術,目的是將單詞還原到其詞根或基本形式,以降低詞彙的多樣性,方便後續分析。

詞形還原指的是利用詞性和詞典資訊,將詞彙還原到字典中的基本形式(詞元),例如將"is"、"was"、"were"還原成"be"。詞形還原的精確度高,但因需要查詢詞典,處理速度較慢。

詞幹提取則是用簡單的規則去除詞彙的詞尾變化,如動詞的時態或名詞的複數,快速但常忽略語意或導致詞形不完整,因此精確度較低。

以下是使用Python nltk庫進行詞形還原的範例:

text="The weather is very hot today, so I bought an ice cream from a convenience store."
lem = nltk.WordNetLemmatizer()
' '.join([lem.lemmatize(word) for word in text.split()])
# output:'The weather is very hot today, so I buy an ice cream from a convenience store.'

此範例中,"bought"被還原為基本形"buy",展示了詞形還原能有效標準化詞彙,提升文本一致性與模型效果。

詞性標註

詞性標註是文本預處理中標記每個詞彙的語法類別(詞性)的步驟,例如名詞、動詞、形容詞等。詞性資訊有助於理解詞語在句子中的語法功能,進而提升語意分析、句法解析和資訊擷取的準確性。

以下為使用Python中文分詞與詞性標註庫jieba的範例:

import jieba.posseg as pseg

words = pseg.cut(strs)
for word, flag in words:
    print('%s, %s' % (word, flag))
    
# output=
今天, t
天氣, x
晴時多雲偶陣雨, x
,, x
我, r
想, v
從, p
台南公園, x
回到, v
台南, ns
公園圖書館, x
避雨, v
,, x
雨, n
停, v
後, nr
,, x
搭, v
露天觀光巴士, x
去, v
火車站, x

在此輸出中,詞性標記「x」代表自訂語料或未分類詞,「v」代表動詞,「n」代表名詞,「t」表示時間詞,「r」為代詞,「p」為介詞,「ns」為地名,「nr」為人名等。這些詞性標註有助於提升中文文本的語法與語意分析效果。

RAG與Transformers的關係

RAG是一種將外部檢索系統與Transformer生成模型結合的技術架構。Transformer負責生成文字,利用自注意力機制理解語言,而RAG則透過檢索器從知識庫中尋找相關段落,將這些段落作為生成的背景,讓模型能產生更具事實根據和上下文關聯性的回應。

檢索器(Retriever):基於embedding的相似度搜尋,從大量文本中快速找出與輸入問題相關的文件或段落。

生成器(Generator):通常是Transformer架構,如BART或T5,根據檢索出的文本和用戶輸入生成最終回答。

此方法克服了Transformer模型固有的知識記憶限制(如固定上下文長度與靜態知識庫),使模型能夠利用最新或大量的外部資料,而不需重新訓練整個模型。

在多模態資料預處理中的應用
在處理多模態資料時,Transformers提供的Tokenizer、ImageProcessor等預處理工具能將不同類型的資料轉換成模型可接受的tensor格式。RAG架構同樣可應用於多模態,藉由擴展檢索源與融合多種輸入,提升生成質量。


實作:

資料集

使用chatgpt、claude、gemini,先使用指令"幫我搜尋chatgpt、claude code的評價"給LLM基本知識記憶,然後請他生成固定格式的csv檔,包含正負面情緒不重複的各100則,發現chatgpt-5快速在判讀27種情緒中尤其是'興致', '勝利', '欽佩'這類較細膩的情緒時常會概括進"快樂"、"喜悅",無法被判定出來(免費的將就用),使用gemini 2.5 flash和claude sonnet 4則有比較貼合主觀感受的分類。
gemini的情緒分類很到位

資料集可供下載

模型訓練

起初使用27種情緒標籤,發現每一種情緒的資料量太少且容易因為資料比例懸殊(焦慮(50筆) vs 畏懼(1筆)),無法有效訓練模型。加上人工標註有些標註過度主觀,且標準不一,不利於產生統一標註的標準。導致最好的精確度只有0.39。
後來將27種情緒標籤歸類成四種,每種類的資料量有提升,雖然還是比例懸殊,透過隨機複製樣本讓每個種類樣本來到平均數量,則準確率已來到0.95,有顯著的提升。
訓練模型程式在colab
使用時需要將資料集上傳到colab右側資料夾"sample_data"中(預設讀檔路徑):
colab資料集上傳示意圖
step1.點擊左側工作列資料夾圖示
step2.滑鼠在sample_data上停留
step3.右側出現三個點,點擊下去
step4.在跳出選單選擇上傳,在檔案總管中選擇剛剛下載好的"emotion_dataset_500_3.csv"
step5.執行程式碼

# 積極情緒
'快樂', '喜悅', '滿足', '興奮',
'興致', '勝利', '欽佩', '驚喜',
'狂喜忘我', '開心', '愉快', '高興',
'幸福', '歡樂', '愛', '喜歡',
            
# 消極情緒  
'悲傷', '生氣', '焦慮', '厭惡',
'無聊', '混亂', '尷尬', '同情痛苦',
'畏懼', '難過', '失望', '痛苦',
'害怕', '恐懼', '討厭', '憤怒',

# 中性情緒
'中性', '冷靜', '平靜', '平常',
'普通', '一般',

# 期待情緒
'渴望', '娛樂消遣', '懷舊', '浪漫',
'美學欣賞', '敬畏', '崇拜', '期待',
'希望', '憧憬'
=== CSV情緒數據集分析器 ===
=== 載入CSV文件: /content/sample_data/emotion_dataset_500_3.csv ===
成功使用 utf-8 編碼載入文件
原始數據形狀: (404, 3)
列名: ['emotion', 'text', ' tag']
清理後數據形狀: (404, 3)
情緒分布: {'積極': np.int64(194), '消極': np.int64(152), '期待': np.int64(44), '中性': np.int64(13), 'emotion': np.int64(1)}
=== 處理數據 ===
處理完成: 404 筆資料
詞性校正: 0 筆
合併後情緒分布: {'積極': 194, '消極': 152, '中性': 13, '期待': 44, 'emotion': 1}
=== 數據集分析 ===
總樣本數: 404
文本列: text
情緒列: emotion

文本長度統計:
  平均長度: 23.2
  中位數長度: 23.0
  最短: 4
  最長: 47

原始情緒分布:
  積極: 194 (48.0%)
  消極: 152 (37.6%)
  期待: 44 (10.9%)
  中性: 13 (3.2%)
  emotion: 1 (0.2%)

合併後情緒分布:
  積極: 194 (48.0%)
  消極: 152 (37.6%)
  中性: 13 (3.2%)
  期待: 44 (10.9%)
  emotion: 1 (0.2%)
=== 開始訓練模型 ===
原始數據: 404 筆
原始情緒分布: {'積極': 194, '消極': 152, '中性': 13, '期待': 44, 'emotion': 1}
創建增強特徵...
=== 數據平衡處理 ===
原始分布: {'積極': 194, '消極': 152, '中性': 13, '期待': 44, 'emotion': 1}
平衡後分布: {'積極': 194, '消極': 194, '中性': 194, '期待': 194, 'emotion': 194}
最終訓練數據: 970 筆
最終情緒分布: {'積極': 194, '消極': 194, '中性': 194, '期待': 194, 'emotion': 194}
測試集準確率: 0.954

詳細分類報告:
              precision    recall  f1-score   support

     emotion       1.00      1.00      1.00        39
          中性       0.97      1.00      0.99        38
          期待       0.95      0.97      0.96        39
          消極       0.88      0.95      0.91        39
          積極       0.97      0.85      0.90        39

    accuracy                           0.95       194
   macro avg       0.96      0.95      0.95       194
weighted avg       0.96      0.95      0.95       194


=== 模型訓練完成,準確率: 0.954 ===

=== 預測測試 ===

文本: 這個產品真的很棒,我非常滿意
預測情緒: 積極
信心度: 0.600
概率分布: [(np.str_('積極'), '0.600'), (np.str_('消極'), '0.200'), (np.str_('期待'), '0.130')]

文本: 服務態度太差了,讓我很失望
預測情緒: 消極
信心度: 0.501
概率分布: [(np.str_('消極'), '0.501'), (np.str_('積極'), '0.281'), (np.str_('期待'), '0.129')]

文本: 還可以,沒什麼特別的感覺
預測情緒: 積極
信心度: 0.466
概率分布: [(np.str_('積極'), '0.466'), (np.str_('消極'), '0.287'), (np.str_('期待'), '0.152')]

文本: 今天天氣很好,心情愉快
預測情緒: 積極
信心度: 0.572
概率分布: [(np.str_('積極'), '0.572'), (np.str_('消極'), '0.260'), (np.str_('期待'), '0.092')]

文本: 這個電影太無聊了,浪費時間
預測情緒: 消極
信心度: 0.418
概率分布: [(np.str_('消極'), '0.418'), (np.str_('積極'), '0.324'), (np.str_('期待'), '0.173')]
模型已保存至: emotion_model_3.pkl


上一篇
第1天:EmoRAG專案初始化與環境建置
下一篇
第3天:關鍵字檢索實作與情緒標籤
系列文
從RAG到EmoRAG:讓AI真正聽懂你的心聲5
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言