แกะที่อยู่ในข้อความ

Punyapat Sessomboon
3 min readJan 5, 2021

--

ระหว่างที่ทำงานเป็น developer ผมมักจะได้รับโจทย์เกี่ยวกับเรื่องที่อยู่บ่อยๆ ทั้งจาก Chatbot, Lead Genderation website หรือ งาน Data processing ทั่วๆ ไป วันนี้เลยอยากมาแชร์วิธีการแก้ปัญหาครับ โจทย์ที่ได้รับส่วนมากจะแบ่งเป็น 2 ข้อดังนี้

ตัวอย่างการแกะที่อยู่จากข้อความ
  1. อยากรู้ว่าข้อความไหนที่ผู้ใช้พิมพ์เข้ามาแล้วเป็นที่อยู่ เช่น
    ที่อยู่ = “สมพัฒน์ แก้วพิจิตร 66/8 ม.10 ต.เขาแก้ว อ.ท่าใหม่ จ.จันทบุรี 22170”
    ที่อยู่ = “0986663434 ศิริวัฒน์ ขจรประภา มหาวิทยาลัยขอนแก่น 40002”
    ไม่ใช่ที่อยู่ = “สอบถามครับ ส่งของไปต่างจังหวัดได้ไหม”
    ไม่ใช่ที่อยู่ = “เดินทางไปจังหวัดเชียงใหม่ยังไงดีคะ”
  2. อยากได้ข้อมูลที่อยู่แยกเป็น บ้านเลขที่ ถนน ตำบล อำเภอ จังหวัด และอื่นๆ เช่น
    Input = “สมพัฒน์ แก้วพิจิตร 66/8 ต.เขาแก้ว อ.ท่าใหม่ จ.จันทบุรี 22170”
    - ชื่อ: สมพัฒน์ แก้วพิจิตร
    - ที่อยู่: 66/8
    - ตำบล: เขาแก้ว
    - อำเภอ: ท่าใหม่
    - จังหวัด: จันทบุรี
    - รหัสไปรษณีย์: 22170

ลองมาดูวิธีแก้ปัญหาทีละโจทย์กัน…

อยากรู้ว่าข้อความไหนที่ผู้ใช้พิมพ์มาเป็นที่อยู่

โจทย์ข้อนี้ดูเผินๆ อาจจะเหมือนไม่ยากเท่าไหร่ มีวิธีการง่ายๆ หลายแบบที่จะทำให้เราแยกข้อความธรรมดาจากข้อความที่เป็นที่อยู่ได้ เช่น

  1. ในประโยคมีคำว่า “ที่อยู่”
  2. ในประโยคมีคำว่า “ตำบล” หรือ “อำเภอ” หรือ “จังหวัด”
  3. ในประโยคมีคำจากข้อด้านบน และมีตัวเลขติดกัน 5 ตัวพอดี (รหัสไปรษณีย์)

วิธีการเหล่านี้พอจะรองรับที่อยู่โดยทั่วไปได้ดีพอสมควร แต่ก็จะมีจุดผิดพลาด เช่น

  1. False-Positive (บอกว่าเป็นที่อยู่ แต่จริงๆ ไม่ใช่ที่อยู่) เช่น
    - ผมเป็นคนจังหวัดขอนแก่นครับ
    - ผมจำที่อยู่ตัวเองไม่ได้
    - เขาเป็นคนชอบทำอะไรตามอำเภอใจ
  2. False-Negative (บอกว่าไม่ใช่ที่อยู่ แต่จริงๆ เป็นที่อยู่) เช่น
    - นายสมชาย สุขสวัสดิ์ ถ. ตากสิน ซอย 2 บางลำภูล่าง กทม
    - 0877170742 ในเมือง ขอนแก่น ติดต่อ 9:00–15:00

เราสามารถแก้ปัญหาเหล่านี้ได้ด้วย

  1. การเตรียม Dictionary ของตำบล อำเภอ และ จังหวัด โดยหา String contains ถ้ามี ตำบล อำเภอ จังหวัด ในข้อความก็ถือว่าเป็นที่อยู่
  2. รองรับตัวย่อ ต. อ. และ จ.

