อัลกอริทึมใดให้คำแนะนำในตัวตรวจสอบการสะกด


114

โดยทั่วไปจะใช้อัลกอริทึมใดในการใช้งานตัวตรวจสอบการสะกดที่มาพร้อมกับคำแนะนำ

ตอนแรกฉันคิดว่ามันสมเหตุสมผลแล้วที่จะตรวจสอบคำใหม่แต่ละคำที่พิมพ์ (หากไม่พบในพจนานุกรม) เทียบกับระยะทาง Levenshteinจากทุกคำในพจนานุกรมและส่งคืนผลลัพธ์อันดับต้น ๆ อย่างไรก็ตามดูเหมือนว่าจะไม่มีประสิทธิภาพอย่างมากเนื่องจากต้องประเมินพจนานุกรมซ้ำทั้งเล่ม

โดยทั่วไปแล้วจะทำอย่างไร?

คำตอบ:


203

มีบทความที่ดีโดย Peter Norvigเกี่ยวกับวิธีใช้ตัวแก้ไขการสะกดคำ โดยพื้นฐานแล้วเป็นวิธีการบังคับที่ดุร้ายโดยพยายามใช้สตริงผู้สมัครโดยมีระยะการแก้ไขที่กำหนด ( นี่คือเคล็ดลับบางประการในการปรับปรุงประสิทธิภาพตัวแก้ไขการสะกดโดยใช้Bloom Filterและการแฮชผู้สมัครที่เร็วขึ้น )

ข้อกำหนดสำหรับตัวตรวจสอบการสะกดจะอ่อนกว่า คุณต้องรู้ว่าคำนั้นไม่มีอยู่ในพจนานุกรม คุณสามารถใช้Bloom Filterเพื่อสร้างตัวตรวจสอบการสะกดซึ่งใช้หน่วยความจำน้อยลง เวอร์ชันโบราณจะถูกถอดรหัสในProgramming Pearlsโดย Jon Bentley โดยใช้ 64kb สำหรับพจนานุกรมภาษาอังกฤษ

BK-ต้นไม้เป็นวิธีทางเลือก บทความที่ดีคือที่นี่

ระยะทาง Levenshstein ไม่ใช่ระยะแก้ไขที่ถูกต้องสำหรับเครื่องตรวจตัวสะกด มันรู้แค่การแทรกการลบและการเปลี่ยนตัว การเปลี่ยนตำแหน่งขาดหายไปและสร้าง 2 สำหรับการย้าย 1 อักขระ (เป็นการลบ 1 ครั้งและการแทรก 1 ครั้ง) ระยะ Damerau – Levenshteinคือระยะแก้ไขที่เหมาะสม


2
+1 สำหรับข้อมูลอ้างอิง BK-Tree ที่ไม่เป็นที่รู้จัก นั่นเป็นวิธีที่ บริษัท ต่างๆเช่น Google ซึ่งทำงานกับปริมาณข้อมูล Real-World [TM] กำลังดำเนินการอยู่
NoozNooz42

2
มีคำอธิบายที่ดีมากของ BK-ต้นไม้เป็นที่นี่
Ian Boyd

17

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

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

ตัวอย่างเช่นความผิดพลาดที่พบบ่อยคือการใช้สระผิดเช่นที่แน่นอนแทนแน่นอน ดังนั้นคุณจึงออกแบบฟังก์ชันแฮชที่ถือว่าสระทั้งหมดเป็นตัวอักษรเดียวกัน วิธีง่ายๆในการทำเช่นนั้นคือขั้นแรก "ทำให้เป็นปกติ" ของคำที่ป้อนจากนั้นจึงใส่ผลลัพธ์ที่เป็นมาตรฐานผ่านฟังก์ชันแฮชปกติ ในตัวอย่างนี้ฟังก์ชั่น normalizing อาจลดลงสระทั้งหมดเพื่อให้กลายเป็นdefinite dfntจากนั้นคำว่า "normalized" จะถูกแฮชด้วยฟังก์ชันแฮชทั่วไป

แทรกคำศัพท์ในพจนานุกรมทั้งหมดของคุณลงในดัชนีเสริม (ตารางแฮช) โดยใช้ฟังก์ชันแฮชพิเศษนี้ ที่เก็บข้อมูลในตารางนี้จะมีรายการการชนกันที่ยาวเนื่องจากฟังก์ชันแฮช "ไม่ดี" แต่รายการการชนกันเหล่านั้นเป็นคำแนะนำที่คำนวณล่วงหน้าเป็นหลัก

