angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

Politician Translator avec Spacy et Negate

Découvrez ce que les politiciens veulent vraiment dire en changeant leur texte en son contraire.

11 janvier 2023
post main image
https://www.pexels.com/nl-nl/@pixabay

Ceci est un court message. Nous entendons tout le temps ces politiciens parler mais la plupart du temps, ils veulent dire le contraire. Par exemple, si un politicien dit qu'il va baisser les impôts, les impôts vont augmenter. Si un politicien dit qu'il n'a pas eu de relation avec cette femme, alors ... Etc.

J'ai donc pensé, pourquoi ne pas faire un Politician Translator en Python ? Dans ce post, je commence par les résultats. Le code est à la fin.

Le Politician Translator en action

Joe Biden le 9 janvier 2023 (Twitter) :

Les deux premières années de ma présidence ont été les deux plus fortes années de croissance de l'emploi jamais enregistrées.
Ces gains historiques en matière d'emploi et de chômage donnent plus de pouvoir aux travailleurs et plus de souffle aux familles américaines.

Politician Translator:

Les deux premières années de ma présidence n'ont pas été les deux plus fortes années de croissance de l'emploi jamais enregistrées.
Ces gains historiques en matière d'emploi et de chômage ne donnent pas plus de pouvoir aux travailleurs et plus de souffle aux familles américaines.

Bill Clinton il y a 15 ans :

Je n'ai pas eu de relations sexuelles avec cette femme, Mlle Lewinsky.

Politician Translator:

J'ai eu des relations sexuelles avec cette femme, Mlle Lewinsky.

Joe Biden le 6 janvier 2023 (Twitter) :

Mon plan économique a toujours été de faire croître notre économie du bas vers le haut et du milieu vers l'extérieur.
Aujourd'hui, nous avons appris que le chômage est à son plus bas niveau depuis 50 ans après les deux plus fortes années de croissance de l'emploi jamais enregistrées.
Nous créons des emplois. Nous réduisons les coûts. Notre plan fonctionne.

Politician Translator:

Mon plan économique n'a pas toujours été de faire croître notre économie du bas vers le haut et du milieu vers l'extérieur.
Aujourd'hui, nous n'avons pas appris que le chômage n'est pas à son plus bas niveau depuis 50 ans après les deux plus fortes années de croissance de l'emploi jamais enregistrées.
Nous ne créons pas d'emplois. Nous ne réduisons pas les coûts. Notre plan ne fonctionne pas.

N'aimez-vous pas ça ?

Le Politician Translator peut aussi être utilisé pour former les politiciens.

Par exemple, ils doivent dire :

J'aime le beurre de cacahuètes et j'en mange tous les jours.

Alors qu'ils veulent dire en réalité :

Je n'aime pas le beurre de cacahuètes et je n'en mange pas tous les jours.

Un autre exemple. Ils doivent dire :

Mon premier anniversaire était génial. Mon 2. était encore mieux.

Alors qu'ils veulent dire :

Mon premier anniversaire n'était pas génial. Mon deuxième anniversaire n'était pas encore mieux.

Quelques details sur le code

J'ai eu cette idée et j'ai d'abord envisagé d'utiliser antonymes. Trop complexe pour un projet court, peut-être dans une prochaine version. Puis j'ai trouvé le paquet Python 'Negate'. Très bien, mais il ne peut pas gérer les phrases composées.

J'ai donc cherché un moyen de décomposer les phrases en parties. Pour ce faire, nous utilisons le POS-tags d'une phrase. Bien que très primitif, ce système fonctionne dans de nombreux cas.

Une fois que nous avons les parties d'une phrase, nous lançons 'Negate' sur elles, et les recollons ensemble. Puis quelques corrections, et c'est fini.

Politician Translator : Le code

# your text
text = """The first two years of my presidency were the two strongest years of job growth on record. 
These historic jobs and unemployment gains are giving workers more power and American families more breathing room.
"""