รวมๆ แล้วก็จะได้โปรแกรมประมาณนี้ครับ

จะเห็นว่าโปรแกรมก็ยังมีจุดบกพร่องหลายอย่าง เช่น

  • แยกประโยคคำถามกับที่อยู่ไม่ได้
  • ไม่รองรับกรณีที่ผู้ใช้พิมพ์ผิด
  • ไม่รองรับชื่อย่อแปลกๆ ที่คนพื้นเข้าใจ เช่น วาริน = วารินชำราบ, มหา = มหาชัย

อีกแนวทางที่เป็นที่นิยมคือ การใช้ Machine Learning เข้ามาช่วย

เนื่องจากการ classify ที่อยู่ให้ถูกต้องแม่นยำจำเป็นต้องใช้เงื่อนไขที่ซับซ้อน จนบางครั้งแค่การดู keyword จำนวนไม่มากอาจจะไม่เพียงพอ โปรแกรมต้องทำความเข้าใจความหมายของภาษาด้วย ซึ่งเป็นสิ่งที่ Technology ตอนนี้ก็ยังไปไม่ถึง แต่สิ่งที่ใกล้เคียงกับความเข้าใจภาษามากที่สุดตอนนี้ก็คงเป็น ML ตระกูล NLP โดยขั้นตอนการทำจะมีประมาณนี้ครับ

1. เตรียม dataset จำนวนมาก (ควรจะ 1000 ข้อความ++)โดย label แต่ละข้อความว่า ใช่ หรือ ไม่ใช่ ที่อยู่

2. Train model โดยเริ่มจากตัดคำ สามารถศึกษาเพิ่มเติมเรื่องตัดคำได้จาก

3. ตัดคำ (หรืออาจจะทั้งประโยคก็ได้) เปลี่ยนเป็น vector อาจจะด้วย dictionary ธรรมดา, Layer Embedded หรือ Pre-train transformer ก็ได้

4. นำ Input vector ไป train model ตัว model ก็ขึ้นอยู่กับความถนัดเลยครับ ว่าจะใช้ framework ตัวไหน หรือ model อะไร

5. Output ที่ได้โดยทั่วไปมักจะเป็นค่า propability ตั้งแต่ 0–1 ซึ่ง 0 คือไม่ใช่ที่อยู่แน่ๆ และ 1 คือเป็นที่อยู่แน่นอน

  • การใช้ Machine Learning เข้ามาช่วย จะทำให้เราสามารถรองรับเคสแปลกๆ เพิ่มขึ้นได้ เนื่องจากตัว Algorithm จะช่วยหา rules ในการพิจรณาความเป็นที่อยู่ของข้อความ input
  • แต่ก็อาจจหลงเหลือบางเคสที่อาจจะเฉพาะเจาะจงเกินไป เช่น การหาชื่อจังหวัดในข้อความ ถ้า dataset ไม่ได้มีชื่อจังหวัดเดิมๆ เยอะมากพอ Model ก็อาจจะไม่เข้าใจว่านั่นคือชื่อจังหวัด ซึ่งมีส่วนอย่างมากในการบอกว่าข้อความเป็นที่อยู่หรือไม่ กรณีของชื่ออำเภอและตำบลก็เช่นกัน
  • วิธีการที่ดีที่สุดควรจะเป็นการใช้ทั้ง Rule-based keyword + ML ครับ เพื่อให้เรา support case ต่างๆ ได้มากที่สุด แต่การสร้าง rules ก็จะต้องให้ Generalize มากพอก็จะไม่ทำให้ Overfit กับข้อมูลครับ

อยากได้ข้อมูลที่อยู่แยกเป็น บ้านเลขที่ ถนน ตำบล อำเภอ จังหวัด และอื่นๆ

