大家午安,昨天介紹過羅吉斯迴歸的原理之後,今天要帶大家實作羅吉斯迴歸的模型,任務是要偵測推特上的貼文是否有憂鬱傾向。在NLP的領域裡面,我們把這種分析文本情感傾向的任務稱作「文本情感分析(sentiment analysis)」。偵測貼文是否具有憂鬱或自傷傾向也是現在對社群媒體運營者來說很重要的事情,相信大家應該都有聽說過FB跟IG會偵測你的貼文然後給予關心的事情。雖然做文本情感分析的方法有很多,但我們今天還是以比較基礎的特徵-TF-IDF來訓練模型,也順便把之前沒示範到的實作補起來。
先把資料讀到colab裡面。讀進來看之後你就會發現這個資料每一行的名稱也太長了吧,操作起來不是很方便,所以我們就幫他換幾個比較方便的名字吧。(順便複習一下pandas
的使用)
import pandas as pd
raw_data = pd.read_csv("/content/sentiment_tweets.csv")
raw_data.columns = ["index", "tweet", "label"]
今天一樣使用scikit learn
提供的工具來進行特徵萃取。因為最簡單的TF-IDF說白了就是在詞頻的基礎上多加了逆向文檔頻率的計算,實際使用scikit learn
操作的時候跟詞袋模型的萃取基本上沒什麼差異。我們一樣要把資料裡面的文本轉換成向量化工具可以讀懂的樣子。在初始化向量化工具之後就可以把轉換過的資料丟進去給他計算TF-IDF的值了。
raw_text = []
for rows in range(len(raw_data["tweet"])):
text = raw_data.at[rows, "tweet"]
raw_text.append(text)
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer()
vectorized_data = vectorizer.fit_transform(raw_text)
這個工具跟BOW不一樣的地方在於他多了一個可以讓我們看的IDF資料:
print(vectorizer.idf_[0:5])
# 輸出
[7.93876933 8.29544428 9.54820724 9.54820724 9.54820724]
接下來就跟詞袋模型一樣,我們把資料裡面的type取出來作為標記資料的行名,再跟計算結果統合成一個表示特徵的dataframe。
feature_arr = vectorizer.get_feature_names_out()
feature_data = vectorizer.transform(raw_text)
annotation = feature_data.toarray()
feature_df = pd.DataFrame(annotation, columns=[feature_arr])
label_df = raw_data[["label"]]
資料的前處理完成之後,我們就可以開始訓練模型了,這邊開始因為scikit learn
基本上都已經幫我們寫好工具了,跟Naive Bayes的進行都是大同小異的。
from sklearn.model_selection import train_test_split
data_train, data_test, label_train, label_test = train_test_split(feature_df, label_df, test_size=0.2, random_state=88)
我們一樣把Logistic Regression的套件引進來之後出使用模型,然後再把訓練集的標記資料跟正確答案丟給模型。
from sklearn.linear_model import LogisticRegression
model = LogisticRegression().fit(data_train, label_train)
這邊開始跟Naive Bayes的差異在於,因為Logistic Regression公式求出來的是它分屬不同類別的機率,所以除了預測結果之外,我們還可以看到準確的機率數字。
label_predict = model.predict(data_test)
print(label_predict[0:10])
label_predict_probability = model.predict_proba(data_test)
print(label_predict_probability[0:10])
# 輸出
[0 0 0 0 0 0 0 0 0 0]
[[0.94254135 0.05745865]
[0.9721023 0.0278977 ]
[0.9654564 0.0345436 ]
[0.9600599 0.0399401 ]
[0.96620099 0.03379901]
[0.93570204 0.06429796]
[0.95370278 0.04629722]
[0.94124656 0.05875344]
[0.95658776 0.04341224]
[0.91855423 0.08144577]]
從上面我們可以看到,測試集的前10筆資料都被預測為沒有憂鬱傾向的發文,還有這些發文屬於非憂鬱傾向的機率跟屬於憂鬱傾向的機率。最後當然還是要拿來跟正確答案比較一下,評估這個模型的表現囉~
from sklearn.metrics import confusion_matrix, precision_recall_fscore_support
print(confusion_matrix(label_test, label_predict))
evaluation = precision_recall_fscore_support(label_test, label_predict, average='macro')
accuracy = model.score(data_test, label_test)
print("accuracy: " + str(accuracy) + "\nprecision: " + str(evaluation[0]) + "\nrecall: " + str(evaluation[1]) + "\nfscore: " + str(evaluation[2]))
# 輸出
[[1605 0]
[ 44 414]]
accuracy: 0.98
precision: 0.99
recall: 0.95
fscore: 0.97
結果看起來也是非常好呢,大概是因為這邊提供的資料是比較漂亮,沒那麼多奇奇怪怪的網路用語,再加上有憂鬱傾向的文本比較少,他們的特徵如果相似的話就會顯得特別明顯。但這並不代表真實生活中再進行分類任務的時候也可以這麼美好,之後有機會再寫一篇文針對情感分析的難點做介紹。那麼今天就到這邊結束了,大家明天見~