How to find Subject, Verb, Object from spaCy and NLTK

Top'p Kullawattana
5 min readMay 5, 2020

--

ในปัจจุบัน การประมวลผลภาษาธรรมชาติ (NLP) เราสามารถค้นหาคำศัพท์ที่สามารถระบุคำ และความหมายของคำในประโยคได้อย่างง่ายแล้ว ซึ่งในทางซอฟต์แวร์ ผมได้ศึกษาโครงสร้างภาษาธรรมชาติ และสร้างเฟรมเวิร์คเพื่อกำหนดโครงสร้างทางภาษาในงานวิศวกรรมความต้องการ โดยจุดเริ่มต้นที่ผมศึกษา คือ การใช้ไลบราลี spaCy และ NLTK ซึ่งเป็นไลบราลีที่ประมวลผลภาษาธรรมชาติที่เขียนด้วยภาษาไพธอน โดยศึกษาวิธีการประสมคำ การแตกคำ และการแตกโครงสร้างประโยค ที่จะสามารถระบุได้ว่าเป็นประธาน กริยา หรือกรรม ซึ่งมีประโยชน์อย่างมากเลยครับ

ในส่วนของบทความ ผมจะขอนำเสนอ Algorithm ที่ใช้ในการประมวลผล มีวิธีการคิดและกระบวนการสร้างอัลกอริทึมเพื่อประมวลผล ดังนี้

การค้นหา SVO มีเริ่มต้นจากการระบุ Dependency Rule (Subject, Object)

  • Import โมเดลการวิเคราะห์โครงสร้างภาษา (WordNetLemmatizer) จากไลบราลี NLTK
  • Import โมเดลภาษาอังกฤษ (English) จากไลบราลี spaCy
  • สร้าง List ที่ระบุ Dependency ในการค้นหาประธาน (Subject) และกรรม (Object) เพื่อใช้ในการตรวจสอบกับ Token ที่ได้จากประโยค

*** Token : คือ ตัวเลขที่เปรียบเสมือนตัวแทนของคำ โดยเราสามารถตรวจสอบคำจากเลข Token ที่เราได้

สร้าง Main เพื่อทดสอบการประมวลผลโครงสร้างภาษา

  • สร้างเมธอด findSVOs เพื่อค้นหาโครงสร้างประโยค โดยเริ่มต้นจากการโหลดโมเดลภาษาของ spaCy โดยจะใช้ “en_core_web_sm” ซึ่งเป็นโมเดลการวิเคราะห์ภาษาขนาดเล็ก ซึ่งเราจะนำเข้าโครงสร้างประโยคตัวอย่าง นั้นคือ “making $12 an hour? where am i going to go? i have no other financial assistance available and he certainly won’t provide support.”
  • เก็บประโยคไว้ใน tok (โดยไลบราลี spaCy จะแปลงเป็น Token)

การทดสอบการค้นหา SVO ได้ผลลัพธ์การวิเคราะห์ ดังนี้

ต่อไป… การวิเคราะห์ของเรา จะไม่พูดถึงความหมายของคำ แต่จะพูดถึงโครงสร้างภาษาของคำแต่เพียงอย่างเดียว มาเริ่มการวิเคราะห์กันเลย

PART หลัก… การค้นหา SVO

  • สร้าง Array svos เพื่อเก็บโครงสร้าง (ประธาน (S), กริยา (V), กรรม (O))
  • โดยการเริ่มต้น สิ่งที่ง่ายที่สุดของการแบ่งประโยค คือ เริ่มต้นการตรวจสอบคำกริยาแท้ (Verb) จาก Token ที่ตำแหน่ง (pos) ของคำกริยา และจะต้องมี dep ที่ไม่ใช่กริยาช่วย “aux”
  • ต่อมา จะเริ่มการค้นหาประธานในประโยคในทุกๆ ประโยค โดยเรียก getAllSubs เพื่อหาประธาน (Subject) ที่มีความสัมพันธ์กับ Verb ทั้งหมด ซึ่งจะได้ Verb กับ Object ออกมา จากกระบวนการนี้
  • แบ่งการวนลูปเพื่อดูแต่ละประโยค โดยแบ่งประโยคจากประธาน โดยประธาน 1 ตัว จะมีกรรม (Object) และใน Object เอง จะมีการตรวจสอบ isNegated (“no”, “not”, “n’t”, “never”, “none”) จากการตรวจสอบใน Token โดยดูจาก List ทางซ้ายและทางขวา (เป็นกระบวนการค้นหาของ spaCy) ซึ่งจะมีการตรวจสอบ verbNegated หรือ objNegated ถ้าเข้าข่าย… ให้ใส่เครื่องหมาย “!”

PART ย่อย ที่ 1 ค้นหา Subject

จากกระบวนการที่แล้ว เรายังไม่ทราบถึงวิธีการค้นหา Subject ทั้งหมด ในกระบวนการนี้เราจะมาพูดถึงกัน

การค้นหา Subject ทั้งหมด ด้วย getAllSubs โดยใช้ Verb

  • ตรวจสอบ verbNegated จาก isNegated(“no”, “not”, “n’t”, “never”, “none”)
  • ตรวจสอบ SUBJECT จาก Token โดยดูจากตำแหน่งของคำที่ไม่เป็น “DET” ให้ Get Subject เหล่านั้น ออกมา
  • ถ้าตรวจสอบแล้วไม่พบเลย ให้ค้นหาต่อที่ findSubs(verb)

