Hướng dẫn python fast fuzzy matching - kết hợp mờ nhanh python

Tôi hiện đang sử dụng phương thức phương thức GET_CLOSE_MATCHES từ Difflib đến Iterate thông qua danh sách 15.000 chuỗi để có được trận đấu gần nhất với danh sách khác khoảng 15.000 chuỗi:

a=['blah','pie','apple'...]
b=['jimbo','zomg','pie'...]

for value in a:
    difflib.get_close_matches(value,b,n=1,cutoff=.85)

Phải mất 0,58 giây cho mỗi giá trị, điều đó có nghĩa là sẽ mất 8.714 giây hoặc 145 phút để hoàn thành vòng lặp. Có một thư viện/phương thức khác có thể nhanh hơn hoặc là cách để cải thiện tốc độ cho phương pháp này? Tôi đã thử chuyển đổi cả hai mảng thành chữ thường, nhưng nó chỉ dẫn đến tăng tốc độ nhẹ.

Hướng dẫn python fast fuzzy matching - kết hợp mờ nhanh python

Chuỗi mờ khớp trong Python

Chúng tôi đã thực hiện nhiệm vụ của mình để lấy vé sự kiện từ mọi góc của internet, cho bạn thấy tất cả trên cùng một màn hình để bạn có thể so sánh chúng và đến trò chơi/buổi hòa nhạc/chương trình/chương trình của bạn càng nhanh càng tốt.

Tất nhiên, một vấn đề lớn với hầu hết các góc của Internet là & nbsp; ghi nhãn. Một trong những vấn đề bực bội nhất quán của chúng tôi là cố gắng tìm ra liệu hai danh sách vé có phải là sự kiện thực tế tương tự hay không (nghĩa là không tranh thủ sự giúp đỡ của quân đội thực tập viên của chúng tôi).

Để chọn một ví dụ hoàn toàn một cách ngẫu nhiên, Cirque du Soleil có một chương trình chạy ở New York có tên là Zarkana. Khi chúng tôi lùng sục trên web để tìm vé để bán, chủ yếu là những vé đó được xác định bởi một tiêu đề, ngày, thời gian và địa điểm. Dưới đây là một lựa chọn của một số tiêu đề mà chúng tôi đã thực sự thấy cho chương trình này:

Cirque du Soleil Zarkana New York
Cirque du Soleil-Zarkana
Cirque du Soleil: Zarkanna
Cirque Du Soleil - Zarkana Tickets 8/31/11 (New York)
Cirque Du Soleil - ZARKANA (Matinee) (New York)
Cirque du Soleil - New York

Theo như Internet, điều này không quá tệ. Một thực tập sinh bình thường sẽ không gặp khó khăn gì khi chọn rằng tất cả các danh sách này là cho cùng một chương trình. Và một thực tập sinh bình thường sẽ không gặp khó khăn gì khi chọn rằng các danh sách đó là & nbsp; khác nhau & nbsp; so với những người dưới đây:different than the ones below:

Cirque du Soleil Kooza New York
Cirque du Soleil: KA
Cirque du Soleil Zarkana Las Vegas

Nhưng như bạn có thể tưởng tượng, chúng tôi có quá nhiều sự kiện (hơn 60.000) để có thể ném thực tập sinh vào vấn đề. Vì vậy, chúng tôi muốn thực hiện theo chương trình này, nhưng chúng tôi cũng muốn kết quả lập trình của chúng tôi vượt qua bài kiểm tra thực tế trên mạng và có ý nghĩa với người dùng bình thường.

