Eu estou procurando por um algoritmo de similaridade de string que produz melhores resultados em strings de comprimento variável do que os geralmente sugeridos (distância de levenshtein, soundex, etc.).
Por exemplo,
Dada a sequência A: "Robert",
Em seguida, string B: "Amy Robertson"
seria uma combinação melhor do que
String C: "Richard"
Além disso, de preferência, esse algoritmo deve ser independente de idioma (também funciona em outros idiomas que não o inglês).
string-matching
ranking
similarity
fuzzy-search
marzagao
fonte
fonte
Respostas:
Simon White, da Catalysoft, escreveu um artigo sobre um algoritmo muito inteligente que compara pares de caracteres adjacentes que funciona muito bem para meus propósitos:
http://www.catalysoft.com/articles/StrikeAMatch.html
O Simon tem uma versão Java do algoritmo e, abaixo, escrevi uma versão PL / Ruby (tirada da versão ruby simples, feita no comentário de entrada do fórum relacionado por Mark Wong-VanHaren), para que eu possa usá-lo nas minhas consultas no PostgreSQL:
Funciona como um encanto!
fonte
string_similarity("vitamin B", "vitamin C") #=> 1
existe uma maneira fácil de evitar esse tipo de comportamento?A resposta de Marzagao é ótima. Eu o convertei em C #, então pensei em publicá-lo aqui:
Pastebin Link
fonte
(2.0 * intersection) / union
- eu recebo o Double.NaN ao comparar duas strings vazias.Aqui está outra versão da resposta de marzagao , esta escrita em Python:
fonte
Aqui está minha implementação em PHP do algoritmo sugerido StrikeAMatch, de Simon White. as vantagens (como diz o link) são:
Um verdadeiro reflexo da semelhança lexical - strings com pequenas diferenças devem ser reconhecidas como sendo similares. Em particular, uma sobreposição significativa de substring deve apontar para um alto nível de similaridade entre as strings.
Robustez para mudanças na ordem das palavras - duas cadeias que contêm as mesmas palavras, mas em uma ordem diferente, devem ser reconhecidas como sendo semelhantes. Por outro lado, se uma string é apenas um anagrama aleatório dos caracteres contidos na outra, então (geralmente) deve ser reconhecido como diferente.
Independência de idioma - o algoritmo deve funcionar não apenas em inglês, mas em muitos idiomas diferentes.
fonte
Uma versão mais curta da resposta de John Rutledge :
fonte
intersection
variável é um desperdício de linha.Esta discussão foi realmente útil, obrigado. Converti o algoritmo em VBA para uso com o Excel e escrevi algumas versões de uma função de planilha, uma para comparação simples de um par de cadeias, a outra para comparar uma cadeia com um intervalo / matriz de cadeias. A versão strSimLookup retorna a última melhor correspondência como uma string, índice de matriz ou métrica de similaridade.
Essa implementação produz os mesmos resultados listados no exemplo da Amazon no site de Simon White, com algumas pequenas exceções em correspondências com baixa pontuação; não sei onde a diferença se aproxima, poderia ser a função Split do VBA, mas não investiguei, pois está funcionando bem para meus propósitos.
fonte
Sinto muito, a resposta não foi inventada pelo autor. Este é um algoritmo bem conhecido que foi apresentado pela Digital Equipment Corporation pela primeira vez e é frequentemente chamado de shingling.
http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-TN-1997-015.pdf
fonte
Traduzi o algoritmo de Simon White para PL / pgSQL. Esta é a minha contribuição.
fonte
Métricas de similaridade de string contêm uma visão geral de muitas métricas diferentes usadas na comparação de strings (a Wikipedia também tem uma visão geral). Muitas dessas métricas são implementadas em uma simetria de biblioteca .
Outro exemplo de métrica, não incluído na visão geral fornecida, é, por exemplo, a distância de compressão (tentando aproximar a complexidade de Kolmogorov ), que pode ser usada para textos um pouco mais longos do que o que você apresentou.
Você também pode considerar um assunto muito mais amplo do Processamento de linguagem natural . Esses pacotes R podem ajudá-lo a começar rapidamente (ou pelo menos dar algumas idéias).
E uma última edição - pesquise as outras questões sobre esse assunto no SO, existem algumas relacionadas.
fonte
Uma versão PHP mais rápida do algoritmo:
Para os dados que eu tive (aproximadamente 2300 comparações), eu tive um tempo de execução de 0,58seg com solução Igal Alkon versus 0,35seg com o meu.
fonte
Uma versão na bela Scala:
fonte
Aqui está a versão R:
fonte
Publicando a resposta de marzagao em C99, inspirada nesses algoritmos
Alguns testes baseados no artigo original :
fonte
Com base na incrível versão C # de Michael La Voie, conforme a solicitação para torná-lo um método de extensão, aqui está o que eu criei. O principal benefício de fazer dessa maneira é que você pode classificar uma Lista Genérica pela porcentagem correspondente. Por exemplo, considere que você tem um campo de seqüência de caracteres chamado "Cidade" em seu objeto. Um usuário procura por "Chester" e você deseja retornar os resultados em ordem decrescente de correspondência. Por exemplo, você deseja que correspondências literais de Chester apareçam antes de Rochester. Para fazer isso, adicione duas novas propriedades ao seu objeto:
Em cada objeto, defina o SearchText para o que o usuário procurou. Depois, você pode classificá-lo facilmente com algo como:
Aqui está a pequena modificação para torná-lo um método de extensão:
fonte
Minha implementação JavaScript utiliza uma sequência ou matriz de sequências e um piso opcional (o piso padrão é 0,5). Se você passar uma string, ela retornará true ou false, dependendo se a pontuação de similaridade da string é ou não maior ou igual ao piso. Se você passar uma matriz de cadeias, ela retornará uma matriz daquelas cadeias cuja pontuação de similaridade seja maior ou igual ao piso, classificada por pontuação.
Exemplos:
Aqui está:
fonte
for(var j = 0; j < pairs1.length; j++){
deve serfor(var j = 0; j < pairs2.length; j++){
O algoritmo do coeficiente de dados (resposta de Simon White / marzagao) é implementado em Ruby no método pair_distance_similar na gema amatch
https://github.com/flori/amatch
Essa gema também contém implementações de vários algoritmos aproximados de comparação e comparação de cadeias: distância de edição de Levenshtein, distância de edição de vendedores, distância de Hamming, maior comprimento de subsequência comum, maior comprimento de substring comum, métrica de distância de pares, métrica de Jaro-Winkler .
fonte
Uma versão de Haskell - fique à vontade para sugerir edições porque não fiz muito Haskell.
fonte
Clojure:
fonte
E a distância de Levenshtein, dividida pelo comprimento da primeira corda (ou, alternativamente, dividido pelo comprimento mínimo / máximo / médio de ambas as cordas)? Isso funcionou para mim até agora.
fonte
Ei pessoal, eu tentei isso em javascript, mas eu sou novo, alguém sabe maneiras mais rápidas de fazer isso?
fonte
x
ey
, e não deve percorrer loops usando umfor..in..
loop (use emfor(..;..;..)
vez disso).Aqui está outra versão do Similarity baseada no índice Sørensen – Dice (resposta de marzagao), esta escrita em C ++ 11:
fonte
Eu estava procurando por uma implementação em Ruby pura do algoritmo indicado pela resposta de @ marzagao. Infelizmente, o link indicado por @marzagao está quebrado. Na resposta do @ s01ipsist, ele indicou ruby gemmatmat onde a implementação não está em puro rubi. Então, pesquisei um pouco e encontrei a gema fuzzy_match que possui uma implementação pura de rubi (embora essa gema use
amatch
) aqui . Espero que isso ajude alguém como eu.fonte