2016-06-22 26 views
5

Tak więc, patrzę na wdrażanie dopasowywania logiki Fuzzy w mojej firmie i problemy z uzyskaniem dobrych wyników. Na początek próbuję dopasować nazwy firm do tych na liście dostarczonej przez inne firmy.
Moja pierwsza próba polegała na użyciu soundex, ale wygląda na to, że soundex porównuje tylko kilka pierwszych dźwięków w nazwie firmy, więc dłuższe nazwy firm były dla siebie zbyt łatwo pogmatwane.
Pracuję teraz nad drugą próbą przy użyciu porównania odległości w levensteinie. Wygląda obiecująco, zwłaszcza jeśli najpierw usunę interpunkcję. Jednak nadal nie mogę znaleźć duplikatów bez zbyt wielu fałszywych alarmów.
Jednym z problemów, które mam, są firmy takie jak widgetsco vs widgets inc. Tak więc, jeśli porówna się podciągi o długości krótszej nazwy, pobieram też rzeczy takie jak BBC University i kampus Uniwersytetu CBC. Podejrzewam, że rozwiązaniem może być wynik wykorzystujący kombinację odległości i najdłuższego wspólnego podciągu.
Czy ktoś zdołał zbudować algorytm, który wykonuje takie dopasowanie z ograniczonymi fałszywymi pozytywami?Logika rozmyta pasująca do

+0

Jedyne dopasowanie, jakie kiedykolwiek miałem do wykonania, polegało na dopasowaniu podłańcucha np. BBC Uni i BBC University. Zakłada się, że początkowa część łańcucha jest taka sama wśród wszystkich duplikatów. Dla przypadków takich jak: widgets inc, najpierw rozpakowałbym skróty typu jednostki. Jeśli masz inne powiązane dane, np. Adres firmy, dyrektor generalny firmy, to również można porównać, aby uzyskać wynik prawdopodobieństwa, że ​​dwie firmy są takie same. Skoncentruję się najpierw na normalizacji danych (poprzez usunięcie puchu), zanim spróbuję to porównać. – Alex

+0

Usuwanie puchu jest zwykle dobrą praktyką, niezależnie od używanego algorytmu. – Yobik

+0

Będę pracował nad normalizacją danych. W przypadkach takich jak "Smith & Wesson" dopasowanych do "Smith and Wesson", zamieniłbym wszystkie "&" na "i" dla celów pojedynku. Próbowałbym również rozebrać typy encji i ich skróty (np. Co.) I sprawdzić, czy to daje fałszywe alarmy. Jeśli dane mają bardziej złożone konstrukty, np. "CompanyA trading jako CompanyB", następnie trzeba je przeanalizować. IMO, dopasowywanie dobrze uporządkowanych danych, takich jak nazwy firm, jest niewłaściwym narzędziem do tego zadania. – Alex

Odpowiedz

0

Chcesz użyć czegoś takiego jak Odległość Levenshteina lub inny algorytm porównywania ciągów znaków. Możesz rzucić okiem na ten projekt na Codeplex.

http://fuzzystring.codeplex.com/

+0

