เขียน Python สร้างแบบจำลองการวิเคราะห์รู้สึก (Sentiment Analysis) สำหรับภาษาไทย
บทความนี้จะแนะนำการเขียนภาษา Python สำหรับสร้างแบบจำลองการวิเคราะห์รู้สึก (Sentiment Analysis) จากข้อมูลที่เป็นข้อความภาษาไทย โดยใช้หลักการของการวิทยาการข้อมูล (Data Science) การเรียนรู้ของเครื่อง (Machine Learning) และ การประมวลภาษาธรรมชาติ (Natural language Processing: NLP)
สามารถทำตาม clip ได้เช่นเดียวกับบทความนี้นะครับ
ติดตั้ง Software
- Miniconda เครื่องมือในการจัดการ package ต่าง ๆ ของ Python โดยจะเหมาะสำหรับงานที่เกี่ยวกับวิทยาการข้อมูล (Data Scientist) ดาวน์โหลดและติดตั้งได้จาก https://docs.conda.io/en/latest/miniconda.html
*ระหว่างติดตั้ง Miniconda อย่าลืมเลือก Add Miniconda to my PATH enviornment vairable ด้วยนะครับ ตามรูปด้านล่าง จะได้เรียกคำสั่ง conda ผ่าน Command prompt ได้
สร้างสภาพแวดล้อมสำหรับ Python และติดตั้ง Package เพิ่มเติม
เปิด Command Prompt ขึ้นมา ทำการสร้างสภาพแวดล้อมสำหรับ Python ด้วยคำสั่ง conda และติดตั้ง package เพิ่มเติมด้วยคำสั่ง conda และ pip ตามด้านล่าง
- pandas และ matplotlib เป็น package พื้นฐานสำหรับการทำด้านการวิเคราะห์ข้อมูล
- PyThaiNLP : Thai Natural Language Processing in Python สำหรับการตัดคำภาษาไทย หรือที่เรียกว่า Word Tokenization
- Jupyter Notebook เป็นเครื่องมือในการเขียนภาษา Python ผ่านหน้า browser
conda create -n nlp-env
conda activate nlp-env
conda install -c conda-forge notebook scikit-learn
conda install pip
pip install pandas matplotlib pythainlp
เริ่มต้นเขียน Python
สร้าง folder งานของเราขึ้นมา ดังตัวอย่างด้านล่างที่จะไปสร้าง folder ชื่อว่า nlp ที่ drive d
d:
mkdir nlp
cd nlp
เริ่มใช้งาน Jupyter Notebook ด้วยคำสั่งด้านล่าง (ถ้าครั้งหน้าเปิดเครื่องมาใหม่แล้วจะเรียกใช้ Jupyter Notebook สามารถเรียกคำสั่งตามด้านล่างได้เลย)
d:
cd nlp
conda activate nlp-env
jupyter notebook
เลือก New > Python 3 เพื่อทำการเขียน code
ทำการใส่คำสั่งด้านล่างไว้ที่ cell แล้วกดปุ่ม Run เพื่อเป็นการ run code ดังกล่าว ถ้าไม่มี error ก็ทำต่อได้เลยครับ
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
สำหรับข้อมูลที่เราจะใช้ในการสร้างแบบจำลอง จะเป็นข้อมูลตัวอย่างจาก PyThaiNLP สามารถดาวน์โหลดจาก https://raw.githubusercontent.com/PyThaiNLP/thai-sentiment-analysis-dataset/master/review_shopping.csv
- review_shopping.csv เป็นไฟล์กำกับข้อความรีวิวจากเว็บขายของออนไลน์แห่งหนึ่ง เมื่อปี 2561 โดยมี 2 tag คือ pos และ neg กำกับโดย นาย วรรณพงษ์ ภัททิยไพบูลย์
ทำการดาวน์โหลดไฟล์ review_shopping.csv ไปไว้ที่โฟลเดอร์เดียวกับที่เรา start Jupyter Notebook นะครับ นั้นก็คือที่ d:\nlp
จากนั้นทำการอ่านข้อมูลจากไฟล์ดังกล่าวเก็บเข้าตัวแปร จะเห็นได้ว่าข้อมูลมี 2 คอลัมน์คือ text (ข้อความรีวิว) และ sentiment ระบุว่าข้อความรีวิวเป็นแง่บวก (post) หรือแง่ลบ (neg)
df = pd.read_csv('review_shopping.csv', sep='\t', names=['text', 'sentiment'], header=None)df
ดูว่ามีข้อความที่เป็นแง่บวกและแง่ลบ อย่างละกี่ข้อความ
df['sentiment'].value_counts().plot.bar()
ตัดคำ ลบคำ stopword และ punctuation (เครื่องหมายวรรคตอน) ออกจากข้อความ
ถัดมาเราจะดึง array ของ stopwords หรือคำที่ไม่ค่อยสื่อความหมาย จาก PyThaiNLP มาเก็บไว้ที่ตัวแปร thai_stopwords
from pythainlp.corpus.common import thai_stopwordsthai_stopwords = list(thai_stopwords())
thai_stopwords
จากนั้นจึงทำการตัดคำ (Word Tokenize) ลบ stopword และ punctuation (เครื่องหมายวรรคตอน) ออกจากข้อความ และเปลี่ยนข้อความให้มีช่องว่างระหว่างคำ (ให้เหมือนภาษาอังกฤษ) เพื่อนำไปประมวลผลกับ Word Cloud และสร้าง Bag of Word (Bow) ง่ายขึ้น ซึ่งอันนี้ผู้เขียนคิดว่าจะง่ายต่อการประมวลผลกับ library ต่าง ๆ มากกว่าถ้าปรับข้อความให้เป็นรูปแบบนี้
from pythainlp import word_tokenizedef text_process(text):
final = "".join(u for u in text if u not in ("?", ".", ";", ":", "!", '"', "ๆ", "ฯ"))
final = word_tokenize(final)
final = " ".join(word for word in final)
final = " ".join(word for word in final.split()
if word.lower not in thai_stopwords)
return finaldf['text_tokens'] = df['text'].apply(text_process)
df
ดูความถี่ของคำด้วย Word Cloud
การแสดงความถี่ของคำด้วย Word Cloud จะทำให้เราทราบเบื้องต้นว่าคำส่วนใหญ่ที่ปรากฏในข้อความมีคำว่าอะไรบ้าง โดยถ้าการแสดงผลของคำใน Word Cloud มีขนาดใหญ่เท่าไหร่ จะหมายถึงจำนวนของความถี่ของคำคำนั้นที่ปรากฏอยู่ในข้อความ
Word Cloud ของข้อความที่เป็นแง่ บวก (positive)
from wordcloud import WordCloud, STOPWORDSdf_pos = df[df['sentiment'] == 'pos']
pos_word_all = " ".join(text for text in df_pos['text_tokens'])
reg = r"[ก-๙a-zA-Z']+"
fp = 'THSarabunNew.ttf'wordcloud = WordCloud(stopwords=thai_stopwords, background_color = 'white', max_words=2000, height = 2000, width=4000, font_path=fp, regexp=reg).generate(pos_word_all)
plt.figure(figsize = (16,8))
plt.imshow(wordcloud)
plt.axis('off')
plt.show()
Word Cloud ของข้อความที่เป็นแง่ ลบ (negative)
df_neg = df[df['sentiment'] == 'neg']
neg_word_all = " ".join(text for text in neg_pos['text_tokens'])wordcloud = WordCloud(stopwords=thai_stopwords, background_color = 'white', max_words=2000, height = 2000, width=4000, font_path=fp, regexp=reg).generate(neg_word_all)plt.figure(figsize = (16,8))
plt.imshow(wordcloud)
plt.axis('off')
plt.show()
Split ข้อมูลเป็น Train (70%) Test (30%)
เราจะแบ่งข้อมูลออกเป็น 2 ส่วนนะครับ คือส่วนของการฝึกฝน (train) แบบจำลอง 70% และส่วนของการทดสอบ (test) แบบจำลอง 30% โดย X คือตัวแปรต้นที่เป็นข้อความ และ y คือตัวแปรตามที่เป็น sentiment (pos หรือ neg)
from sklearn.model_selection import train_test_splitX = df[['text_tokens']]
y = df['sentiment']X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=101)
Word Vectorizer และ Bag-of-Words (BoW)
การจะสร้างแบบจำลองวิเคราะห์ความรู้สึกจากข้อความ จำเป็นจะต้องแปลงข้อมูลให้อยู่ในรูปแบบที่มีจำนวนของตัวแปรที่ทำกัน โดยเริ่มต้นเราจะใช้ Count Vectorizer ของ sklearn มาช่วยในการจัดการดึงคำทั้งหมดออกมาจากข้อความ และจัดเก็บในรูปแบบ Vector (จะคล้าย ๆ กับลักษณะของพจนานุกรมที่มีการระบุตัวเลข index ของแต่ละคำด้วย)
from sklearn.feature_extraction.text import CountVectorizercvec = CountVectorizer(analyzer=lambda x:x.split(' '))
cvec.fit_transform(X_train['text_tokens'])cvec.vocabulary_
จากนั้นที่บรรทัดแรกทำการสร้าง Bag-of-Words (BoW) ที่เปรียบเสมือนกับตารางที่มีแถวเป็นข้อความ คอลัมน์เป็นคำทั้งหมด และค่าคือจำนวนคำที่ปรากฏในข้อความดังกล่าว ดังตัวอย่างด้านล่าง
เราจะใช้ BoW นี้ในการฝึกฝนแบบจำลอง โดยบรรทัดที่ 2 ใช้แสดงข้อมูลให้เห็นภาพเฉย ๆ
train_bow = cvec.transform(X_train['text_tokens'])pd.DataFrame(train_bow.toarray(), columns=cvec.get_feature_names(), index=X_train['text_tokens'])
สร้างแบบจำลอง Logistic Regression เพื่อจำแนกความรู้สึก positive หรือ negative
ทำการสร้างแบบจำลอง Logistic Regression เพื่อจำแนก (classify) ข้อความว่าเป็น pos หรือ neg โดยให้ตัวแปรต้นเป็น BoW ที่สร้างจากข้อความสำหรับการฝึกฝน และตัวแปรตามคือ y_train หรือก็คือคอลัมน์ sentiment ที่แบ่งไว้สำหรับการฝึกฝน
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
lr.fit(train_bow, y_train)
ทดสอบแบบจำลอง
ใช้ sklearn ในการทดสอบแบบจำลองว่ามีความแม่นยำมากน้อยแค่ใหน โดยดูจาก precision และ recall ได้เลย ซึ่งโดยแล้วอยู่ที่ประมาณ 0.9 ซึ่งเป็นที่น่าพอใจสำหรับผมนะครับ 555
from sklearn.metrics import confusion_matrix,classification_reporttest_bow = cvec.transform(X_test['text_tokens'])
test_predictions = lr.predict(test_bow)
print(classification_report(test_predictions, y_test))
ทดสอบกับข้อความที่เราสร้างขึ้นเอง
สามารถทดสอบกับข้อความที่เราสร้างขึ้นเองได้ โดยตัวอย่างตามด้านล่างที่เป็นข้อความว่า ตรงปกส่งไวครับ ผลลัพธ์ที่ได้คือ pos ซึ่งหมายถึงเป็นข้อความในแง่บวก
my_text = 'ตรงปกส่งไวครับ'
my_tokens = text_process(my_text)
my_bow = cvec.transform(pd.Series([my_tokens]))
my_predictions = lr.predict(my_bow)
my_predictions
อีกตัวอย่างเป็นข้อความว่า ไม่ตรงปกส่งช้าครับ ผลลัพธ์ที่ได้คือ neg ซึ่งหมายถึงเป็นข้อความในแง่ลบนั้นเอง
my_text = 'ไม่ตรงปกส่งช้าครับ'
my_tokens = text_process(my_text)
my_bow = cvec.transform(pd.Series([my_tokens]))
my_predictions = lr.predict(my_bow)
my_predictions
จบละครับ อย่างที่เห็นว่าเราสามารถสร้างแบบจำลองเพื่อจำแนกความรู้สึกได้ จากการนั้นขอความที่มีอยู่แล้วมาทำการ label ว่าเป็น pos หรือ neg จากนั้นก็ทำตามบทความนี้ ผลลัพธ์ที่ได้ก็อาจจะนำมาใช้ในการคัดกรองข้อความที่ได้จากลูกค้าว่าพึงพอใจแค่ใหน ควรจะปรับปรุงสินค้าหรือบริการใดเป็นพิเศษ หรือถ้าใครมีไอเดียการประยุกต์ใช้แบบใหนก็แชร์กันมาได้นะครับ พบกันใหม่บทความถัดไปครับ
บทความโดย อ.ดร.กานต์ ยงศิริวิทย์
วิทยาลัยนวัตกรรมดิจิทัลเทคโนโลยี มหาวิทยาลัยรังสิต