Để đạt được điều này, chúng tôi đã xây dựng một thư viện các thói quen phù hợp chuỗi fuzzy, để giúp chúng tôi cùng. Và tin tốt! Chúng tôi mở nguồn cung cấp nó. Thư viện được gọi là Fuzzywuzzy, mã là Python thuần túy và nó chỉ phụ thuộc vào (thư viện Python (xuất sắc) & nbsp; Difflib & nbsp; Python. Nó có sẵn trên GitHub ngay bây giờ.difflib python library. It is available on Github right now.

Chuỗi tương tự

Cách đơn giản nhất để so sánh hai chuỗi là với phép đo khoảng cách chỉnh sửa. Ví dụ, hai chuỗi sau đây khá giống nhau:

NEW YORK METS
NEW YORK MEATS

Trông giống như một lỗi chính tả vô hại. Chúng ta có thể định lượng nó không? Sử dụng Python sườn Difflib, điều đó khá dễ dàng

from difflib import SequenceMatcher
m = SequenceMatcher(None, "NEW YORK METS", "NEW YORK MEATS")
m.ratio() ⇒ 0.962962962963

Vì vậy, có vẻ như hai chuỗi này khoảng 96% giống nhau. Khá tốt! Chúng tôi sử dụng mẫu này thường xuyên, chúng tôi đã viết một phương pháp trợ giúp để gói gọn nó

fuzz.ratio("NEW YORK METS", "NEW YORK MEATS") ⇒ 96

Tuyệt vời, vì vậy chúng tôi đã hoàn thành! Không hẳn. Nó chỉ ra rằng phép đo gần nhau của chuỗi tiêu chuẩn, hoạt động tốt cho các chuỗi rất ngắn (chẳng hạn như một từ duy nhất) và các chuỗi rất dài (như một cuốn sách đầy đủ), nhưng không quá nhiều & nbsp; cho nhãn 3-10 từ. Cách tiếp cận ngây thơ quá nhạy cảm với những khác biệt nhỏ trong trật tự từ, thiếu hoặc thêm từ và các vấn đề khác như vậy.

Sự tương đồng chuỗi một phần

Ở đây, một minh họa tốt:

fuzz.ratio("YANKEES", "NEW YORK YANKEES") ⇒ 60
fuzz.ratio("NEW YORK METS", "NEW YORK YANKEES") ⇒ 75

Điều này không vượt qua bài kiểm tra thực tập. Hai chuỗi đầu tiên rõ ràng đề cập đến cùng một đội, nhưng hai chuỗi rõ ràng đang đề cập đến các chuỗi khác nhau. Tuy nhiên, điểm số của trận đấu Bad Bad cao hơn so với một bên phải.

Chất nền không nhất quán là một vấn đề phổ biến đối với chúng tôi. Để hiểu được nó, chúng tôi sử dụng một heuristic mà chúng tôi gọi là một phần tốt nhất khi hai chuỗi có độ dài khác nhau đáng chú ý (chẳng hạn như trường hợp trên). Nếu chuỗi ngắn hơn có độ dài m và chuỗi dài hơn là độ dài n, về cơ bản chúng tôi sẽ quan tâm đến điểm số của chuỗi con độ dài phù hợp nhất.

Trong trường hợp này, chúng tôi đã xem xét các kết hợp sau đây

fuzz.ratio("YANKEES", "NEW YOR") ⇒ 14
fuzz.ratio("YANKEES", "EW YORK") ⇒ 28
fuzz.ratio("YANKEES", "W YORK ") ⇒ 28
fuzz.ratio("YANKEES", " YORK Y") ⇒ 28
...
fuzz.ratio("YANKEES", "YANKEES") ⇒ 100

và kết luận rằng cái cuối cùng rõ ràng là tốt nhất. Nó chỉ ra rằng, Yan Yankees, và New York Yankees, là một trận đấu hoàn hảo, chuỗi ngắn hơn là một chuỗi con dài hơn. Chúng tôi cũng có một chức năng trợ giúp cho việc này (và nó hiệu quả hơn nhiều so với thuật toán đơn giản hóa mà tôi vừa đặt ra)

fuzz.partial_ratio("YANKEES", "NEW YORK YANKEES") ⇒ 100
fuzz.partial_ratio("NEW YORK METS", "NEW YORK YANKEES") ⇒ 69

Tốt hơn rồi đấy.

Không theo thứ tự

Subrings aren vấn đề duy nhất của chúng tôi. Chúng tôi cũng phải đối phó với sự khác biệt trong xây dựng chuỗi. Dưới đây là một mô hình cực kỳ phổ biến, trong đó một người bán xây dựng các chuỗi là VS VS và một chuỗi cấu trúc khác là

fuzz.ratio("New York Mets vs Atlanta Braves", "Atlanta Braves vs New York Mets") ⇒ 45
fuzz.partial_ratio("New York Mets vs Atlanta Braves", "Atlanta Braves vs New York Mets") ⇒ 45

Một lần nữa, những điểm số thấp này don don vượt qua bài kiểm tra thực tập. Nếu các danh sách này là trong cùng một ngày, họ chắc chắn sẽ đề cập đến cùng một trận bóng chày. Chúng tôi cần một cách để kiểm soát xây dựng chuỗi.

Để giải quyết vấn đề này, chúng tôi đã phát triển hai heuristic khác nhau: cách tiếp cận của Token Token_sort và cách tiếp cận của Token Token_set. Tôi sẽ giải thích cả hai.

Sắp xếp mã thông báo

Cách tiếp cận sắp xếp mã thông báo liên quan đến việc mã hóa chuỗi trong câu hỏi, sắp xếp các mã thông báo theo thứ tự bảng chữ cái và sau đó tham gia chúng trở lại vào một chuỗi. Ví dụ:

Cirque du Soleil Zarkana New York
Cirque du Soleil-Zarkana
Cirque du Soleil: Zarkanna
Cirque Du Soleil - Zarkana Tickets 8/31/11 (New York)
Cirque Du Soleil - ZARKANA (Matinee) (New York)
Cirque du Soleil - New York
0

Sau đó, chúng tôi so sánh các chuỗi được chuyển đổi với tỷ lệ đơn giản (). Điều đó giải quyết vấn đề đơn đặt hàng của chúng tôi, vì chức năng trợ giúp của chúng tôi dưới đây chỉ ra:

Cirque du Soleil Zarkana New York
Cirque du Soleil-Zarkana
Cirque du Soleil: Zarkanna
Cirque Du Soleil - Zarkana Tickets 8/31/11 (New York)
Cirque Du Soleil - ZARKANA (Matinee) (New York)
Cirque du Soleil - New York
1

Bộ mã thông báo

Cách tiếp cận bộ mã thông báo là tương tự, nhưng linh hoạt hơn một chút. Ở đây, chúng tôi mã hóa cả hai chuỗi, nhưng thay vì sắp xếp và so sánh ngay lập tức, chúng tôi chia các mã thông báo thành hai nhóm: giao lộ và phần còn lại. Chúng tôi sử dụng các bộ đó để xây dựng một chuỗi so sánh.

Đây là một ví dụ minh họa:

Cirque du Soleil Zarkana New York
Cirque du Soleil-Zarkana
Cirque du Soleil: Zarkanna
Cirque Du Soleil - Zarkana Tickets 8/31/11 (New York)
Cirque Du Soleil - ZARKANA (Matinee) (New York)
Cirque du Soleil - New York
2

Sử dụng phương thức sắp xếp mã thông báo là hữu ích, bởi vì chuỗi thứ hai (dài hơn) có quá nhiều mã thông báo bổ sung được xen kẽ với loại. Chúng tôi cuối cùng đã so sánh:

Cirque du Soleil Zarkana New York
Cirque du Soleil-Zarkana
Cirque du Soleil: Zarkanna
Cirque Du Soleil - Zarkana Tickets 8/31/11 (New York)
Cirque Du Soleil - ZARKANA (Matinee) (New York)
Cirque du Soleil - New York
3

Không hữu ích lắm. Thay vào đó, phương pháp SET cho phép chúng ta phát hiện ra rằng các thiên thần của người Hồi giáo và người Mariners là phổ biến đối với cả hai chuỗi và tách các chuỗi ra (giao điểm tập hợp). Bây giờ chúng tôi xây dựng và so sánh các chuỗi của biểu mẫu sau

Cirque du Soleil Zarkana New York
Cirque du Soleil-Zarkana
Cirque du Soleil: Zarkanna
Cirque Du Soleil - Zarkana Tickets 8/31/11 (New York)
Cirque Du Soleil - ZARKANA (Matinee) (New York)
Cirque du Soleil - New York
4

Và sau đó so sánh từng cặp.

Trực giác ở đây là bởi vì thành phần Sắp xếp_intersection luôn giống hệt nhau, điểm số tăng khi (a) chiếm tỷ lệ lớn hơn của chuỗi đầy đủ và (b) chuỗi còn lại giống nhau hơn. Trong ví dụ của chúng tôi

Cirque du Soleil Zarkana New York
Cirque du Soleil-Zarkana
Cirque du Soleil: Zarkanna
Cirque Du Soleil - Zarkana Tickets 8/31/11 (New York)
Cirque Du Soleil - ZARKANA (Matinee) (New York)
Cirque du Soleil - New York
5

Có nhiều cách khác để kết hợp các giá trị này. Ví dụ, chúng tôi có thể đã mất trung bình, hoặc một phút. Nhưng theo kinh nghiệm của chúng tôi, một cách tiếp cận trận đấu tốt nhất có thể của người Viking dường như cung cấp kết quả thực tế tốt nhất. Và tất nhiên, bằng cách sử dụng một bộ có nghĩa là các mã thông báo trùng lặp bị mất trong quá trình chuyển đổi.

Cirque du Soleil Zarkana New York
Cirque du Soleil-Zarkana
Cirque du Soleil: Zarkanna
Cirque Du Soleil - Zarkana Tickets 8/31/11 (New York)
Cirque Du Soleil - ZARKANA (Matinee) (New York)
Cirque du Soleil - New York
6

Sự kết luận

Vì vậy, bạn có nó. Một trong những bí mật của Seatgeek tiết lộ. Có nhiều mẩu tin hơn trong thư viện (có sẵn trên GitHub), bao gồm các phương thức tiện lợi để kết hợp các giá trị thành một danh sách các tùy chọn. Đi săn vui nhé.