Skip to content

Latest commit

 

History

History
439 lines (287 loc) · 14.1 KB

chapter2.md

File metadata and controls

439 lines (287 loc) · 14.1 KB
title description prev next type id
Chapitre 2 : analyse de données à grande échelle avec spaCy
Dans ce chapitre, tu vas utiliser tes nouvelles compétences pour extraire des informations spécifiques à partir de grandes quantités de textes. Tu vas apprendre à tirer le meilleur parti des structures de données de spaCy, et comment combiner efficacement les approches statistiques et celles basées sur les règles pour l'analyse de textes.
/chapter1
/chapter3
chapter
2

Partie 1

  • Recherche la chaîne de caractères "chat" dans nlp.vocab.strings pour obtenir le hash.
  • Recherche le hash pour revenir à la chaîne de caractères.
  • Tu peux utiliser le magasin de chaînes de caractères nlp.vocab.strings comme un dictionnaire Python normal. Par exemple nlp.vocab.strings["licorne"] va retourner le hash, et la recherche du hash va retourner la chaîne "licorne".

Partie 2

  • Recherche l'étiquette de la chaîne "PER" dans nlp.vocab.strings pour obtenir le hash.
  • Recherche le hash pour revenir à la chaîne de caractères.
  • Tu peux utiliser le magasin de chaînes de caractères nlp.vocab.strings comme un dictionnaire Python normal. Par exemple nlp.vocab.strings["licorne"] va retourner le hash, et la recherche du hash va retourner la chaîne "licorne".

Pourquoi ce code génère-t-il une erreur ?

import spacy

# Crée un objet nlp pour le français et un pour l'allemand
nlp = spacy.blank("fr")
nlp_de = spacy.blank("de")

# Obtiens l'ID pour la chaîne 'Bowie'
bowie_id = nlp.vocab.strings["Bowie"]
print(bowie_id)

# Recherche l'ID de "Bowie" dans le vocabulaire
print(nlp_de.vocab.strings[bowie_id])

Les hashes ne peuvent pas être inversés. Pour éviter ce problème, ajoute le mot au nouveau vocabulaire en traitant un texte ou en cherchant la chaîne, ou utilise le même vocabulaire pour résoudre le hash vers une chaîne.

N'importe quelle chaîne de caractères peut être convertie en hash.

Le nom de variable nlp est seulement une convention. Si le code utilisait le nom de variable nlp au lieu de nlp_de, il écraserait l'objet nlp existant, vocabulaire y compris.

Créons quelques objets Doc de toutes pièces !

Partie 1

  • Importe le Doc depuis spacy.tokens.
  • Crée un Doc à partir des words et des spaces. N'oublie pas de passer le vocabulaire en argument !

La classe Doc prend 3 arguments : le vocabulaire partagé, généralement nlp.vocab, une liste de words et une liste de spaces, valeurs booléennes indiquant si le mot est suivi par un espace ou pas.

Partie 2

  • Importe le Doc depuis spacy.tokens.
  • Crée un Doc à partir des words et des spaces. N'oublie pas de passer le vocabulaire en argument !

Inspecte chaque mot du résultat textuel souhaité et vérifie s'il est suivi par un espace. Si c'est le cas, les valeurs d'espace doivent être True. Sinon, elles doivent être False.

Partie 3

  • Importe le Doc depuis spacy.tokens.
  • Complète les words et spaces pour correspondre au texte désiré et créer un doc.

Fais attention aux tokens individuels. Pour voir comment spaCy effectue normalement cette chaîne, tu peux essayer d'afficher les tokens pour nlp("Oh, vraiment ?!").

Dans cet exercice, tu vas créer les objets Doc et Span manuellement, et actualiser les entités nommées – exactement comme spaCy le fait en coulisses. Un objet nlp partagé a déjà été créé.

  • Importe les classes Doc et Span depuis spacy.tokens.
  • Utilise la classe Doc directement pour créer un doc à partir des mots et des espaces.
  • Crée un Span pour "David Bowie" à partir du doc et assigne-lui le label "PER" ("personne").
  • Remplace doc.ents par une liste d'une seule entité, le span "David Bowie".
  • Le Doc est initialisé avec trois arguments : le vocabulaire partagé, par exemple nlp.vocab, une liste de mots et une liste de valeurs booléennes indiquant si le mot doit ou non être suivi par un espace.
  • La classe Span prend quatre arguments: le doc de référence, l'indice du token de début, l'indice du token de fin et un label optionnel.
  • La propriété doc.ents est accessible en écriture, tu peux donc lui assigner n'importe quel itérable composé d'objets Span.

Le code de cet exemple essaie d'analyser un texte et de recueillir tous les noms propres qui sont suivis par un verbe.

import spacy

nlp = spacy.load("fr_core_news_sm")
doc = nlp("Berlin semble être une jolie ville")

# Obtiens tous les tokens et les étiquettes de partie de discours
token_texts = [token.text for token in doc]
pos_tags = [token.pos_ for token in doc]

for index, pos in enumerate(pos_tags):
    # Vérifie si le token courant est un nom propre
    if pos == "PROPN":
        # Vérifie si le token suivant est un verbe
        if pos_tags[index + 1] == "VERB":
            result = token_texts[index]
            print("Trouvé un nom propre avant un verbe :", result)

Partie 1

Pourquoi le code est-il mauvais ?

Il ne sera pas nécessaire de reconvertir les chaînes en objets Token. Evite plutôt de convertir les tokens en chaînes de caractères si tu as encore besoin d'accéder à leurs attributs et leurs relations.

