บันทึก training data science EP 11: NLP & Spacy – สอนภาษารัก
ตอนก่อนหน้า: บันทึก training data science EP 10: Cluster – เชื่อมก้อนให้เป็นกลุ่ม
ที่ผ่านมา เราต้องเรียนภาษาคอมพิวเตอร์ แต่ตอนนี้เป็นยุคที่คอมพิวเตอร์ต้องเรียนภาษาของเราแล้วล่ะฮะ
Natural Language Processing (NLP)
มันคือศาสตร์ของการแปลงและแปลข้อความที่มนุษย์พูดกัน ออกมาเป็นชุดข้อมูลที่ใช้วิเคราะห์ในงานต่อไปฮะ เช่น เราพูดว่า “ฉันรักเธอ” ชุดข้อมูลที่ได้อาจเป็น “ด้านบวก”, “ความรู้สึก”, “โรแมนติก” เป็นต้นฮะ
ก่อนอื่น เราต้องรู้จักคำว่า Tokenization หรือการแบ่งคำกันก่อน ยกตัวอย่างเวลาเราพูดคุยกัน เราจะเข้าใจความหมายของประโยคจากการรวมความหมายของแต่ละคำ ถูกมั้ยฮะ ทีนี้ Python เองก็มี Library ที่มีความสามารถ tokenization หลายตัวเลยแหละ สำหรับบล็อกนี้ จะใช้ Spacy กัน
Spacy
ครั้งนี้เราจะใช้ Spacy เพื่อวิเคราะห์หา rating จากชื่อการ์ตูนกัน (อันนี้เป็น final project ของผมเองเน้อ) ไอเดียคือการแบ่งชื่อการ์ตูนออกมาเป็นคำๆ แล้วแปลงคำเป็นตัวเลข คล้ายๆ index และใช้ Random Forest เพื่อสร้าง estimator ทำนาย rating จากตัวเลขที่ว่าฮะ
มาเริ่มกันเลย
1. Install
ก่อนอื่น เราต้องมี library Spacy อยู่ในเครื่องก่อน ทำตามลิงก์นี้เลยฮะ
2. เตรียม dataset
Dataset อันนี้ ผมได้มาจาก Kaggle ของ CooperUnion ตามลิงก์นี้ฮะ และนี่คือหน้าตาของไฟล์ตั้งต้นของเรา
3. import และอ่านไฟล์ dataset
เริ่มต้นก็ใช้ Pandas
มา .read_csv()
กันก่อนฮะ
4. import spacy
dataset เป็นภาษาอังกฤษ ก็เลยใช้ spacy model เป็นภาษาอังกฤษ ซึ่งเราก็ต้อง download model นั้นด้วยคำสั่ง .load()
ฮะ ในที่นี้คือ "en_core_web_sm"
นั่นเอง และวิธีการ tokenize (แบ่งคำ) ก็ง่ายมาก นั่นคือ ป้อนข้อความลงไปใน class ที่เรา .load()
เอาไว้ มันจะ return เป็น iterator ของคำที่มันแบ่งมาได้ ตามรูปฮะ
และ iterator ที่ว่ามันมี properties ระบุหน้าที่ของคำนั้นได้ด้วยฮะ นั่นคือ .pos_
และเราก็ระบุคำด้วย .text
5. แบ่งคำตามใจฉัน
จากรูปข้างบน เราต้องการไม่ให้มันมีเครื่องหมายอื่นๆ นอกจากตัวเลข และตัวอักษร จึงต้องเขียน method เพิ่มนิดหน่อย โดยใช้ regular expression ฮะ
import re
def splitter(val, processor):
pattern = r'[0-9a-zA-Z]+'
return [r.group().lower() for r in re.finditer(pattern, processor(val).text)]
ความหมายของ [0-9a-zA-Z]+
คือ เลือกเฉพาะที่เป็น 0 – 9 หรือ a – z พิมพ์เล็ก หรือ A – Z พิมพ์ใหญ่ ส่วนเครื่องหมายบวกแปลว่ามีตั้งแต่หนึ่งตัวขึ้นไปก็ได้แล้ว จากรูปข้างบนจะเห็นเลยว่ามันแยกออกมาตามที่เราตั้งใจไว้ฮะ
6. แบ่งคำทั้งหมด
เมื่อเราได้วิธีแบ่งคำตามที่เราต้องการแล้ว ขั้นตอนต่อมา คือ การสร้าง column ใหม่จากการแบ่งคำของชื่อการ์ตูนนั่นเองฮะ
pattern_splitter = [splitter(n, processor) for n in anime.name]
pattern_splitter
ถึงตรงนี้ เราจะมี column ที่ชื่อ “name_token” ไว้เก็บชื่อการ์ตูนที่แบ่งคำเสร็จเรียบร้อยแล้วฮะ
anime.loc[:, 'name_token'] = pd.Series(pattern_splitter)
anime
7. ทำความสะอาดก่อนนำไปใช้
เราจะ predict rating ดังนั้นจึงต้องกำจัดข้อมูลที่ไม่มี rating ออกไปก่อน จะได้ train ได้ผลที่ดีขึ้นฮะ
8. แยกกลุ่ม train และ test
จากทั้งหมด 12,064 rows ในขั้นที่ 7 เนี่ย เรามาแบ่งเป็น train set และ test set นะฮะ ครั้งนี้เรากำหนดให้ train set เป็น 70% ของทั้งหมด
9. Vectorizer
Vectorizer ใน Scikit-learn คือการแปลงค่าให้อยู่ในรูปของ matrix ฮะ ตามรูปนี้ โดยเราจะใช้ TF-IDF vectorizer เพื่อคำนวณความถี่ของคำที่เกิดขึ้น
ก่อนอื่นก็สร้าง TfidfVectorizer
object
จากนั้นก็ .fit_transform()
กับ train set เพื่อเรียนรู้คำก่อน เก็บในตัวแปร matrix และ .transform()
กับ test set
10. Random Forest
ได้เวลาลงมือ train แล้วฮะ เริ่มจากสร้าง Regressor ขึ้นมาก่อน
เตรียมตัวแปร y เป็น rating ของ train set
แล้วก็ .fit()
โดยให้ตัวแปรแรกเป็น matrix ที่เป็น train set ผ่าน vectorizer ข้างต้น กับตัวแปรสองคือ y นั่นเอง
11. วัดผลของ Random Forest
เมื่อสร้าง estimator จาก .fit()
ข้างบนเสร็จแล้ว จะลองมาวัด score กัน ได้ค่า mse = 1.64 ฮะ
ลองเอามาเทียบค่ากันระหว่าง rating จริงกับ rating ที่ทำนายมาได้
แล้วเอามาวาดกราฟ ถือว่า อื้ม กระจายอย่างสวยงาม จะบอกว่าตอนที่คิดโจทย์นี้ก็ไม่ได้คาดหวังว่ามันจะมีความสัมพันธ์จริงจังระหว่างชื่อการ์ตูนกับ rating แต่เราคำนวณได้ผลมาแบบนี้ก็ค่อนข้างพอใจฮะ
12. Features ที่น่าสนใจ
เราสามารถใช้ .feature_importances_
ของ Random Forest เพื่อดูลำดับความสำคัญของแต่ละค่า features ควบคู่กับ .get_feature_names()
ของ vectorizer เพื่อดูว่าค่าไหนบ้างที่มีความสำคัญสูงๆ ฮะ
อันนี้แสดง DataFrame
ของ feature names กับ feature importances ฮะ
13. เทียบกับ Linear Regression
ลองสร้าง Linear Regression estimator มาเทียบกัน พบว่า ได้ mse = 2.98 สูงกว่า Random Forest ข้างบน แปลว่า estimator ตัวนี้แย่กว่าฮะ
NLP ภาษาไทย
สำหรับ NLP ภาษาไทยเนี่ย อาจารย์แนะนำให้รู้จัก pythainlp ฮะ ซึ่งในคลาสก็มีโชว์การใช้งานเบื้องต้น ซึ่งคล้ายกับ Spacy เลยฮะ นั่นคือ Tokenization และความสามารถอื่นๆ ฮะ
NLP ครั้งนี้เป็นแค่พื้นฐานนะฮะ ของจริงนี่มีการใช้งานประยุกต์หลากหลายมาก ไม่ว่าจะเป็นการเชื่อมโยงเนื้อหา (Content Classification), การวิเคราะห์ความรู้สึก (Sentiment Analysis) และอื่นๆ
รอบหน้าจะเป็นอะไร จะมาแชร์ให้อ่านฮะ
ตอนต่อไป: บันทึก training data science EP 12: skimage – ภาพจำยังชัดเจน