text = """I did not have sexual relations with that woman, Miss Lewinsky."""

#text = """I like peanut butter and eat it every day."""

#text = """My first birthday was great. My 2. was even better."""


import re
from negate import Negator
import spacy
from spacy.lang.en import English


class TextToSentences:
    def __init__(self):
        self.nlp = spacy.load('en_core_web_sm')
        self.nlp.add_pipe('sentencizer')
    
    def get_sentences(self, text):
        doc = self.nlp(text)
        return [sent.text.strip() for sent in doc.sents]

class SentenceToParts:
    def __init__(self):
        self.nlp = spacy.load('en_core_web_sm')

    def get_parts(self, sentence):
        doc = self.nlp(sentence)
        parts, words = [], []
        for token in doc:
            if token.pos_ in ['CCONJ', 'SCONJ']:
                parts.append(' '.join(words))
                words = []
            words.append(token.text)
        if len(words) > 0:
            parts.append(' '.join(words))
        return parts

class NegateParts:
    def __init__(self):
        self.negator = Negator(use_transformers=True)

    def get_negated_parts(self, parts):
        negated_parts = []
        for part in parts:
            negated_parts.append(self.negator.negate_sentence(part, prefer_contractions=False))
        return negated_parts

class StitchParts:
    def __init__(self):
        self.nlp = spacy.load('en_core_web_sm')

    def get_stitched_parts(self, parts):
        stitched_parts_items = []
        for i, part in enumerate(parts):
            # first word to lowercase if not PROPN
            doc = self.nlp(part)
            words = []
            for j, token in enumerate(doc):
                word = token.text
                if i > 0 and j == 0 and token.pos not in ['PROPN']:
                    word = word.lower()
                words.append(word)
            stitched_parts_items.append(' '.join(words))
        return ' '.join(stitched_parts_items)
                
class FixUpSentence:
    def __init__(self):
        pass

    def get_fixedup_sentence(self, sentence):
        # trim
        sentence = sentence.strip()
        # fix: end of line ' .'
        sentence = re.sub(r'\s\.$', '.', sentence)
        # fix: ' ’s'
        sentence = sentence.replace(' ’s', '\'s')
        # fix: ' , '
        sentence = sentence.replace(' , ', ', ')
        return sentence
       
tts = TextToSentences()
stp = SentenceToParts()
np = NegateParts()
sp = StitchParts()
fus = FixUpSentence()

# step 1: split text into sentences
sentences = tts.get_sentences(text)
    
ftext_items = []
for sentence in sentences:
    # step 2.1: split sentence into sub-sentences
    parts = stp.get_parts(sentence)
    # step 2.2: negate sub-sentences
    nparts = np.get_negated_parts(parts)
    # step 2.3: create sentences from sub-sentences
    nsentence = sp.get_stitched_parts(nparts)
    #print('nsentence = {}'.format(nsentence))
    fsentence = fus.get_fixedup_sentence(nsentence)
    # step 2.4: Remove spaces etc.
    ftext_items.append(fsentence)

# step 3: join sentences
ftext = ' '.join(ftext_items)

print('what they say = \n{}'.format(text))
print('what they mean = \n{}'.format(ftext))

Résumé

Je pourrais dire que je n'ai pas apprécié ce petit projet, mais alors vous utiliseriez le Politician Translator et vous sauriez ce que je veux vraiment dire ... ;-)

Liens / crédits

How to break up document by sentences with Spacy
https://stackoverflow.com/questions/46290313/how-to-break-up-document-by-sentences-with-spacy

Negate
https://pypi.org/project/negate

Tutorial on Spacy Part of Speech (POS) Tagging
https://machinelearningknowledge.ai/tutorial-on-spacy-part-of-speech-pos-tagging

En savoir plus...

Machine Learning

Laissez un commentaire

Commentez anonymement ou connectez-vous pour commenter.

Commentaires

Laissez une réponse

Répondez de manière anonyme ou connectez-vous pour répondre.