Quindi, sto cercando di implementare la logica della logica Fuzzy nella mia azienda e di avere problemi a ottenere buoni risultati. Per cominciare, sto cercando di abbinare i nomi delle aziende con quelli di un elenco fornito da altre società.
Il mio primo tentativo è stato quello di utilizzare soundex, ma sembra che soundex paragoni solo i primi suoni nel nome della società, quindi i nomi di società più lunghi erano troppo facilmente confusi l'uno con l'altro.
Ora sto lavorando al mio secondo tentativo utilizzando il confronto della distanza di levenstein. Sembra promettente, soprattutto se rimuovo prima la punteggiatura. Tuttavia, sto ancora avendo difficoltà a trovare i duplicati senza troppi falsi positivi.
Uno dei problemi che ho sono aziende come widgetsco vs widgets inc. Quindi, se confronto la sottostringa della lunghezza del nome più breve, raccolgo anche cose come il campus della BBC University e della CBC University. Sospetto che una soluzione utilizzando una combinazione di distanza e la più lunga sottostringa comune possa essere la soluzione.
Qualcuno è riuscito a creare un algoritmo che esegua tale abbinamento con falsi positivi limitati?Corrispondenza logica fuzzy
risposta
Si desidera utilizzare qualcosa come Levenshtein Distance o un altro algoritmo di confronto delle stringhe. Potresti dare un'occhiata a questo progetto su Codeplex.
Mi piace Levenshtein Distance ma il problema è che non è "sfocato". La distanza tra 'CBC University' e 'CBC Univer' è 4 anche se probabilmente sono lo stesso posto.Questo post SO ha un bel "fuzzy" Levenshtein [Ricerca Fuzzy SQL Server con percentuale di corrispondenza] (http://stackoverflow.com/questions/26259117/sql-server-fuzzy-search-with-percentage-of-match) – user918967
Si sta utilizzando Access? Se è così, considera il carattere '*', senza le virgolette. Se utilizzi SQL Server, utilizza il carattere '%'. Tuttavia, questa non è una logica fuzzy, è davvero l'operatore Like. Se hai davvero bisogno di logica fuzzy, esporta il set di dati in Excel e carica AddIn dall'URL sottostante.
https://www.microsoft.com/en-us/download/details.aspx?id=15011
Leggere attentamente le istruzioni. Funziona sicuramente, e funziona benissimo, ma devi seguire le istruzioni e non è completamente intuitivo. La prima volta che l'ho provato, non ho seguito le istruzioni e ho perso un sacco di tempo cercando di farlo funzionare. Alla fine ho capito, e ha funzionato benissimo !!
Abbiamo ottenuto buoni risultati sull'abbinamento del nome e dell'indirizzo utilizzando una funzione Metaphone creata da Lawrence Philips. Funziona in modo simile a Soundex, ma crea un modello suono/consonante per l'intero valore. Potresti trovarlo utile in combinazione con altre tecniche, specialmente se puoi eliminare alcuni dei fluff come "co". e 'inc.' come menzionato in altri commenti:
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
L'unico abbinamento che abbia mai dovuto fare era basato sulla corrispondenza della sottostringa ad es. BBC Uni e BBC University. Ciò presuppone che la parte iniziale della stringa sia la stessa tra tutti i duplicati. Per casi come: widgets inc vorrei innanzitutto eliminare le abbreviazioni di tipo entità. Se disponi di altri dati correlati, ad es. L'indirizzo della società, amministratore delegato della società, quindi anche questo, può essere paragonato per produrre un punteggio della probabilità che due società siano le stesse. Mi concentrerei sulla normalizzazione dei dati prima (rimuovendo il fluff) prima di provare a confrontarlo effettivamente. – Alex
Rimozione del fluff è in genere una buona pratica, non importa quale algoritmo si utilizza. – Yobik
Elaborerò sulla normalizzazione dei dati. Per casi come "Smith & Wesson" abbinati a "Smith and Wesson", convertirei tutti "&" in "e" ai fini di una partita. Vorrei anche provare a rimuovere i tipi di entità e le loro abbreviazioni (inc. Co.) E verificare se questo dà falsi positivi. Se i dati hanno costrutti più complessi, ad es. "CompanyA trading as CompanyB", quindi devono essere analizzati. IMO, fuzzy che combina dati ben strutturati come i nomi delle aziende è uno strumento sbagliato per il lavoro. – Alex