ตอนนี้เมื่อคุณพบคำที่สะกดผิดคุณจะค้นหารายการการชนกันสำหรับที่เก็บข้อมูลที่แมปการสะกดผิดในดัชนีเสริม Ta da: คุณมีรายการแนะนำ! สิ่งที่คุณต้องทำคือจัดลำดับคำบนนั้น

ในทางปฏิบัติคุณจะต้องมีดัชนีเสริมสองสามตัวพร้อมกับฟังก์ชันแฮชอื่น ๆ เพื่อจัดการข้อผิดพลาดประเภทอื่น ๆ เช่นตัวอักษรที่ถูกเปลี่ยนตำแหน่งตัวอักษรเดี่ยว / คู่และแม้แต่ตัวอักษรที่คล้ายกับ Soundex ที่เรียบง่ายเพื่อตรวจจับการสะกดคำที่สะกดผิด ในทางปฏิบัติฉันพบว่าการออกเสียงแบบง่าย ๆ นั้นไปได้ไกลและล้าสมัยโดยพื้นฐานแล้วการออกแบบมาเพื่อค้นหาการพิมพ์ผิดเล็กน้อย

ดังนั้นตอนนี้คุณจะค้นหาการสะกดผิดในดัชนีเสริมแต่ละรายการและเชื่อมรายการการชนกันก่อนจัดอันดับ

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

ปรับปรุง : ฉันได้พบตั้งแต่คำอธิบายขั้นตอนวิธีการหนึ่งที่คล้ายกับนี้FAROO กระจายค้นหา นี่ยังคงเป็นการค้นหาแบบ จำกัด ระยะทางแก้ไข แต่ก็เร็วมากเพราะขั้นตอนการคำนวณล่วงหน้าทำงานเหมือนกับแนวคิด "ฟังก์ชันแฮชที่ไม่ถูกต้อง" ของฉัน FAROO ใช้แนวคิดที่ จำกัด เกี่ยวกับฟังก์ชันแฮชที่ไม่ถูกต้อง


ขอขอบคุณที่อ้างอิงอัลกอริทึม SymSpell ของ Faroos แม้ว่าอัลกอริทึมทั้งสองจะคำนวณการพิมพ์ผิดล่วงหน้าที่เป็นไปได้และใช้ตารางแฮชเพื่อการค้นหาอย่างรวดเร็วความแตกต่างที่สำคัญคือ SymSpell รับประกันว่าจะตรวจจับข้อผิดพลาดในการสะกดที่เป็นไปได้ทั้งหมดจนถึงระยะแก้ไขที่กำหนด (ในแง่นี้ SymSpell จะเทียบเท่ากับอัลกอริทึมของ Peter Norvig เพียง 3..6 คำสั่งขนาดเร็วขึ้น) ในขณะที่อัลกอริทึมของคุณกำลังใช้วิธีการฮิวริสติกซึ่งจะตรวจจับเฉพาะส่วนย่อยที่ จำกัด ของข้อผิดพลาดในการสะกดที่เป็นไปได้ในทางทฤษฎีทั้งหมด (ดังนั้นค่าใช้จ่ายในการคำนวณล่วงหน้าของคุณอาจต่ำกว่า)
Wolf Garbe

อัลกอริทึม SymSpell คำนวณล่วงหน้าอย่างชัดเจนและจัดเก็บการพิมพ์ผิดที่เป็นไปได้โครงร่าง "แฮชที่ไม่ถูกต้อง" ของฉันไม่ สำหรับภาษาอังกฤษการเพิ่มแฮชการออกเสียงแบบง่ายเพียงตัวเดียวซึ่งครอบคลุมพื้นดินจำนวนมาก (เช่น "terradacktle" -> "pterodactyl" ซึ่งมีระยะแก้ไข 6) จริงอยู่ถ้าคุณต้องการการค้นหาหลายภาษาอาจจะยากกว่ามาก
Adrian McCarthy

แน่นอนโดยการใช้ประโยชน์จากความรู้เชิงประจักษ์เกี่ยวกับการพิมพ์ผิด (และ จำกัด เฉพาะ) คุณจะประหยัดเวลาและพื้นที่ในการคำนวณล่วงหน้า แต่เพื่อให้ครอบคลุมข้อผิดพลาดในการสะกดที่เป็นไปได้ทั้งหมด SymSpell จำเป็นต้องคำนวณล่วงหน้าเพียงเศษเสี้ยวเล็ก ๆ คำที่เป็นตัวอักษร 5 ตัวมีข้อผิดพลาดในการสะกดที่เป็นไปได้ประมาณ 3 ล้านรายการภายในระยะการแก้ไขสูงสุดที่ 3 แต่ด้วย SymSpell คุณต้องคำนวณล่วงหน้าและจัดเก็บการลบเพียง 25 ครั้ง สิ่งนี้สำคัญสำหรับการค้นหาที่คลุมเครือ / คล้ายคลึงกันนอกเหนือจากการแก้ไขการสะกดคำโดยที่ไม่มีความรู้เชิงประจักษ์
Wolf Garbe