โจทย์ต่อมาดูยากกว่าการบอกว่าข้อความเป็นที่อยู่หรือไม่ ก็คือเมื่อเรารู้แล้วว่าข้อความนี้เป็นที่อยู่แล้ว เราต้องการที่อยู่แต่ละส่วนในข้อความนั้นๆ คือ ชื่อ เบอร์โทร บ้านเลขที่ ตำบล อำเภอ จังหวัด และ รหัสไปรษณีย์

บางคนอาจจะสงสัยว่าทำไมเราต้อง classify ข้อความว่าเป็นที่อยู่ก่อน ทำไมเราไม่พยายามหา ตำบล อำเภอ จังหวัด รหัสไปรษณีย์ไปเลย ถ้ามีครบก็แสดงว่าเป็นที่อยู่ เหตุผลก็เพราะว่า การมีชื่อ ตำบล อำเภอ จังหวัด ไม่ได้แปลว่าข้อความนั้นๆ จะเป็นที่อยู่เสมอไป เช่น

“ที่อยู่ จำเป็นต้องประกอบด้วย ตำบล อำเภอ จังหวัด รหัสไปรษณีย์”

“ตำบลนาชุมแสง อยู่ในอำเภอภูเวียง ซึ่งเป็นอำเภอหนึ่งในจังหวัดขอนแก่น”

ซึ่งการที่ประโยคมีชื่อตำบล อำเภอ จังหวัด ก็สามารถเอามาใช้เป็น factor เพื่อคำนวนความน่าจะเป็นที่ข้อความจะเป็นที่อยู่ได้ด้วย

เราสามารถทดลองเขียนโปรแกรมแบบง่ายๆ ได้โดย

  1. ใช้ Dictionary เหมือนที่อธิบายด้านบนในการช่วยหา ตำบล อำเภอ จังหวังหวัด
  2. มองหา prefix แล้วดึงคำด้านหลังออกมา เช่น “จังหวัดขอนแก่น” prefix คือ “จังหวัด” ข้อมูลที่ต้องการคือ “ขอนแก่น” หรืออาจจะนำไปใช้กับเบอร์โทรศัพท์ด้วย เช่น “โทร. 0877170742” และอย่าลืมว่า prefix นี้ก็ต้องรองรับตัวย่อด้วย
Simple Address Extractor with Python

แต่ก็จะยังมีอีกหลายๆ เคสที่โปรแกรมนี้ไม่รองรับ เช่น

  1. การหาชื่อและเบอร์โทรในที่อยู่
  2. ถ้ามีคำที่พิมพ์ผิดจะหาใน dictionary ไม่พบ
  3. ถ้ามีการใช้ชื่อย่อของ ตำบล อำเภอ จังหวัด โดยไม่มี prefix โปรแกรมก็จะไม่พบใน dictionary
  4. ถ้าส่วนหนึ่งในชื่อตำบล เป็นชื่อจังหวัด ก็อาจจะทำให้โปรแกรมสับสน
  5. ยังมีอีกหลายเคสมากๆ ที่โปรแกรมนี้ยังไม่รองรับ ผมแนะนำเลยว่าการทำ service ประมาณนี้เราจะต้องเขียน Test ด้วยเสมอ เพราะ Test case จะช่วยให้เรารู้ว่า case ไหนที่เรารองรับแล้ว และยังไม่รองรับ และการแก้ code เพื่อให้รองรับ case ใหม่ๆ ต้องไม่ทำให้ case เดิมพัง และการมี Test case ที่ยากๆ เราสามารถนำไปใช้เป็น demo เพื่อโชว์ความสามารถของ service ได้ด้วย

ใช้ API เพื่อช่วยหาที่อยู่ในข้อความ

ตอนนี้มีผู้ให้บริการหลายๆ เจ้าที่มี API เพื่อช่วยแกะข้อมูลที่อยู่ เช่น https://demo.nlp.insightera.co.th/demo/address โดยเราเพียงแค่ส่งข้อความที่เรามี API จะ คืน % ความเป็นที่อยู่ พร้อมทั้งแยกข้อมูลที่อยู่แต่ละส่วนกลับมาให้เลย ตัวอย่างเช่น

