文字資料該怎麼分析?
文字屬於非結構化資料,不像正常身高、體重、年紀等是直接的數值型結構化資料,無法直接在資料科學、機器學習中使用。
因此,需要將文字轉成數值才能進行後續處理,而此轉換又稱為向量化。
目錄
- 文字資料該怎麼分析?
- 文字向量化
- tf-idf 簡介
- 如何在 Python 中使用
- 最後
文字向量化
最簡單的文字向量化方法就屬於 BoW(Bag of Word) 了,又稱為詞袋模型。
詞袋模型是一個基於單詞出現頻率來表示文字的方法,它並不考慮單詞的排列順序、或甚至是文法結構。
比如說一個分詞後的幾個句子:
原始句子:「每天努力學習資料科學,是為了成為一個資料科學家。」經過分詞後(jieba),會變成「每天/努力/學習/資料/科學/是/為/了/成為/一個/資料/科學家/」,此時每一個/分隔而成的就是一個詞,就可以用 BoW 來表示。
「每天」:1, 「努力」: 1, 「資料」: 2,以此類推。
就可以將上面這句話用向量表示為11維的向量[1,1,1,2,1,1,1,1,1,1],後續就可以使用任何ML的模型作為特徵輸入了。
但是這個方法有一個巨大的缺陷,隨著句子變長,重複的詞其特徵值會越來越大,在遇到許多贅詞的時候會顯得不符使用。
因此,為了平衡權重的調整,在不同長度的句子都可以更好地表示,也就是 tf-idf 的出現了!
tf-idf 簡介
有興趣可以去看看tf-idf定義,wiki講得很清楚!
這邊想與大家介紹的是 tf-idf 的背後直覺,tf 就是詞頻,也就是去數「詞」出現的頻率(機率),跟 BoW 沒有不同,而 idf 則是會根據該「詞」在各個檔案中出現的頻率倒數取 log,比如說我有 100 篇文章,而詞「科學家」只出現過 1 遍,那麼其 idf = log (100 / 1) = 2,如果在該篇文章中出現了 3 次(該文章總字數假設為100),則 tf = 3/100 = 0.03,就會得到 tf-idf = tf*idf = 0.03*2 = 0.06。
那我們可以看看相同另一個例子,如詞「是」可能就大量出現在各個文章中,比如 100 次,那麼 idf = log(100 / 100) = 1,而假設其中一篇文章的 tf 也為 0.03,其 tf-idf = 0.03*1 = 0.03。
可以發現,其數值在詞頻相同的情況下,因為出現在更多的文章中,就被限制了大小,可以達到贅詞會被限縮,而像「科學家」這樣比較有代表意義的則會給予比較大的權重。
tf-idf 背後的精神非常直覺,透過數學計算,將常出現在「各文章」的「詞」視為辨別度不高(idf),給予較低權重,但在「同一篇文章」中如果出現次數高(tf),可能具有代表意義,給予較高的權重,兩者互相平衡來表示。
如何在 Python 中使用(code snippet)
Python 的 sklearn 套件已經幫我們製作好了模組,其向量化只需要數行即可。後續即可輸入 ML 模型或者其他方法去分析。
ps: 還有許多超參數可供調整,可參考官方文件去研究唷!另外,此處套件會忽略「單字」,如果需要單字可以去更多研究唷!
from sklearn.feature_extraction.text import TfidfVectorizer# 已中文分詞
corpus = [
'我 是 優秀的 資料 科學 家',
'每天 學習 資料 科學 很 有趣']
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(corpus)
vectorizer.get_feature_names() # ['優秀的', '學習', '有趣', '每天', '科學', '資料']
print(X.shape) # (2, 6)
最後
但 tf-idf 也有它自身的缺陷,如不考慮詞的擺放順序、詞與詞之間是獨立的、隨著詞庫增加,維度會爆炸且稀疏等等,不過在很多情況下,是一個非常實用的技術!
那這次的 NLP 系列就到這邊告一段落了!希望大家有學會一個新的文字向量化方法,也可以了解其背後的直覺!
如果覺得文章有幫助,也希望可以給我一些掌聲👏讓我更有動力繼續分享類似的主題,也歡迎提供任何主題想法哦!
參考