Szukam algorytmu podobieństwa ciągów, który daje lepsze wyniki na ciągach o zmiennej długości niż te, które są zwykle sugerowane (odległość levenshteina, soundex itp.).
Na przykład,
Biorąc pod uwagę ciąg A: "Robert",
Następnie ciąg B: „Amy Robertson”
byłby lepszy niż
Ciąg C: „Richard”
Ponadto najlepiej, aby algorytm ten był agnostyczny językowo (działa również w językach innych niż angielski).
string-matching
ranking
similarity
fuzzy-search
marzagao
źródło
źródło
Odpowiedzi:
Simon White z Catalysoft napisał artykuł o bardzo sprytnym algorytmie porównującym sąsiadujące pary znaków, który sprawdza się naprawdę dobrze w moich celach:
http://www.catalysoft.com/articles/StrikeAMatch.html
Simon ma wersję algorytmu w języku Java, a poniżej napisałem jego wersję PL / Ruby (zaczerpniętą ze zwykłej wersji ruby wykonanej w komentarzu na forum pokrewnego przez Marka Wong-VanHarena), aby móc go używać w zapytaniach dotyczących PostgreSQL:
Działa jak marzenie!
źródło
string_similarity("vitamin B", "vitamin C") #=> 1
czy istnieje łatwy sposób zapobiegania tego typu zachowaniom?odpowiedź marzagao jest świetna. Przekonwertowałem go na C #, więc pomyślałem, że opublikuję go tutaj:
Pastebin Link
źródło
(2.0 * intersection) / union
- otrzymuję Double.NaN podczas porównywania dwóch pustych ciągów.Oto kolejna wersja odpowiedzi marzagao , ta napisana w Pythonie:
źródło
Oto moja implementacja w PHP sugerowanego algorytmu StrikeAMatch autorstwa Simona White'a. zalety (jak jest napisane w linku) to:
Prawdziwe odzwierciedlenie podobieństwa leksykalnego - łańcuchy z niewielkimi różnicami należy uznać za podobne. W szczególności znaczne nakładanie się podciągów powinno wskazywać na wysoki poziom podobieństwa między ciągami.
Odporność na zmiany kolejności słów - dwa ciągi zawierające te same słowa, ale w innej kolejności, należy uznać za podobne. Z drugiej strony, jeśli jeden ciąg jest tylko przypadkowym anagramem znaków zawartych w drugim, to (zwykle) należy go rozpoznać jako niepodobne.
Niezależność językowa - algorytm powinien działać nie tylko w języku angielskim, ale w wielu różnych językach.
źródło
Krótsza wersja odpowiedzi Johna Rutledge'a :
źródło
intersection
zmienna jest marnotrawstwem linii.Ta dyskusja była bardzo pomocna, dzięki. Przekonwertowałem algorytm na VBA do użytku z Excelem i napisałem kilka wersji funkcji arkusza, jedna do prostego porównania pary ciągów, a druga do porównania jednego ciągu z zakresem / tablicą ciągów. Wersja strSimLookup zwraca ostatnie najlepsze dopasowanie jako ciąg znaków, indeks tablicy lub metrykę podobieństwa.
Ta implementacja daje te same wyniki, co przykład Amazona na stronie internetowej Simona White'a z kilkoma drobnymi wyjątkami dotyczącymi meczów o niskiej punktacji; Nie jestem pewien, gdzie wkrada się różnica, może to być funkcja Split VBA, ale nie badałem, ponieważ działa dobrze do moich celów.
źródło
Przepraszam, odpowiedź nie została wymyślona przez autora. Jest to dobrze znany algorytm, który po raz pierwszy pojawił się w firmie Digital Equipment Corporation i jest często nazywany gontem.
http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-TN-1997-015.pdf
źródło
Przetłumaczyłem algorytm Simona White'a na PL / pgSQL. To mój wkład.
źródło
Wskaźniki podobieństwa ciągów zawierają przegląd wielu różnych wskaźników używanych do porównywania ciągów ( przegląd zawiera również Wikipedia ). Wiele z tych metryk jest zaimplementowanych w bibliotece simmetrics .
Jeszcze innym przykładem metryki nieuwzględnionej w tym przeglądzie jest na przykład odległość kompresji (próba przybliżenia złożoności Kołmogorowa ), której można użyć do tekstów nieco dłuższych niż ten, który przedstawiłeś.
Możesz również rozważyć przyjrzenie się znacznie szerszemu tematowi przetwarzania języka naturalnego . Te pakiety R mogą szybko rozpocząć pracę (lub przynajmniej dać kilka pomysłów).
I ostatnia edycja - poszukaj innych pytań na ten temat w SO, jest sporo powiązanych.
źródło
Szybsza wersja algorytmu PHP:
Dla danych, które miałem (około 2300 porównań), miałem czas działania 0,58 sekundy z roztworem Igal Alkon w porównaniu z 0,35 sekundy z moim.
źródło
Wersja w pięknej Scali:
źródło
Oto wersja R:
źródło
Publikowanie odpowiedzi marzagao w C99, zainspirowane tymi algorytmami
Niektóre testy oparte na oryginalnym artykule :
źródło
Opierając się na niesamowitej wersji C # Michaela La Voie, zgodnie z prośbą o uczynienie z niej metody rozszerzającej, oto co wymyśliłem. Główną zaletą zrobienia tego w ten sposób jest to, że możesz sortować listę ogólną według dopasowania procentowego. Załóżmy na przykład, że w obiekcie znajduje się pole tekstowe o nazwie „Miasto”. Użytkownik wyszukuje „Chester”, a Ty chcesz zwrócić wyniki w malejącej kolejności. Na przykład chcesz, aby dosłowne dopasowania Chester były wyświetlane przed Rochester. Aby to zrobić, dodaj dwie nowe właściwości do swojego obiektu:
Następnie dla każdego obiektu ustaw SearchText na to, czego szukał użytkownik. Następnie możesz je łatwo posortować za pomocą czegoś takiego:
Oto niewielka modyfikacja, aby uczynić go metodą rozszerzenia:
źródło
Moja implementacja JavaScript pobiera ciąg lub tablicę ciągów i opcjonalną podłogę (domyślna podłoga to 0,5). Jeśli przekażesz mu łańcuch, zwróci wartość true lub false w zależności od tego, czy wynik podobieństwa ciągu jest większy lub równy podłodze. Jeśli przekażesz mu tablicę ciągów, zwróci tablicę tych ciągów, których wynik podobieństwa jest większy lub równy podłodze, posortowanych według wyniku.
Przykłady:
Oto ona:
źródło
for(var j = 0; j < pairs1.length; j++){
powinno byćfor(var j = 0; j < pairs2.length; j++){
Algorytm współczynnika Dice (odpowiedź Simona White'a / marzagao) jest zaimplementowany w Ruby w metodzie pair_distance_similar w amatch gem
https://github.com/flori/amatch
Ten klejnot zawiera również implementacje szeregu algorytmów przybliżonego dopasowywania i porównywania ciągów: odległość edycji Levenshteina, odległość edycji sprzedawcy, odległość Hamminga, najdłuższa wspólna długość podciągu, najdłuższa wspólna długość podciągu, metryka odległości pary, metryka Jaro-Winklera .
źródło
Wersja Haskell - nie krępuj się sugerować zmian, ponieważ nie zrobiłem zbyt wiele Haskell.
źródło
Clojure:
źródło
A co z odległością Levenshteina podzieloną przez długość pierwszej struny (lub alternatywnie podzieloną przez moją min / max / średnią długość obu strun)? Jak na razie to działa.
źródło
Hej ludzie, wypróbowałem to w javascript, ale jestem w tym nowy, ktoś zna szybsze sposoby na zrobienie tego?
źródło
x
iy
, i nie powinieneś przechodzić przez pętle za pomocąfor..in..
pętli (for(..;..;..)
zamiast tego użyj ).Oto kolejna wersja podobieństwa oparta na indeksie Sørensena – Dice (odpowiedź marzagao), ta napisana w C ++ 11:
źródło
Szukałem czystej rubinowej implementacji algorytmu, na który wskazuje odpowiedź @ marzagao. Niestety link wskazany przez @marzagao jest uszkodzony. W odpowiedzi @ s01ipsist wskazał zestaw ruby gem, w którym implementacja nie jest w czystym rubinie. Poszukałem więc trochę i znalazłem gem fuzzy_match, który ma czystą implementację ruby (choć ten klejnot używa
amatch
) tutaj . Mam nadzieję, że to pomoże komuś takiemu jak ja.źródło