token ฟรี = 10512F2049B72659DB9C46A7DCF60ED1

ข้อดีของการใช้ API เทียบกับเราเขียนโปรแกรมเอง เช่น

  1. รองรับการพิมพ์ผิด (ผิดบางตัวอักษร แต่ยังพอเข้าใจ)
  2. ตรวจสอบความสัมพันธ์ของที่อยู่ เช่น ตำบลอยู่ในอำเภอจริงๆ รหัสไปรษณีตรงกับ ตำบล อำเภอ จังหวัดที่ระบุไว้
  3. เติมข้อมูลที่ขาดหายไป เช่น ผู้ใช้ลืมใส่อำเภอ API ก็จะเติมให้ เพื่อให้เป็นที่อยู่ที่สมบูรณ์
  4. เจ้าของ API สามารถพัฒนา algorithm ได้โดยไม่กระทบกับผู้ใช้อย่างเรา ทำให้เรามี service ที่มีคุณภาพใช้
  5. โดยรวมแล้วความถูกต้องแม่นยำจะสูงกว่าเราพัฒนาเองมาก เพราะว่าผู้ให้บริการมักจะมีข้อมูลที่อยู่และทีมงานสำหรับพัฒนาเฉพาะ service นี้โดยเฉพาะ ทำให้ความถูกต้อง และ case ที่คลอบคลุมดีกว่ามาก

แต่การใช้ API ก็มีข้อเสียเหมือนกัน เช่น

  1. การเรียก API ทุกชนิด จะมี latency time คือเวลาที่ใช้รับส่งข้อมูลผ่าน Network ซึ่งถ้าเป็นการเรียกใช้แบบจำนวนไม่มาก ก็จะไม่ค่อยเห็นผล แต่ถ้าต้องการประมวลผลข้อความจำนวนมากๆ เช่น หลักหมื่นข้อความขึ้นไป อาจจะเห็นความแตกต่างเมื่อเทียบกับพัฒนา service เอง หรือใช้ library offline
  2. การใช้ API โดยส่วนมากจะมีค่าใช้จ่าย แล้วแต่ว่าผู้ให้บริการจะคิดราคาอย่างไร แต่อย่างกรณีของ ELI จะเป็นใช้ฟรี เมื่อใช้จำนวนไม่มาก เช่น ไม่เกิน 1000 requests ต่อชั่วโมง เป็นต้น

ELI มีหน้า demo ให้ลองเล่นด้วยนะครับ ลองเข้าไปกดเล่นดูได้

สรุป

โจทย์การ Extract ข้อมูลที่อยู่เป็นโจทย์ที่ค่อนข้างพบได้บ่อย ซึ่งมีวิธีการแก้ปัญหาได้หลายแบบ เช่น

  1. พัฒนาเอง
  2. ใช้ Library
  3. ใช้ API

ซึ่งแต่ละวิธีการก็มีข้อดีข้อเสียแตกต่างกันไป

สำหรับผม ถ้าโจทย์ยังไม่ชัดมาก ยังไม่แน่ใจว่าทำออกมาแล้วจะตอบโจทย์ลูกค้าไหม ก็ควรจะลองทำ POC (Prove of concept) ก่อน แนะนำให้ใช้ API เลยครับ เพราะว่าเร็วที่สุด ดีที่สุดในเวลาที่จำกัด ช่วงแรกๆ ตอนที่ลูกค้ายังไม่เยอะมาก ก็ใช้ฟรี ถ้าเราพิสูจน์ได้แล้วว่าสิ่งที่เรากำลังจะทำมีลูกค้าต้องการจริงๆ ตอบโจทย์ธุรกิจจริงๆ เราค่อยมาคิดว่าควรจะพัฒนา service เป็นของตัวเองหรือไม่ หรือว่าจ่ายเงินใช้ API ต่อ

--

--