1. En première partie de cours, il n'y a pas de pistes comment se procurer d'une jeu de données pour travailler avec. J'ai bien compris que partager la base de données est interdit à cause de droits d'auteurs. Par contre avec quoi va-t-on travailler? J'ai regardé sur le forum - il a pas mal de plaintes sur ce sujet et aucune solution.
Il serait bien de partager le code pour scraper les données, soit donner les pistes comment charger un jeu de données de texte dans la bibliothèque nltk. Et non pas juste le mentionner comme il est fait dans le cours, "téléchargez dans la bibliothèque nltk, c'est simple". Eh non. Si c'était simple, je n'avais pas besoin de passer ce cours.
2. En troisième partie de cours, on utilise le sous-module "ap" de module "tools". Sauf que ce module est obsolète (deprecated). https://pypi.org/project/tools/
c'est normal, ça arrive que les module viellissent et sont supprimés ou remplacés. Alors il serait bien de mettre à jour le code correspondant. Sinon il devient impossible de suivre le cours, sauf pour les étudiants qui savent déjà comment ça fonctionne et qui n'ont donc pas forcement besoin de ce cours.
je partage entièrement l'avis de Veronika (sans compter les nombreuses fautes d'orthographe...).
Ce cours n'est pas du tout pédagogique : pré-requis non dits nécessaires (comme scrapper les données), des TPs qui devraient être là pour nous aider à comprendre la démarche et comment utiliser les outils, alors qu'on passe son temps à corriger les bugs de code ou à trouver les bons modules...
Par la remarque sur l'orthographe je deduis que vous m'avez pris pour quelqu'un qui avait étudié la grammaire frnçaise pendant 11 ans à l'école durant toute mon enfance et l'adolescence, comme le font les locuteurs natifs français (French native speakers). Ou au moins les gens qui font leur études d'école en France. Hah, je suis flattée alors Mais en fait non, c'est juste une illusion : je n'ai pas investi 11 ans dans l'apprentissage de grammaire française.
L'orthographe n'est pas sacrée, elle peut aussi être repensée et modifiée. Comme ce cours Déjà des bons efforts dans cette direction étaient fait en 1990, puis en 2018. Une piste géniale, qu'on ne peut que saluer et encourager. Et un avis est surtout le sens transmi et non pas l'orthographe.
Sinon, sur le fond de sujet - peut-être le cours est abandonné par les créateurs, nous avons beau de crier dans le vide. Tous les cours listés avec ce proffesseur datent de quelques ans. Au plus probablement, il ne coopère plus avec Openclassroms, il a quitté cet organisme.
Sauf si quelqu'un d'autre qui est maintenant responsable pour le bon fonctionnement de Parcours Data Scientist, pourrait assurer que les étudiants sont munis de matériel de qualité.
Par la remarque sur l'orthographe je deduis que vous m'avez pris pour quelqu'un qui avait étudié la grammaire frnçaise pendant 11 ans à l'école durant toute mon enfance et l'adolescence, comme le font les locuteurs natifs français (French native speakers). Ou au moins les gens qui font leur études d'école en France. Hah, je suis flattée alors Mais en fait non, c'est juste une illusion : je n'ai pas investi 11 ans dans l'apprentissage de grammaire française.
L'orthographe n'est pas sacrée, elle peut aussi être repensée et modifiée. Comme ce cours Déjà des bons efforts dans cette direction étaient fait en 1990, puis en 2018. Une piste géniale, qu'on ne peut que saluer et encourager. Et un avis est surtout le sens transmi et non pas l'orthographe.
Sinon, sur le fond de sujet - peut-être le cours est abandonné par les créateurs, nous avons beau de crier dans le vide. Tous les cours listés avec ce proffesseur datent de quelques ans. Au plus probablement, il ne coopère plus avec Openclassroms, il a quitté cet organisme.
Sauf si quelqu'un d'autre qui est maintenant responsable pour le bon fonctionnement de Parcours Data Scientist, pourrait assurer que les étudiants sont munis de matériel de qualité.
Bonjour Veronika,
je me suis très mal exprimée dans mon précédent message et je m'en excuse !!!
Les fautes d'orthographe concernaient bien sur le cours et pas du tout votre message !!!
Bonjour, Vos commentaires vont m'éviter de perdre un temps précieux, merci! J'en déduis donc que le plus simple est de zapper les parties techniques du cours et de faire ses armes sur les projets directement...
Dommage, il est toujours utiles de faire de petits TP rapides pour prendre les choses en main.
Dommage que le cours ne semble donc pas maintenu... On est quand même sur un métier d'actualité ...
Je partage les avis qui ont été exprimés jusqu'à présent. Malheureusement, ça semble être une constante pour tous les cours de Yannis Chaouche que j'ai pu suivre jusqu'à présent : TP non-reproduisibles, nombreuses fautes dans le cours et les énoncés (grammaticales ou erreurs pures et simples), approche pédagogique mal pensée etc. etc. Il serait pertinent de revoir ce cours (parmi d'autres) en profondeur...
comme les autres étudiants, je constate que l'obtention des paroles de rap n'est pas du tout documentée. Même si ça ne sert pas tant que ça pour la suite, j'ai pris l'initiative d'écrire un scraper qui extrait la liste des rappeurs français de Wikipédia, puis qui scrape Genius.com pour récupérer les paroles des chansons.
Je vous fournis ici mon code.
1/ Créer un fichier extract_rappers.py et copier le code ci-dessous:
import numpy as np
import os
import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
project_settings = get_project_settings()
project_settings["FEEDS"] = { "rappeurs.json": {"format": "json"} }
class RapperSpider(scrapy.Spider):
name = 'rappeurs français'
start_urls = [
'https://fr.wikipedia.org/wiki/Cat%C3%A9gorie:Rappeur_fran%C3%A7ais',
]
def parse(self, response):
for category_group in response.css('div.mw-category-group'):
for letter_group in category_group.xpath('ul/li/a'):
yield {
'rappeur': letter_group.css('::text').get()
}
next_page = response.xpath('//div[@id="mw-pages"]/a').attrib["href"]
if next_page is not None:
yield response.follow(next_page, self.parse)
def stop(self):
self.crawler.engine.close_spider(self, 'timeout')
process_1 = CrawlerProcess(settings=project_settings )
process_1.crawl(RapperSpider, start_urls=["https://fr.wikipedia.org/wiki/Cat%C3%A9gorie:Rappeur_fran%C3%A7ais"])
process_1.start(stop_after_crawl=True)
2/ Créer un autre fichier nommé extract_single_rapper_songs.py et insérer le code ci-dessous
import scrapy, json, os, re, requests, sys
import numpy as np
from scrapy.crawler import CrawlerRunner
from scrapy.utils.project import get_project_settings
from twisted.internet import reactor
# Ici lire les rappeurs du fichier rappeurs.json
rappeurs = []
for dico in json.load(open('rappeurs.json')):
rappeurs.append(dico["rappeur"])
# Supprimer les parenthèses (exemple : "Abd al Malik (artiste)") + éventuels doublons + trier
rappeurs = list(map (lambda name : re.sub(pattern="\((.*)\)",repl='',string=name).rstrip() , rappeurs ) )
rappeurs = list(dict.fromkeys(rappeurs))
rappeurs.sort()
def get_songs_of_rapper( name ):
""" Fonction permettant d'aller lire sur genius.com la liste des chansons attribuées à ce rappeur """
GENIUS_CLIENT_ACCESS_TOKEN = "<votre client access token de Genius.com>"
rx = requests.get("https://api.genius.com/search?q="+ name.replace(' ','%20'), headers={"Authorization":"Bearer " + GENIUS_CLIENT_ACCESS_TOKEN})
only_unique_artist_query_songs = [ e for e in rx.json()["response"]["hits"] if e["result"]["artist_names"] == name ]
if only_unique_artist_query_songs == []:
return []
artist_api_path = only_unique_artist_query_songs[0]["result"]["primary_artist"]["api_path"]
rx = requests.get("https://api.genius.com" + artist_api_path +"/songs?sort=popularity&per_page=50&page=1", headers={"Authorization":"Bearer " + GENIUS_CLIENT_ACCESS_TOKEN})
# Ne garder que les morceaux dont le rappeur est l'unique artiste
artist_songs = [ e for e in rx.json()["response"]["songs"] if e["primary_artist"]["api_path"] == artist_api_path ]
songs = list(map( lambda e : ( e["title"], e["path"] ) ,artist_songs) )
return songs
# Créer un répertoire "/paroles" pour contenir les fichiers des paroles
if os.path.isdir("paroles") == False:
path = os.path.join(os.curdir, "paroles")
os.mkdir(path)
# Définition d'un Spider Scrapy custom (pour extraire les paroles de N chansons d'un même rappeur)
class SongSpider(scrapy.Spider):
name = 'paroles de chansons'
def __init__(self, song_paths=[], *args, **kwargs):
super(SongSpider, self).__init__(*args, **kwargs)
self.start_urls = ["https://genius.com" + song_path for song_path in song_paths]
def parse(self, response):
""" Parser le fichier HTML de sorte à extraire les paroles """
song_lyrics = []
for lyrics_container in response.xpath("//div[@data-lyrics-container='true']"):
for highlighted_verse in lyrics_container.xpath("a"):
song_lyrics += highlighted_verse.xpath("span//text()").getall()
song_lyrics += lyrics_container.xpath("text()").getall()
yield {
response.url.split("/")[-1] : song_lyrics
}
offset = int(sys.argv[1])
if offset >= len(rappeurs): exit()
rappeur_name = rappeurs[offset]
songs_of_a_rapper = get_songs_of_rapper( rappeur_name )
if songs_of_a_rapper == []:
exit()
project_settings = get_project_settings()
project_settings["FEEDS"] = { "paroles/" + rappeur_name + ".json": {"format": "json"} }
runner = CrawlerRunner(settings=project_settings)
song_paths_of_a_rapper = list(np.array(songs_of_a_rapper).T[1])
runner.crawl(SongSpider, song_paths=song_paths_of_a_rapper )
deferred = runner.join()
deferred.addBoth(lambda _: reactor.stop())
reactor.run()
3/ Se connecter à genius.com, et créer un compte (gratuit).
Aller sur leur API Client management page, et créer un client (plus d'infos ici : https://docs.genius.com/ ).
Cliquez sur "Generate Access Token" et en sauvegardez le client access token sur un bloc-note.
4/ Mettez à jour le client access token dans le fichier extract_single_rapper_songs.py
Cela se fait en remplaçant la valeur "<votre client access token de Genius.com>" par votre client access token pour la variable GENIUS_CLIENT_ACCESS_TOKEN. (ligne 23)
5/ Voilà, c'est prêt. Il ne vous reste plus qu'à exécuter le fichier suivant (nommez-le "install.py" par exemple):
import os, json
os.system("python extract_rappers.py")
rappeurs = []
for dico in json.load(open('rappeurs.json')):
rappeurs.append(dico["rappeur"])
for idx, rappeur_name in enumerate(rappeurs):
os.system("python extract_single_rapper_songs.py "+str(idx))
Mon code n'est pas du tout optimisé ni commenté convenablement, mais ça devrait marcher. Une exécution de python extract_single_rapper_songs.py <idx> devrait aller chercher toutes les paroles du rappeur index <idx>. Malheureusement, j'ai dû boucler sur tous les rappeurs au lieu de faire ça en une seule fois, car je ne connais pas trop scrapy, et je n'ai pas trop le temps de comprendre pourquoi plusieurs CrawlerRunner s'interbloquent entre eux. Je me doute que c'est dû à twisted.internet.reactor, mais bon, le code quick&dirty fait ce qu'on lui demande.
6/ Le code du TP devrait être à peu près celui-là:
import os, json, re
import pandas as pd
import matplotlib.pyplot as plt
import nltk
files_name = os.listdir("paroles")
os.chdir("paroles")
# Dictionnaire contenant
# - en clé : le nom du rappeur
# - en item : une liste de tous les couplets de toutes ses chansons
artistes = {}
for file_name in files_name:
rappeur_songs = json.load(open(file_name))
lyrics_of_a_single_rapper = []
for song in rappeur_songs:
song_title, song_lyrics = list(song.items())[0]
song_lyrics = list(map( lambda str: re.sub( "\[(.*)\]", '', str ).strip(), song_lyrics ))
song_lyrics = [ verse for verse in song_lyrics if len(verse) > 0 ]
lyrics_of_a_single_rapper += song_lyrics
artistes[ file_name[0:-5] ] = lyrics_of_a_single_rapper
words_used_by_rappeurs = {}
tokenizer = nltk.RegexpTokenizer(r'\w+')
for rappeur in artistes.keys():
words_used_by_rappeurs[rappeur] = []
for verse in artistes[rappeur]:
words_used_by_rappeurs[rappeur] += tokenizer.tokenize(verse.lower())
single_words_used_by_rappeurs = {}
for rappeur in words_used_by_rappeurs.keys():
single_words_used_by_rappeurs[rappeur] = list(dict.fromkeys(words_used_by_rappeurs[rappeur]))
lexical_variety_of_rappeurs = {}
for rappeur in words_used_by_rappeurs.keys():
lexical_variety_of_rappeurs[rappeur] = len (single_words_used_by_rappeurs[rappeur] ) / len(words_used_by_rappeurs[rappeur])
### Obtenir le classement des artistes avec le plus de variété lexicale
df_lexical_variety =pd.DataFrame( index=lexical_variety_of_rappeurs.keys(), data=lexical_variety_of_rappeurs.values(), columns=["variété lexicale"] )
df_lexical_variety_sorted = df_lexical_variety.sort_values(by="variété lexicale", ascending=False)
### Afficher le classement des artistes avec le plus de variété lexicale
fig = plt.figure(figsize=(25,5))
plt.bar(height=df_lexical_variety_sorted[0:20].values.T[0], x=df_lexical_variety_sorted[0:20].index )
### Mots les plus utilisés par rappeur
sw = set()
sw.update(tuple(nltk.corpus.stopwords.words('french')))
sw.update(["a","ça","va","quand","comme"])
most_used_words = {}
for rappeur in words_used_by_rappeurs.keys():
single_words = [ e for e in words_used_by_rappeurs[rappeur] if e not in sw ]
most_used_words[rappeur] = [ a for a, in pd.DataFrame(single_words).value_counts().index.values ]
Il serait vraiment pas mal d'avoir un embryon du début d'une ébauche d'exemple pour les TPs de ce cours. Comme indiqué ci-dessus, pour ceux pour qui c'est une première que de traiter du texte, le premier tp est un peu un écueil...
N'existe-il pas une base de données plus simple que le scrapping proposé dans le cours pour expliquer les différents principes et rendre le cours plus interactif??? C'est vraiment dommage
Je suis d'accord à propos des paroles de rap, j'ai tout de suite laissé tomber et je me suis fait mon propre corpus à partir de discours politiques mais j'ai perdu du temps et ce n'était pas aussi intéressant d'un point de vue pédagogique...
J'ai des remarques à faire également sur la partie Représentez votre corpus en "bag of words" :
1) je trouve que la structure du cours n'est pas claire : le bag-of-words, l'utilisation de n-grams et le TF-IDF semble en première lecture des étapes ou des façons de faire différentes alors qu'on peut utiliser le TF-IDF sur des n-grams. Une structure plus claire serait :
qu'est-ce qu'un bag of words ou bags of n-grams ? Introduire d'abord le principe de n-grams puis insister sur le fait qu'avec n=1 on appelle ça "bag of words"
"pondérer l'importance de chaque n-grams" , découpée elle-même en : 1)la probabilité de co-occurence 2) TF-IDF
2) Reprendre absolument les formules poids=fréquence du terme×indicateur similarité et poids=frequence du n-gram×idf(n-gramme) qui ne sont pas claires. Dans certains autres cours de machine learning, chaque item est bien défini et a sa propre notation. Ici,on utilise "poids" pour deux choses différentes, on ne précise pas si "fréquence" signifie "fréquence dans le document" ou "fréquence dans le corpus", etc. Ça pourrait donner :
On note W le poids d'un n-gram G dans un document D : W(G,D) = TF(G,D) * S avec
TF(G,D) : la fréquence du n-gram G dans le document D
S : un indice de similarité à travers les autres corpus
Dans le cas particulier de la méthode TF-IDF, on choisit l'Inverse Document Frequency comme indice de similarité. On a donc :
S = IDF(G) c'est-à-dire l'Inverse Document Frequency du n-gram G dans tout le corpus qui peut s'écrire ainsi :
IDF(G) = log( N / n(G) ) avec N = le nombre total de documents dans le corpus et n(G) = le nombre de documents dans lesquels le n-gram G apparaît.
Notre poids devient : W(G,D) = TF(G,D) * IDF(G) = TF(G,D) * log ( N / n(G) ) et c'est ce poids qui est une feature souvent appelée TF-IDF(G,D). Et qui n'est pas une soustraction de TF et IDF, d'ailleurs.
Si j'ai fait une erreur, n'hésitez pas à me corriger
Y a-t-il vraiment quelqu'un chez OpenClassRooms qui regarde nos commentaires dans l'optique d'améliorer les cours ? Il serait intéressant d'avoir un lien vers un formulaire de remarques sur chaque page de cours. On pourrait catégoriser en : fautes d'orthographes, propositions, ressenti, etc.
Merci !
[COURS] Analysez vos données textuelles
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Veronika Berezhnaia
Veronika Berezhnaia
Veronika Berezhnaia