1
votes

Jeton de remplacement Spacy

J'essaye de remplacer un mot sans détruire la structure de l'espace dans la phrase. Supposons que j'ai la phrase text = "Hi this is my dog." . Et je souhaite remplacer le chien par Simba . Suite à la réponse de https://stackoverflow.com/a/57206316/2530674 j'ai fait:

import spacy
nlp = spacy.load("en_core_web_lg")
from spacy.tokens import Doc

doc1 = nlp("Hi this is my dog.")
new_words = [token.text if token.text!="dog" else "Simba" for token in doc1]
Doc(doc1.vocab, words=new_words)
# Hi this is my Simba . 

Remarquez qu'il y avait un espace supplémentaire à la fin avant le point (ça devrait être Hi this is my Simba. ). Existe-t-il un moyen de supprimer ce comportement. Heureux pour une réponse générale sur le traitement des chaînes python.


3 commentaires

Quel est le résultat attendu après le remplacement, lors de la «préservation de la structure spatiale»?


Mis à jour pour Hi this is my Simba. . Merci.


Ce code ne s'exécute pas, doc1 n'est jamais défini. Veuillez corriger votre code. ( MCVE


5 Réponses :


2
votes

Une façon de faire cela de manière extensible serait d'utiliser le Spacy Matcher et de modifier l'objet Doc, comme ceci:

import re
def replace_word_re(text, word, replacement):
    return re.sub(word, replacement, text)

>>> replace_word_re("Hi this is my dog.", "dog", "Simba")
Hi this is my Simba.

Vous pouvez bien sûr étendre ce modèle et remplacer toutes les instances de "dog" en ajoutant une boucle for dans la fonction au lieu de simplement remplacer la première correspondance, et vous pouvez échanger des règles dans le matcher pour changer différents mots.

La bonne chose à faire de cette façon, même si c'est plus complexe, est que cela vous permet de conserver les autres informations dans l'objet Spacy Doc, comme les lemmes, les parties de discours, les entités, l'analyse des dépendances, etc.

Mais vous, si vous n'avez qu'une chaîne, vous n'avez pas à vous soucier de tout cela. Pour ce faire avec Python ordinaire, j'utiliserais regex.

from spacy.matcher import Matcher

matcher = Matcher(nlp.vocab)
matcher.add("dog", on_match, [{"LOWER": "dog"}])

def replace_word(doc, replacement):
    doc = nlp(doc)
    match_id, start, end = matcher(doc)[0] #assuming only one match replacement

    return nlp.make_doc(doc[:start].text + f" {replacement}" + doc[-1].text)

>>> replace_word("Hi this is my dog.", "Simba")
Hi this is my Simba.


0 commentaires

1
votes

Il semble donc que vous recherchiez un remplacement régulier? Je ferais juste

string = "Hi this is my dog."
string = string.replace("dog","Simba")


4 commentaires

Le problème avec un simple remplacement de chaîne est que vous perdez alors toutes les informations de l'objet Spacy Doc.


Ok, je ne sais pas ce qu'est spacy alors je vais laisser ça ici.


Spacy est une bibliothèque NLP qui prend un document sous forme de chaîne et le transforme en gros c struct qui stocke des informations sur le document et toutes les sous-structures qu'il contient, comme les analyses de dépendances, des parties de discours, des lemmes, des fréquences, des indices, etc. Il est vraiment utile de garder toutes ces informations intactes, et de les réduire à un traitement de chaîne efface la structure sous-jacente. :)


Aha, ça sonne bien :)



1
votes

text = 'Bonjour c'est mon chien' print (text.replace ('dog', 'simba'))


0 commentaires

1
votes

Grâce à @ lora-johns, j'ai trouvé cette réponse. Donc, sans emprunter la voie du matcher, je pense que cela pourrait être une réponse plus simple:

new_words = [(token.idx, len("dog")) for token in doc1 if token.text.lower()=="dog"]
# reverse order of replacement words from end to start
new_words = sorted(new_words, key=lambda x:-x[0])
for i, l in new_words: 
    text = text[:i] +  "Simba" + text[i+l:] 


1 commentaires

Agréable! Vous pouvez également accéder directement à token.lower_ .



1
votes

La fonction ci-dessous remplace n'importe quel nombre de correspondances (trouvées avec spaCy), conserve le même espacement que le texte d'origine et gère de manière appropriée les cas de bord (comme lorsque la correspondance est au début du texte):

import spacy
from spacy.matcher import Matcher

nlp = spacy.load("en_core_web_lg")

matcher = Matcher(nlp.vocab)
matcher.add("dog", None, [{"LOWER": "dog"}])

def replace_word(orig_text, replacement):
    tok = nlp(orig_text)
    text = ''
    buffer_start = 0
    for _, match_start, _ in matcher(tok):
        if match_start > buffer_start:  # If we've skipped over some tokens, let's add those in (with trailing whitespace if available)
            text += tok[buffer_start: match_start].text + tok[match_start - 1].whitespace_
        text += replacement + tok[match_start].whitespace_  # Replace token, with trailing whitespace if available
        buffer_start = match_start + 1
    text += tok[buffer_start:].text
    return text

>>> replace_word("Hi this is my dog.", "Simba")
Hi this is my Simba.

>>> replace_word("Hi this dog is my dog.", "Simba")
Hi this Simba is my Simba.


0 commentaires