กรณีที่ 1 ถ้าเจอ Subject ให้เริ่มการ getSubsFromConjunctions

  • เริ่มต้น คือ สร้าง Array เพื่อเก็บ moreSubs ที่ได้ทั้งหมด
  • หลังจากนั้น ตรวจสอบ Subject ที่ได้มาทั้งหมด โดยใช้กระบวนการของ spaCy คือการค้นหา left และ right ถ้าใน rightDeps. พบคำว่า “and” แสดงว่า ยังมีประธานที่แสดงอยู่ในประโยค หลังจากคำว่า “and” ให้ตรวจสอบและค้นหาต่อไปและทำการเก็บไว้ใน Array ที่มีชื่อว่า moreSubs
  • เมื่อตรวจสอบ list ของประโยคแล้วยังไม่หมด ให้ตรวจสอบต่อ ถ้าตรวจสอบว่าตรงตาม List ที่เป็น SUBJECT และมี token ที่เป็น NOUN ให้เก็บไว้
  • วนลูปเพื่อตรวจสอบจนกว่าจะหมด

กรณีที่ 2 ถ้าไม่เจอ Subject ให้ค้นหาในทุกๆ Token

ให้ get word จาก Token นั้นออกมา

ในส่วนที่ 1 ตรวจสอบถ้าตำแหน่งของ Head เป็น “Verb” และไม่เป็น “NOUN” และเป็น Head คนละตัวกัน ให้เก็บ Head และ Return Head นั้นออกไป

ในส่วนที่ 2 ตรวจสอบตำแหน่งของ Head ที่เป็น “VERB”

  • ในกรณีแรก ค้นหา Subject โดยตรวจสอบ Token จาก head โหนดทางซ้าย และ Dep = “SUB”
  • เช็คว่า ถ้ามี Subject จากโหนดทางซ้าย ให้ตรวจสอบ verbNegated จาก isNegated(“no”, “not”, “n’t”, “never”, “none”) และให้กลับไปเรียก getSubsFromConjunctions เพื่อค้นหา Subject ต่อไป แล้ว Return Subject กับ verbNegated
  • ในกรณีต่อมา ถ้าไม่มี Subject หรือตรวจสอบว่า head ไม่เป็น Verb หรือ Noun ดังนั้น ให้เรียก findSubs อีกครั้ง ก็คือกลับไปวนตรวจสอบใหม่จนหมด
  • สุดท้าย ตรวจสอบจนหมดทั้งประโยค

ในส่วนที่ 3 ตรวจสอบถ้า Head = “Noun” ให้เรียก findSubs อีกครั้ง

และ… ถ้าไม่มี Head ที่เป็น Verb หรือ Noun เลย ให้ Return [] , false ถือว่าอัลกอรึทีมค้นหาแล้ว ไม่เจออะไร

PART ย่อย ที่ 2 ค้นหา Object

การค้นหากรรมจาก getAllObject จาก Verb ให้ค้นหาตามโหนดที่อยู่ทางขวา

  • ตรวจสอบโครงสร้างประโยคด้วยการเช็ค Dependency ที่เป็น OBJECTS ตาม list ที่กำหนดไว้ในตอนแรก
  • ตรวจสอบ Object จาก Preposition (ด้วย getObjsFromPrepositions) จากประโยค ถ้าเจอ ให้เก็บไว้ที่ตัวแปร objs

ในส่วนของ getObjsFromPrepositions(list(v.right))

โดยการค้นหา Objs จาก getObjsFromConjunctions จาก Verb เริ่มต้นจาก การสร้าง Array Objs และวน deps โดยตรวจสอบในทุกๆ ตำแหน่ง (position) ที่เป็น “ADP” และมี DEP เป็น “PREP” หลังจากนั้นให้ตรวจสอบ dep ที่เป็น Object หรือ (POS เป็น “PRON” และ token lower เป็น “me”) ให้ Return Objs และเก็บค่า New Verb และ New Object ใน Objs

  • กลับมาสู่การตรวจสอบ Object จาก getObjFromXcomp โดยตรวจสอบ deps ถ้า position ที่ตรวจสอบเป็น “VERB” และ dep เป็น “xcomp”
  • ได้ New Verb และ New Object จาก Xcomp
  • เก็บค่า dep ไว้ที่ตัวแปร v
  • ค้นหา v.right ใน list
  • ค้นหา dependency type ที่เป็น OBJECTS จาก token
  • ถ้ามี Objs ให้ getObjsFromConjunctions จาก Objs

การแสดงผล Dependency ให้แสดงตาม Token (โครงสร้างประโยค) ได้เลย

ตัวอย่างการวิเคราะห์แบบ Complex Sentence

“Every weekday morning, the database is backed up and then it is checked to see whether the Account Defaulter table has new records. If no new records are found, then the process should check the CRM system to see whether new returns have been filed. If new returns exist, then register all defaulting accounts and customers. If the defaulting client codes have not been previously advised, produce another table of defaulting accounts and send to account management. All of this must be completed by 2:30 pm, if it is not, then an alert should be sent to the supervisor. Once the new defaulting account report has been completed, check the CRM system to see whether new returns have been filed. If new returns have been filed, reconcile with the existing account defaulters table. This must be completed by 4:00 pm otherwise a supervisor should be sent a message.”

การทดสอบการค้นหา SVO ได้ผลลัพธ์การวิเคราะห์ ดังนี้

[(‘table’, ‘have’, ‘records’),
(‘process’, ‘check’, ‘system’),
(‘table’, ‘default’, ‘accounts’),
(‘supervisor’, ‘send’, ‘message’)]

--

--

Top'p Kullawattana

Coding Stylist of Kept by Krungsri, I have experience of 10 years in the design and implementation of enterprise applications.