Podoba mi się odległość Levenshteina, ale problemem jest to, że nie jest "rozmyta". Odległość między "CBC University" i "CBC Univer" wynosi 4, mimo że prawdopodobnie to samo miejsce.Ten post SO ma ładne "rozmyte" Levenshtein [SQL Server Fuzzy Search z Procentem dopasowania] (http://stackoverflow.com/questions/26259117/sql-server-fuzzy-search-with-percentage-match) – user918967

0

Używasz dostęp? Jeśli tak, rozważ znak "*" bez cudzysłowów. Jeśli używasz programu SQL Server, użyj znaku "%". Jednak to naprawdę nie jest logika rozmyta, to tak naprawdę operator Like. Jeśli naprawdę potrzebujesz logiki rozmytej, wyeksportuj zestaw danych do Excela i załaduj AddIn z poniższego adresu URL.

https://www.microsoft.com/en-us/download/details.aspx?id=15011

Czytaj uważnie instrukcje. To na pewno działa i działa świetnie, ale musisz postępować zgodnie z instrukcjami i nie jest to całkowicie intuicyjne. Za pierwszym razem, kiedy go wypróbowałem, nie postępowałem zgodnie z instrukcjami i zmarnowałem dużo czasu, próbując zmusić go do działania. W końcu zorientowałem się, i działało świetnie !!

0

Mieliśmy dobre wyniki w dopasowywaniu nazw i adresów przy użyciu funkcji Metaphone stworzonej przez Lawrence Philipsa. Działa to podobnie jak Soundex, ale tworzy wzór dźwiękowy/spółgłoskowy dla całej wartości. Może się okazać, że jest to przydatne w połączeniu z innymi technikami, szczególnie jeśli możesz usunąć trochę puchu jak "co". i "inc." jak wspomniano w innych komentarzach:

create function [dbo].[Metaphone](@str as nvarchar(70), @KeepNumeric as bit = 0) 
returns nvarchar(25) 
    /* 
    Metaphone Algorithm 

    Created by Lawrence Philips. 
    Metaphone presented in article in "Computer Language" December 1990 issue. 

       *********** BEGIN METAPHONE RULES *********** 
    Lawrence Philips' RULES follow: 
    The 16 consonant sounds: 
               |--- ZERO represents "th" 
               | 
      B X S K J T F H L M N P R 0 W Y 
    Drop vowels 

    Exceptions: 
    Beginning of word: "ae-", "gn", "kn-", "pn-", "wr-" ----> drop first letter 
    Beginning of word: "wh-"        ----> change to "w" 
    Beginning of word: "x"        ----> change to "s" 
    Beginning of word: vowel or "H" + vowel    ----> Keep it 

    Transformations: 
    B ----> B  unless at the end of word after "m", as in "dumb", "McComb" 
    C ----> X  (sh) if "-cia-" or "-ch-" 
      S  if "-ci-", "-ce-", or "-cy-" 
        SILENT if "-sci-", "-sce-", or "-scy-" 
      K  otherwise 
      K  "-sch-" 
    D ----> J  if in "-dge-", "-dgy-", or "-dgi-" 
      T  otherwise 
    F ----> F 
    G ---->   SILENT if "-gh-" and not at end or before a vowel 
           "-gn" or "-gned" 
           "-dge-" etc., as in above rule 
      J  if "gi", "ge", "gy" if not double "gg" 
      K  otherwise 
    H ---->   SILENT if after vowel and no vowel follows 
          or "-ch-", "-sh-", "-ph-", "-th-", "-gh-" 
      H  otherwise 
    J ----> J 
    K ---->   SILENT if after "c" 
      K  otherwise 
    L ----> L 
    M ----> M 
    N ----> N 
    P ----> F  if before "h" 
      P  otherwise 
    Q ----> K 
    R ----> R 
    S ----> X  (sh) if "sh" or "-sio-" or "-sia-" 
      S  otherwise 
    T ----> X  (sh) if "-tia-" or "-tio-" 
      0  (th) if "th" 
        SILENT if "-tch-" 
      T  otherwise 
    V ----> F 
    W ---->   SILENT if not followed by a vowel 
      W  if followed by a vowel 
    X ----> KS 
    Y ---->   SILENT if not followed by a vowel 
      Y  if followed by a vowel 
    Z ----> S 
    */ 


as 
begin 
declare @Result varchar(25) 
     ,@str3 char(3) 
     ,@str2 char(2) 
     ,@str1 char(1) 
     ,@strp char(1) 
     ,@strLen tinyint 
     ,@cnt tinyint 

set @strLen = len(@str) 
set @cnt = 0 
set @Result = '' 

-- Preserve first 5 numeric values when required 
if @KeepNumeric = 1 
    begin 
     set @Result = case when isnumeric(substring(@str,1,1)) = 1 
          then case when isnumeric(substring(@str,2,1)) = 1 
            then case when isnumeric(substring(@str,3,1)) = 1 
              then case when isnumeric(substring(@str,4,1)) = 1 
                then case when isnumeric(substring(@str,5,1)) = 1 
                   then left(@str,5) 
                   else left(@str,4) 
                   end 
                else left(@str,3) 
                end 
              else left(@str,2) 
              end 
            else left(@str,1) 
            end 
          else '' 
          end 

     set @str = right(@str,len(@str)-len(@Result)) 
    end 

--Process beginning exceptions 
set @str2 = left(@str,2) 

if @str2 = 'wh' 
    begin 
     set @str = 'w' + right(@str , @strLen - 2) 
     set @strLen = @strLen - 1 
    end 
else 
    if @str2 in('ae', 'gn', 'kn', 'pn', 'wr') 
     begin 
      set @str = right(@str , @strLen - 1) 
      set @strLen = @strLen - 1 
     end 



set @str1 = left(@str,1) 

if @str1 = 'x' 
    set @str = 's' + right(@str , @strLen - 1) 
else 
    if @str1 in ('a','e','i','o','u') 
     begin 
      set @str = right(@str, @strLen - 1) 
      set @strLen = @strLen - 1 
      set @Result = @Result + @str1 
     end 

while @cnt <= @strLen 
    begin 
     set @cnt = @cnt + 1 
     set @str1 = substring(@str,@cnt,1) 

     set @strp = case when @cnt <> 0 
         then substring(@str,(@cnt-1),1) 
         else ' ' 
         end 

     -- Check if the current character is the same as the previous character. 
     -- If we are keeping numbers, only compare non-numeric characters. 
     if case when @KeepNumeric = 1 and @strp = @str1 and isnumeric(@str1) = 0 then 1 
       when @KeepNumeric = 0 and @strp = @str1 then 1 
       else 0 
       end = 1 
      continue -- Skip this loop 

     set @str2 = substring(@str,@cnt,2) 

     set @Result = case when @KeepNumeric = 1 and isnumeric(@str1) = 1 
           then @Result + @str1 
          when @str1 in('f','j','l','m','n','r') 
           then @Result + @str1 
          when @str1 = 'q' 
           then @Result + 'k' 
          when @str1 = 'v' 
           then @Result + 'f' 
          when @str1 = 'x' 
           then @Result + 'ks' 
          when @str1 = 'z' 
           then @Result + 's' 
          when @str1 = 'b' 
           then case when @cnt = @strLen 
              then case when substring(@str,(@cnt - 1),1) <> 'm' 
                then @Result + 'b' 
               else @Result 
               end 
             else @Result + 'b' 
             end 
          when @str1 = 'c' 
           then case when @str2 = 'ch' or substring(@str,@cnt,3) = 'cia' 
              then @Result + 'x' 
              else case when @str2 in('ci','ce','cy') and @strp <> 's' 
                then @Result + 's' 
                else @Result + 'k' 
                end 
              end 
          when @str1 = 'd' 
           then case when substring(@str,@cnt,3) in ('dge','dgy','dgi') 
              then @Result + 'j' 
              else @Result + 't' 
              end 
          when @str1 = 'g' 
           then case when substring(@str,(@cnt - 1),3) not in ('dge','dgy','dgi','dha','dhe','dhi','dho','dhu') 
              then case when @str2 in('gi', 'ge','gy') 
                then @Result + 'j' 
                else case when @str2 <> 'gn' or (@str2 <> 'gh' and @cnt+1 <> @strLen) 
                   then @Result + 'k' 
                   else @Result 
                   end 
                end 
              else @Result 
              end 
          when @str1 = 'h' 
           then case when @strp not in ('a','e','i','o','u') and @str2 not in ('ha','he','hi','ho','hu') 
              then case when @strp not in ('c','s','p','t','g') 
                 then @Result + 'h' 
                 else @Result 
                 end 
              else @Result 
              end 
          when @str1 = 'k' 
           then case when @strp <> 'c' 
              then @Result + 'k' 
              else @Result 
              end 
          when @str1 = 'p' 
           then case when @str2 = 'ph' 
              then @Result + 'f' 
              else @Result + 'p' 
              end 
          when @str1 = 's' 
           then case when substring(@str,@cnt,3) in ('sia','sio') or @str2 = 'sh' 
              then @Result + 'x' 
              else @Result + 's' 
              end 
          when @str1 = 't' 
           then case when substring(@str,@cnt,3) in ('tia','tio') 
              then @Result + 'x' 
              else case when @str2 = 'th' 
                 then @Result + '0' 
                 else case when substring(@str,@cnt,3) <> 'tch' 
                    then @Result + 't' 
                    else @Result 
                    end 
                 end 
              end 
          when @str1 = 'w' 
           then case when @str2 not in('wa','we','wi','wo','wu') 
              then @Result + 'w' 
              else @Result 
              end 
          when @str1 = 'y' 
           then case when @str2 not in('ya','ye','yi','yo','yu') 
              then @Result + 'y' 
              else @Result 
              end 
          else @Result 
          end 
    end 

return @Result 

end