web-dev-qa-db-fra.com

Comparaison de chaîne fuzzy hautes performances en Python, utilisez Levenshtein ou difflib

Je suis en train de normaliser le message clinique (vérification orthographique) dans lequel je vérifie chaque mot donné par rapport au dictionnaire médical 900 000 mots. Je suis plus préoccupé par la complexité du temps/performance.

Je veux faire une comparaison de chaîne floue, mais je ne suis pas sûr de la bibliothèque à utiliser.

Option 1:

import Levenshtein
Levenshtein.ratio('hello world', 'hello')

Result: 0.625

Option 2:

import difflib
difflib.SequenceMatcher(None, 'hello world', 'hello').ratio()

Result: 0.625

Dans cet exemple, les deux donnent la même réponse. Pensez-vous que les deux fonctionnent de la même manière dans ce cas?

115
Maggie

Si vous souhaitez une comparaison visuelle rapide de la similarité Levenshtein et Difflib, j'ai calculé les deux pour environ 2,3 millions de titres de livres:

import codecs, difflib, Levenshtein, distance

with codecs.open("titles.tsv","r","utf-8") as f:
    title_list = f.read().split("\n")[:-1]

    for row in title_list:

        sr      = row.lower().split("\t")

        diffl   = difflib.SequenceMatcher(None, sr[3], sr[4]).ratio()
        lev     = Levenshtein.ratio(sr[3], sr[4]) 
        sor     = 1 - distance.sorensen(sr[3], sr[4])
        jac     = 1 - distance.jaccard(sr[3], sr[4])

        print diffl, lev, sor, jac

J'ai ensuite tracé les résultats avec R:

enter image description here

Strictement pour les curieux, j'ai également comparé les valeurs de similarité de Difflib, Levenshtein, Sørensen et Jaccard:

library(ggplot2)
require(GGally)

difflib <- read.table("similarity_measures.txt", sep = " ")
colnames(difflib) <- c("difflib", "levenshtein", "sorensen", "jaccard")

ggpairs(difflib)

Résultat: enter image description here

La similitude Difflib/Levenshtein est vraiment très intéressante.

Édition 2018: Si vous travaillez à identifier des chaînes similaires, vous pouvez également vérifier minhashing - il y a un très bon aperçu ici . Minhashing est étonnant de trouver des similitudes dans les grandes collections de textes en temps linéaire. Mon laboratoire a mis au point une application qui détecte et visualise la réutilisation du texte à l'aide de minhashing ici: https://github.com/YaleDHLab/intertext

133
duhaime
  • difflib.SequenceMatcher utilise l'algorithme Ratcliff/Obershelp . Il calcule le nombre doublé de caractères correspondants divisé par le nombre total de caractères des deux chaînes.

  • Levenshtein utilise algorithme de Levenshtein il calcule le nombre minimal de modifications nécessaires pour transformer une chaîne en une autre

Complexité

SequenceMatcher est un temps quadratique pour le cas le plus défavorable et a un comportement de cas attendu qui dépend de manière compliquée du nombre d'éléments communs aux séquences. ( à partir d'ici )

Levenshtein est O (m * n), où n et m sont la longueur des deux chaînes en entrée.

Performance

Selon le code source du module Levenshtein: Levenshtein a un certain chevauchement avec difflib (SequenceMatcher). Il ne supporte que les chaînes, pas les types de séquence arbitraires, mais par contre c'est beaucoup plus rapide.

97
Ghassen Hamrouni