web-dev-qa-db-fra.com

Comparaison de chaîne floue

Ce que je cherche à réaliser est un programme qui lit dans un fichier et compare chaque phrase en fonction de la phrase originale. La phrase qui correspond parfaitement à l'original recevra un score de 1 et une phrase représentant le total opposé recevra un 0. Toutes les autres phrases floues recevront une note entre 1 et 0. 

Je ne sais pas quelle opération utiliser pour me permettre de terminer ceci dans Python 3. 

J'ai inclus l'exemple de texte dans lequel le texte 1 est l'original et les autres chaînes précédentes sont les comparaisons. 

Texte: échantillon

Texte 1: C'était une nuit sombre et orageuse. J'étais tout seul assis sur une chaise rouge. Je n'étais pas complètement seul car j'avais trois chats.

Texte 20: C'était une nuit trouble et orageuse. J'étais tout seul assis sur une chaise écarlate. Je n'étais pas complètement seul car j'avais trois félins// Devrait marquer un point haut mais pas 1

Texte 21: Ce fut une nuit trouble et orageuse. J'étais tout seul assis sur une cathèdre pourpre. Je n'étais pas complètement seul car j'avais trois félins// devrait avoir un score inférieur à celui du texte 20

Texte 22: J'étais tout seul assis sur une cathèdre cramoisie. Je n'étais pas complètement seul car j'avais trois félins. C’était une nuit trouble et orageuse . // Doit avoir un score inférieur au texte 21 mais PAS 0

Texte 24: C'était une nuit sombre et orageuse. Je n'étais pas seul. Je n'étais pas assis sur une chaise rouge. J'ai eu trois chats . // devrait marquer un 0!

53
jacksonstephenc

Il existe un package appelé fuzzywuzzy . Installer via pip:

pip install fuzzywuzzy

Utilisation simple:

>>> from fuzzywuzzy import fuzz
>>> fuzz.ratio("this is a test", "this is a test!")
    96

Le paquet est construit sur difflib. Pourquoi ne pas simplement utiliser ça, demandez-vous? En plus d'être un peu plus simple, il a un certain nombre de méthodes de correspondance différentes (comme l'insensibilité aux ordres de jetons, la correspondance partielle de chaînes) qui la rendent plus puissante en pratique. Les fonctions process.extract sont particulièrement utiles: recherchez les chaînes et les ratios les mieux adaptés à un jeu. De leur readme:

Rapport partiel

>>> fuzz.partial_ratio("this is a test", "this is a test!")
    100

Ratio de tri des jetons

>>> fuzz.ratio("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear")
    90
>>> fuzz.token_sort_ratio("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear")
    100

Rapport de jetons

>>> fuzz.token_sort_ratio("fuzzy was a bear", "fuzzy fuzzy was a bear")
    84
>>> fuzz.token_set_ratio("fuzzy was a bear", "fuzzy fuzzy was a bear")
    100

Processus

>>> choices = ["Atlanta Falcons", "New York Jets", "New York Giants", "Dallas Cowboys"]
>>> process.extract("new york jets", choices, limit=2)
    [('New York Jets', 100), ('New York Giants', 78)]
>>> process.extractOne("cowboys", choices)
    ("Dallas Cowboys", 90)
87
congusbongus

Il existe un module dans la bibliothèque standard (appelé difflib ) qui permet de comparer des chaînes et de renvoyer un score en fonction de leur similarité. La SequenceMatcher class devrait faire ce que vous recherchez.

EDIT: Petit exemple de python Invite:

>>> from difflib import SequenceMatcher as SM
>>> s1 = ' It was a dark and stormy night. I was all alone sitting on a red chair. I was not completely alone as I had three cats.'
>>> s2 = ' It was a murky and stormy night. I was all alone sitting on a crimson chair. I was not completely alone as I had three felines.'
>>> SM(None, s1, s2).ratio()
0.9112903225806451

HTH!

75
mac

fuzzyset est beaucoup plus rapide que fuzzywuzzy (difflib) pour l'indexation et la recherche.

from fuzzyset import FuzzySet
corpus = """It was a murky and stormy night. I was all alone sitting on a crimson chair. I was not completely alone as I had three felines
    It was a murky and tempestuous night. I was all alone sitting on a crimson cathedra. I was not completely alone as I had three felines
    I was all alone sitting on a crimson cathedra. I was not completely alone as I had three felines. It was a murky and tempestuous night.
    It was a dark and stormy night. I was not alone. I was not sitting on a red chair. I had three cats."""
corpus = [line.lstrip() for line in corpus.split("\n")]
fs = FuzzySet(corpus)
query = "It was a dark and stormy night. I was all alone sitting on a red chair. I was not completely alone as I had three cats."
fs.get(query)
# [(0.873015873015873, 'It was a murky and stormy night. I was all alone sitting on a crimson chair. I was not completely alone as I had three felines')]

Avertissement: veillez à ne pas mélanger unicode et bytes dans votre fuzzyset.

13
hobs

La tâche est appelée Identification de paraphrase , qui est un domaine de recherche actif en traitement du langage naturel. J'ai lié plusieurs documents de pointe dont vous pouvez trouver le code open source sur GitHub.

Notez que toutes les questions posées supposent qu'il existe une certaine similarité chaîne/surface entre les deux phrases alors qu'en réalité, deux phrases avec peu de similarité de chaîne peuvent être sémantiquement similaires.

Si vous êtes intéressé par ce genre de similitude, vous pouvez utiliser Skip-Thoughts . Installez le logiciel conformément aux guides de GitHub et allez à la section de détection de paraphrase dans le readme:

import skipthoughts
model = skipthoughts.load_model()
vectors = skipthoughts.encode(model, X_sentences)

Ceci convertit vos phrases (X_sentences) en vecteurs. Plus tard, vous pouvez trouver la similitude de deux vecteurs par:

similarity = 1 - scipy.spatial.distance.cosine(vectors[0], vectors[1])

où nous supposons que le vecteur [0] et le vecteur 1 sont le vecteur correspondant à X_sentences [0], X_sentences 1 pour lesquels vous vouliez trouver leurs scores.

Il existe d’autres modèles pour convertir une phrase en vecteur que vous pouvez trouver ici .

Une fois vos phrases converties en vecteurs, la similarité consiste simplement à trouver la similarité Cosinus entre ces vecteurs.

1
Ash