Theppitak's blog

My personal blog.

05 มิถุนายน 2552

Improved Unknown-Word Boundaries in LibThai

เมื่อตอนที่ออกแบบอัลกอริทึมตัดคำใน libthai นั้น การจัดการคำที่ไม่อยู่ในพจนานุกรม (unknown word) จะไม่เน้นละเอียดมากนัก โดยจะอาศัยการตรวจสอบจุดตั้งต้นพยางค์ถัดไปที่เป็นไปได้อย่างคร่าว ๆ แล้วพยายาม recover ด้วยการหาจุดแรกที่สามารถเริ่มตัดคำต่อได้

การตรวจสอบที่ว่านั้นก็เขียนง่าย ๆ คือถ้าเจอสระหน้า พยัญชนะที่ไม่ได้ต่อท้ายสระหน้า หรือตัว ฤ ฦ ก็ถือเป็นจุดเริ่มพยางค์ให้ทดลองตัดคำเพื่อ recover ได้แล้ว เพราะฉะนั้น ผลลัพธ์จึงอาจดูโง่ ๆ ในบางกรณี เช่น ลองแกล้งมันดูแบบนี้:

> เชล็งบดลนที
เชล็|งบ|ดล|นที

ซึ่งจะดูฉลาดกว่าถ้าจะพยายามเดาว่าคำว่า "เชล็ง" อาจเป็นคำที่ไม่อยู่ในพจนานุกรม มากกว่าจะเดาว่า "เชล็" โดยไม่มีตัวสะกด มีตัวอย่างอื่นที่คุณ cwt เคยทำให้ดูขณะคุยกันทางห้อง #tlwg อีก

การตรวจสอบนั้น ถ้าพยายามใช้กฎละเอียดมาก ก็ต้องชั่งน้ำหนักระหว่างความถูกต้องกับประสิทธิภาพ ถ้าตรวจสอบละเอียดเกินไป อาจเสียเวลาคำนวณนานได้ โดยเฉพาะในอัลกอริทึมของ libthai ที่ใช้วิธีเรียกฟังก์ชันตรวจสอบ isleadable() ทุกรอบที่จะตรวจสอบจุดแบ่งพยางค์ ก็เลยยังชะลอความคิดนี้ไว้ก่อน

แต่เมื่อเร็ว ๆ นี้ ได้ตัดสินใจพยายามทำเพิ่ม โดยลองเพิ่มกรณีตรวจสอบเข้าไปอีก แรก ๆ ก็ทำเฉพาะกรณีที่ไม่ซับซ้อนเท่านั้น เพื่อไม่ให้ประสิทธิภาพตกมากนัก แต่ทำไปทำมาก็ได้ไอเดีย ว่าถ้าเรา preprocess มันซะรอบเดียวแต่ต้น เราจะทำให้ซับซ้อนกว่านั้นก็ได้ จากนั้น เวลาที่อัลกอริทึมต้องการตรวจสอบ ก็แค่ตรวจจากค่าที่คำนวณไว้ก่อนแล้วเท่านั้นเอง ไม่ต้องคำนวณใหม่ทุกรอบ

