Exercices supplémentaires

Download nbviewer Onyxia
Binder Open In Colab githubdev

Cette page approfondit certains aspects présentés dans les autres tutoriels. Il s’agit d’une suite d’exercice, avec corrections, pour présenter d’autres aspects du NLP ou pratiquer sur des données différentes

Exploration des libellés de l’openfood database

Exercise: les noms de produits dans l’openfood database

L’objectif de cet exercice est d’analyser les termes les plus fréquents dans les noms de produits de l’openfood database. Au passage, cela permet de réviser les étapes de preprocessing (LIEN XXXXX) et d’explorer les enjeux de reconnaissance d’entités nommées.

Dans cet exercice:

  • tokenisation (nltk)
  • retrait des stop words (nltk)
  • nuage de mots (wordcloud)
  • reconnaissance du langage (fasttext)
  • reconnaissance d’entités nommées (spacy)

le tout sur l’OpenFood Database, une base de données alimentaire qui est enrichie de manière collaborative.

Hint

Pour pouvoir utiliser les modèles pré-entraînés de spaCy, il faut les télécharger. La méthode préconisée est d’utiliser, depuis un terminal, la commande suivante

python -m spacy download fr_core_news_sm

Dans un notebook jupyter, il se peut qu’il soit nécessaire de relancer le kernel.

Si l’accès à la ligne de commande n’est pas possible, ou si la commande échoue, il est possible de télécharger le modèle pré-entraîné directement depuis une session Python

import spacy
spacy.cli.download('fr_core_news_sm')
  1. Importer le modèle de reconnaissance de langage qui sera utilisé par la suite ainsi que le corpus Français utilisé par spacy
import tempfile
import os
import spacy

temp_dir = tempfile.NamedTemporaryFile()
temp_dir = temp_dir.name

os.system("wget -O {} https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.bin".format( "%s.model.bin" % temp_dir))
spacy.cli.download('fr_core_news_sm')
  1. Importer les données de l’openfood database à partir du code suivant
import pandas as pd
import urllib.request


urllib.request.urlretrieve('https://static.openfoodfacts.org/data/en.openfoodfacts.org.products.csv', "%s.openfood.csv" % temp_dir)
df_openfood = pd.read_csv("%s.openfood.csv" % temp_dir, delimiter="\t",
                          usecols=['product_name'], encoding = 'utf-8', dtype = "str")

Ces données devraient avoir l’aspect suivant:

df_openfood.iloc[:2, :5]
  1. Créer une fonction de nettoyage des noms de produits effectuant les étapes suivantes:
  • tokeniser le texte en question
  • retirer la ponctuation et les stopwords

Appliquer cette fonction à l’ensemble des noms de produits (variable product_name)

  1. Effectuer un nuage de mot sur les libellés avant et après nettoyage pour comprendre la structure du corpus en question. Le résultat devrait avoir l’apparence suivante
import wordcloud as wc
import matplotlib.pyplot as plt


def graph_wordcloud(data, by = None, valueby = None, yvar = "Text"):
    if (by is not None) & (valueby is not None):        
        txt = data[data[by]==valueby][yvar].astype(str)
    else:
        txt = data[yvar].astype(str)
    all_text = ' '.join([text for text in txt])
    wordcloud = wc.WordCloud(width=800, height=500,
                          random_state=21,
                      max_words=2000).generate(all_text)
    return wordcloud

def graph_wordcloud_by(data, by, yvar = "Text"):
    n_topics = data[by].unique().tolist()
    width=20
    height=80
    rows = len(n_topics)//2
    cols = 2
    fig=plt.figure(figsize=(width, height))
    axes = []
    for i in range(cols*rows):
        b = graph_wordcloud(data, by = by, valueby = n_topics[i], yvar = yvar)
        axes.append( fig.add_subplot(rows, cols, i+1) )
        axes[-1].set_title("{}".format(n_topics[i]))  
        plt.imshow(b)
        plt.axis('off')
        plt.savefig('{}.png'.format(yvar), bbox_inches='tight')


def wordcount_words(data, yvar, by = None):
    plt.figure( figsize=(15,15) )
    if by is None:
        wordcloud = graph_wordcloud(data, yvar = yvar, by = by)
        plt.imshow(wordcloud)
        plt.axis('off')
        plt.savefig('{}.png'.format(yvar), bbox_inches='tight')
    else:
        graph_wordcloud_by(data, by = by, yvar = yvar)

wordcount_words(df_openfood, yvar = "product_name")
wordcount_words(df_openfood, "tokenized")
  1. Utiliser la librairie Fasttext pour extraire les noms de produits français
  • Appliquer le modèle téléchargé précedemment pour déterminer le langage
  • Ne récupérer que les libellés français
import fasttext

PRETRAINED_MODEL_PATH = "%s.model.bin" % temp_dir
model = fasttext.load_model(PRETRAINED_MODEL_PATH)
newcols = ['language','score_language']
df_openfood[newcols] = pd.DataFrame(df_openfood['product_name'].astype(str).apply(lambda s: list(model.predict(s))).apply(lambda l: [l[0][0],l[1][0]]).tolist(), columns = newcols)
df_openfood['language'] = df_openfood['language'].str.replace("__label__","")
df_openfood_french = df_openfood[df_openfood['language'] == "fr"]
df_openfood_french.head(2)
  1. Visualiser avec spacy.displacy le résultat d’une reconnaissance d’entités nommées sur 50 données aléatoires. Cela vous semble-t-il satisfaisant ?
import spacy
import fr_core_news_sm

nlp = fr_core_news_sm.load()

example = " \n ".join(df_openfood_french['product_name'].astype("str").sample(50))

from spacy import displacy
html = displacy.render(nlp(example), style='ent', page=True)
print(html)
  1. Récupérer dans un vecteur les entités nommées reconnues par spaCy. Regarder les entités reconnues dans les 20 premiers libellés de produits
x = []
for doc in nlp.pipe(df_openfood_french.head(20)['product_name'].astype("unicode"), disable=["tok2vec", "tagger", "parser", "attribute_ruler", "lemmatizer"]):
    # Do something with the doc here
    x.append([(ent.text, ent.label_) for ent in doc.ents])
    
x
Previous