Convertis toujours les résultats en chaînes le plus tard possible, et essaie d'utiliser les attributs natifs des tokens pour garder un code cohérent.

L'attribut .pos_ retourne l'étiquetage grossier de partie de discours et "PROPN" est le bon label pour chercher des noms propres.

Partie 2

  • Réécris le code pour utiliser les attributs de tokens natifs au lieu des listes token_texts et pos_tags.
  • Boucle sur chaque token du doc et contrôle son attribut token.pos_.
  • Utilise doc[token.i + 1] pour vérifier le token suivant et son attribut .pos_.
  • Si un nom propre est trouvé devant un verbe, affiche son token.text.
  • Supprime les token_texts et pos_tags – on n'a pas besoin de compiler d'avance des listes de chaînes de caractères !
  • Au lieu d'itérer sur les pos_tags, boucle sur chaque token dans le doc et vérifie l'attribut token.pos_.
  • Pour savoir si le token suivant est un verbe, jette un oeil à doc[token.i + 1].pos_.

Dans cet exercice, nous utiliserons un pipeline français plus étendu, qui comporte environ 20.000 vecteurs de mots. Le package de pipeline est déjà pré-installé.

  • Charge le pipeline moyen avec vecteurs de mots "fr_core_news_md".
  • Affiche le vecteur pour "bananes" en utilisant l'attribut token.vector.
  • Pour charger un pipeline entraîné, appelle spacy.load avec son nom sous forme de chaîne de caractères.
  • Pour accéder à un token dans un doc, tu peux utiliser son indice. Par exemple, doc[4].

Dans cet exercice, tu vas utiliser les méthodes similarity de spaCy pour comparer des objets Doc, Token et Span et obtenir leurs scores de similarité.

Partie 1

  • Utilise la méthode doc.similarity pour comparer doc1 à doc2 et afficher le résultat.

La méthode doc.similarity prend un argument : l'autre objet auquel l'objet courant doit être comparé.

Partie 2

  • Utilise la méthode token.similarity pour comparer token1 à token2 et afficher le résultat.
  • La méthode token.similarity prend un argument : l'autre objet auquel l'objet courant doit être comparé.

Partie 3

  • Crée des spans pour "super restaurant" et "bar vraiment sympa".
  • Utilise span.similarity pour les comparer et afficher le résultat.

Pourquoi ce motif ne trouve-t-il pas les tokens "Silicon Valley" dans le doc ?

pattern = [{"LOWER": "silicon"}, {"TEXT": " "}, {"LOWER": "valley"}]
doc = nlp("Pourquoi la Silicon Valley est-elle si prisée ?")

L'attribut "LOWER" dans le motif décrit des tokens dont la forme minuscule correspond à une valeur donnée. Ainsi {"LOWER": "valley"} trouvera les tokens "Valley", "VALLEY", "valley" etc.

Le tokenizer effectue déjà la séparation sur la base des espaces et chaque dictionnaire du motif contient un token.

Par défaut, tous les tokens décrits dans un motif doivent être trouvés exactement une fois. Les opérateurs sont nécessaires uniquement pour modifier ce comportement – par exemple, pour trouver zéro ou plusieurs fois un token.

Les deux motifs de cet exercice comportent des erreurs et ne vont pas fonctionner comme souhaité. Peux-tu les corriger ? Si tu es bloqué, essaie d'afficher les tokens du doc pour voir comment le texte sera séparé et ajuster les motifs pour que chaque dictionnaire représente un token.

  • Édite pattern1 pour qu'il trouve correctement toutes les mentions quelle que soit la casse pour "Amazon" suivi d'un nom propre commençant par une majuscule.
  • Édite pattern2 pour qu'il trouve correctement toutes les mentions d'un nom suivi de "tout-compris" quelle que soit sa casse.
  • Essaie de traiter les chaînes qui devraient être trouvées par l'objet nlp – par exemple [token.text for token in nlp("abonnement tout-compris")].
  • Inspecte les tokens et vérifie que chaque dictionnaire du motif décrit correctement un seul token.

Parfois il est plus efficace de rechercher des chaînes de caractères exactes au lieu d'écrire des motifs décrivant individuellement les tokens. C'est particulièrement vrai pour les catégories finies - comme l'ensemble des pays du monde. Nous disposons déjà d'une liste de pays, alors utilisons-là comme base pour notre script d'extraction d'informations. Une liste de chaînes est caractères est accessible via la variable COUNTRIES.

  • Importe le PhraseMatcher et initialise-le avec le vocab partagé dans la variable matcher.
  • Ajoute les motifs de phrase et appelle le matcher sur le doc.

Le vocab partagé est accessible avec nlp.vocab.

Dans l'exercice précédent, tu as écrit un script utilisant le PhraseMatcher de spaCy pour trouver des noms de pays dans un texte. Nous allons maintenant l'utiliser sur un texte plus long, analyser la syntaxe et mettre à jour les entités du document avec les pays trouvés.

  • Itère sur les correspondances et crée un Span avec le label "GPE" (entité géopolitique).
  • Mets à jour les entités dans doc.ents en y ajoutant les spans trouvés.
  • Obtiens la tête du token racine du span trouvé.
  • Affiche le texte de la tête et le span.
  • Rappelle-toi que le texte est disponible avec la variable text.
  • Le token racine du span est accessible avec span.root. La tête d'un token est accessible avec l'attribut token.head.