7

ขั้นตอนวิธี

  1. ป้อนคำที่สะกดผิดเป็นอินพุต
  2. จัดเก็บรายการคำศัพท์ภาษาอังกฤษพร้อมความถี่ไว้ในไฟล์ข้อความ
  3. แทรกคำภาษาอังกฤษที่มีทั้งหมด (เก็บไว้ในไฟล์ข้อความ) พร้อมกับความถี่ (วัดความถี่ในการใช้คำในภาษาอังกฤษ) ใน Ternary Search Tree
  4. ตอนนี้สำรวจไปตาม Ternary Search Tree -
    • สำหรับแต่ละคำที่พบใน Ternary Search Tree ให้คำนวณระยะทาง Levensthein จากคำที่สะกดผิด
    • ถ้า Levensthein Distance <= 3 ให้เก็บคำไว้ในลำดับความสำคัญ
    • หากคำสองคำมีระยะการแก้ไขเท่ากันคำที่มีความถี่สูงกว่าคือขูด พิมพ์รายการ 10 อันดับแรกจาก Priority Queue

การเพิ่มประสิทธิภาพ

  1. คุณสามารถจัดเรียงคำในแผนผังย่อยของโหนดปัจจุบันได้หากระยะการแก้ไขของสตริงย่อยของคำที่ป้อนจากคำปัจจุบันมีค่ามากกว่า 3
    คุณสามารถหาคำอธิบายและรหัสแหล่งที่มารายละเอียดเพิ่มเติมเกี่ยวกับโครงการ GitHub

อืมระยะ Levenshtein จาก 'grater' ถึง 'greater' ในกรณีนี้คงไม่เพียงพอเนื่องจาก 'grater' เป็นคำในพจนานุกรมด้วย ;-)
Tony Brasunas

1
@TonyBrasunas ใช่คุณพูดถูก แต่โปรแกรมจะส่งคืนรายการ 10 คำในกรณีที่ 'grater' เป็นอินพุตและจะแนะนำ 'grater' ด้วยระยะแก้ไขเป็น 0 และ 'มากกว่า' ด้วยระยะแก้ไข 1 ซึ่งอาจช่วยได้บ้าง ;)
amarjeetAnand

หากผู้สมัครคนหนึ่งมีระยะห่าง 2 แต่พบบ่อยมากและผู้สมัครคนอื่นมีระยะห่าง 1 แต่หายากมากคุณจะจัดอันดับทั้งสองได้อย่างไร ด้วยวิธีการข้างต้นไอเทมหายากจะชนะเสมอนี่คือผลลัพธ์ที่ถูกต้องหรือไม่?
เครื่องบินเร็ว

@speedplane ใช่ คนที่หายากจะชนะ และฉันคิดว่ามันเป็นผลลัพธ์ที่ถูกต้อง กลายเป็นสิ่งที่เราคาดหวังคือคำที่ใกล้เคียงที่สุดโดยพิจารณาจากการสะกดคำที่ป้อน หากคุณยังคงสงสัยให้คิดแบบนี้ --- สมมติว่ามีคำที่หายากซึ่งผู้ใช้สะกดถูกต้อง ตอนนี้ระยะทางคือ 0 แต่ความถี่ต่ำมาก ตอนนี้ในคำแนะนำเราควรระบุคำที่หายากนี้ (ที่มีระยะทาง 0) ที่ด้านบน (เนื่องจากระยะการแก้ไขน้อยที่สุดจะชนะ) และคำอื่น ๆ ที่มีระยะ 1-2-3 ด้านล่าง
amarjeetAnand

3

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


1

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

ระบบ Unix ใช้โปรแกรมที่เขียนโดย Mc IllRoy อีกวิธีหนึ่งคือใช้ Trie ซึ่งมีประโยชน์ในกรณีที่มีไฟล์ขนาดใหญ่

วิธีการยูนิกซ์ต้องการพื้นที่น้อยมากสำหรับพจนานุกรมขนาดใหญ่เนื่องจากใช้อัลกอริทึมแฮชกระจาย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.