ก็ดูเป็นทางออกที่ดี ปรากฏว่าสามารถตรวจสอบกรณีซับซ้อนได้ โดยไม่ทำให้ช้าลง กรณีที่ตรวจสอบไปก็คือ:

  • พยัญชนะที่มีทัณฑฆาตตามหลังในระยะไม่เกิน 2 อักขระ เป็นจุดตั้งต้นพยางค์ไม่ได้ เช่น ธ์ ธุ์ ธิ์ ณ์
  • พยัญชนะที่ตามหลังไม้หันอากาศหรือสระอือโดยอาจมีวรรณยุกต์คั่นหรือไม่ก็ได้ เป็นจุดตั้งต้นพยางค์ไม่ได้ เช่น ขั ตั้ มื ซื้ ฟื้
  • พยัญชนะที่ตามด้วยไม้ไต่คู้ แล้วตามด้วย อ อ่าง หรือ ว แหวน ตัวพยัญชนะแรกสามารถเป็นจุดตั้งต้นพยางค์ได้ แต่อักขระที่ตามหลังอีก 3 ตัว ไม่สามารถเป็นจุดตั้งต้นพยางค์ได้ทั้งหมด เช่น ช็อก ช็วก
  • หากพบสระเอ/แอ:
    • ตัวสระเอ/แอ สามารถเป็นจุดตั้งต้นพยางค์ได้
    • พยัญชนะที่ตามมาเป็นจุดตั้งต้นพยางค์ไม่ได้ เช่น เ
    • และถ้าพบต่อไปว่ามีไม้ไต่คู้หรือสระบนต่อท้ายพยัญชนะ (โดยอาจมีวรรณยุกต์ร่วมด้วยหรือไม่ก็ได้) พยัญชนะที่ตามหลังไม้ไต่คู้หรือสระบนนั้นก็ไม่สามารถเป็นจุดตั้งต้นพยางค์ได้เช่นกัน เช่น เก็ แข็ เสี เสื เสี่ เสื่
    • ถ้าพบว่าอักขระที่สามถัดจากสระเอ/แอ เป็นไม้ไต่คู้ โดยที่อักขระก่อนไม้ไต่คู้ไม่ใช่ ก ไก่ (ถ้าเป็น ก ไก่ จะกลายเป็นคำว่า "ก็") และอักขระถัดจากไม้ไต่คู้ไม่ใช่ อ อ่าง หรือ ว แหวน (ถ้าเป็น จะกลายเป็นพยางค์ใหม่ เช่น "ช็อก") อักขระถัดจากสระเอ/แอ 4 ตัวรวด ไม่สามารถเป็นจุดตั้งต้นพยางค์ได้ทั้งหมด เช่น เขบ็ดมล็ด
  • หากพบสระ โ ใ ไ พยัญชนะถัดไปไม่สามารถเป็นจุดตั้งต้นพยางค์ได้ เช่น โต้ท้
  • พยัญชนะกรณีอื่น ๆ มีโอกาสเป็นจุดตั้งต้นพยางค์ได้ทั้งหมด
  • ฤ ฦ มีโอกาสเป็นจุดตั้งต้นพยางค์ได้
  • อักขระอื่น ๆ ที่เหลือ ไม่สามารถเป็นจุดตั้งต้นพยางค์ได้ เช่น สระบน/ล่าง/ข้าง วรรณยุกต์ ทัณฑฆาต ไม้ไต่คู้ นิคหิต

กฎนี้ จะชี้ชัดเฉพาะกรณีที่ระบุได้ว่าไม่สามารถเป็นจุดตั้งต้นพยางค์ได้แน่ ๆ เท่านั้น ถ้า มีโอกาส เป็นจุดตั้งต้นพยางค์ได้ ก็จะให้คำตอบว่าเป็นจุดตั้งต้นได้ทั้งหมด ทั้งนี้ อัลกอริทึมตัดคำจะเป็นผู้ตรวจสอบกับพจนานุกรมอีกที ว่าจริง ๆ แล้วเป็นหรือเปล่า

ด้วยการตรวจสอบนี้ libthai รุ่นล่าสุดใน SVN จะตัดกรณีตัวอย่างข้างต้นเป็นอย่างนี้แทน:

> เชล็งบดลนที
เชล็ง|บด|ลน|ที

ซึ่งน่าจะให้ขอบเขตของ unknown word ในกรณีทั่วไปได้สมเหตุสมผลกว่า

นอกจากเรื่องนี้แล้ว อีกทางหนึ่งก็ทยอยปรับพจนานุกรมอยู่เรื่อย ๆ ครับ การเพิ่มคำที่พบในชีวิตประจำวันก็จะช่วยลดจำนวน unknown word ลงได้ ทำให้ตัดคำได้ถูกต้องยิ่งขึ้น ถ้าพบ libthai ตัดคำผิดตรงไหน ก็แจ้งเข้ามาได้ทุกเมื่อนะครับ

Update (5 มิ.ย. 2552 21.32 น.): ปรับแก้กฎเกี่ยวกับไม้ไต่คู้ เมื่อมี อ อ่าง หรือ ว แหวน ตามหลัง

ป้ายกำกับ:

2 ความเห็น:

แสดงความเห็น (มีการกลั่นกรองสำหรับ blog ที่เก่ากว่า 14 วัน)

<< กลับหน้าแรก

hacker emblem