Habraiting: construction d'un nuage de mots russophones sur l'exemple des en-têtes Habra

Salut, Habr.

Dans la dernière partie de Habraiting, une méthode de construction d'un nuage de mots pour les termes anglais a été publiée. Bien sûr, la tâche d'analyser les mots russes est beaucoup plus compliquée, mais comme suggéré dans les commentaires, il existe des bibliothèques prêtes à l'emploi pour cela.

Voyons comment construire une telle image:



Nous verrons également un nuage d'articles de Habr pour toutes les années.

Peu importe ce qui s'est passé, s'il vous plaît, sous le chat.

Analyse


L'ensemble de données initial, comme dans le cas précédent, est csv avec les en-têtes des articles de Habr de 2006 à 2019. Si quelqu'un est intéressé à l'essayer vous-même, vous pouvez le télécharger ici .

Pour commencer, chargez les données dans le Pandas Dataframe et sélectionnez les en-têtes pour l'année requise.

df = pd.read_csv(log_path, sep=',', encoding='utf-8', error_bad_lines=True, quotechar='"', comment='#') if year != 0: dates = pd.to_datetime(df['datetime'], format='%Y-%m-%dT%H:%MZ') df['datetime'] = dates df = df[(df['datetime'] >= pd.Timestamp(datetime.date(year, 1, 1))) & ( df['datetime'] < pd.Timestamp(datetime.date(year + 1, 1, 1)))] # Remove some unicode symbols def unicode2str(s): try: return s.replace(u'\u2014', u'-').replace(u'\u2013', u'-').replace(u'\u2026', u'...').replace(u'\xab', u"'").replace(u'\xbb', u"'") except: return s titles = df["title"].map(unicode2str, na_action=None) 

La fonction unicode2str est nécessaire pour supprimer divers caractères unicode délicats de la sortie de la console, tels que des guillemets non standard - sous OSX, cela fonctionnait également, et lors de la sortie vers Windows Powershell, l'erreur «UnicodeEncodeError: le codec« charmap »ne peut pas coder le caractère» a été émise. C'était trop paresseux pour gérer les paramètres Powershell, donc cette méthode s'est avérée être la plus simple.

L'étape suivante consiste à séparer les mots de langue russe de tous les autres. C'est assez simple - nous traduisons les caractères en encodage ascii et voyons ce qui reste. S'il reste plus de 2 caractères, alors nous considérons le mot "complet" (la seule exception qui vient à l'esprit est la langue Go, cependant, ceux qui le souhaitent peuvent l'ajouter eux-mêmes).

 def to_ascii(s): try: s = s.replace("'", '').replace("-", '').replace("|", '') return s.decode('utf-8').encode("ascii", errors="ignore").decode() except: return '' def is_asciiword(s): ascii_word = to_ascii(s) return len(ascii_word) > 2 

La tâche suivante consiste à normaliser le mot - afin de dériver un nuage de mots, chaque mot doit être affiché dans un cas et une déclinaison. Pour l'anglais, nous supprimons simplement les «» à la fin, et supprimons également les autres caractères illisibles tels que les crochets. Je ne suis pas sûr que cette méthode soit scientifiquement correcte (et je ne suis pas linguiste), mais pour cette tâche, c'est assez.

 def normal_eng(s): for sym in ("'s", '{', '}', "'", '"', '}', ';', '.', ',', '[', ']', '(', ')', '-', '/', '\\'): s = s.replace(sym, ' ') return s.lower().strip() 

Maintenant, la chose la plus importante, pour le bien de laquelle tout a réellement commencé, est l'analyse des mots russes. Comme indiqué dans les commentaires de la partie précédente, pour Python, cela peut être fait en utilisant la bibliothèque pymorphy2. Voyons comment cela fonctionne.

 import pymorphy2 morph = pymorphy2.MorphAnalyzer() res = morph.parse(u"") for r in res: print r.normal_form, r.tag.case 

Pour cet exemple, nous avons les résultats suivants:

  NOUN,inan,masc sing,datv datv  NOUN,inan,masc sing,loc2 loc2  NOUN,inan,neut sing,datv datv  NOUN,inan,masc sing,gen2 gen2 

Pour le mot "monde", MorphAnalyzer a défini "forme normale" comme le nom "monde" (ou "monde", cependant, je ne sais pas ce que c'est), les cas singuliers et possibles comme dativ, génitiv ou locatif.

Utiliser l'analyse MorphAnalyzer est assez simple - assurez-vous que le mot est un nom et dérivez sa forme normale.

 morph = pymorphy2.MorphAnalyzer() def normal_rus(w): res = morph.parse(w) for r in res: if 'NOUN' in r.tag: return r.normal_form return None 

Il reste à tout rassembler et à voir ce qui s'est passé. Le code ressemble à ceci (fragments non pertinents supprimés):

 from collections import Counter c_dict = Counter() for s in titles.values: for w in s.split(): if is_asciiword(w): # English word or digit n = normal_eng(w) c_dict[n] += 1 else: # Russian word n = normal_rus(w) if n is not None: c_dict[n] += 1 

En sortie, nous avons un dictionnaire des mots et leur nombre d'occurrences. Nous dérivons les 100 premiers et formons d'eux un nuage de popularité des mots:

 common = c_dict.most_common(100) wc = WordCloud(width=2600, height=2200, background_color="white", relative_scaling=1.0, collocations=False, min_font_size=10).generate_from_frequencies(dict(common)) plt.axis("off") plt.figure(figsize=(9, 6)) plt.imshow(wc, interpolation="bilinear") plt.title("%d" % year) plt.xticks([]) plt.yticks([]) plt.tight_layout() file_name = 'habr-words-%d.png' % year plt.show() 

Le résultat, cependant, s'est avéré très étrange:



Sous forme de texte, cela ressemblait à ceci:

   3958  3619  1828  840 2018 496  389  375  375 

Les mots «performant», «deuxième» et «siècle» menaient par une énorme marge. Et bien que, en principe, cela soit possible (vous pouvez imaginer un titre comme «La recherche de mots de passe à une vitesse de 1000 fois par seconde prendra un siècle»), mais il était suspect qu'il y ait autant de ces mots. Et pas en vain - comme l'a montré le débogage, MorphAnalyzer a défini le mot "c" comme "deuxième" et le mot "c" comme "siècle". C'est-à-dire dans la rubrique "Utilisation de la technologie ..." MorphAnalyzer a mis en évidence 3 mots - "deuxième", "aide", "technologie", ce qui est évidemment incorrect. Les mots obscurs suivants étaient «quand» («Lors de l'utilisation ...») et «déjà», qui étaient définis comme le nom «direct» et «déjà», respectivement. La solution était simple - lors de l'analyse, ne considérez que les mots de plus de 2 caractères et entrez une liste de mots d'exception en russe qui seraient exclus de l'analyse. Encore une fois, ce n'est peut-être pas entièrement scientifique (par exemple, un article sur «observer un changement de coloration par déjà» aurait été abandonné de l'analyse), mais pour cette tâche déjà :) suffit.

Le résultat final est plus ou moins similaire à la vérité (à l'exception de Go et des articles possibles sur les serpents). Il reste à enregistrer tout cela dans un gif (le code de génération gif est dans la partie précédente ), et nous obtenons un résultat animé sous la forme de la popularité des mots-clés dans les rubriques Habr de 2006 à 2019.



Conclusion


Comme vous pouvez le voir, l'analyse du texte russe à l'aide de bibliothèques prêtes à l'emploi s'est avérée assez simple. Bien sûr, avec certaines réserves, la langue parlée est un système flexible avec de nombreuses exceptions et la présence d'un sens du contexte selon le contexte, et il est probablement impossible d'obtenir 100% de certitude ici du tout. Mais pour la tâche à accomplir, le code ci-dessus est suffisant.

Le travail avec les textes cyrilliques en Python lui-même, soit dit en passant, est loin d'être parfait - problèmes mineurs avec l'affichage des caractères dans la console, tableaux d'impression cassés, la nécessité d'ajouter u "" dans les lignes pour Python 2.7, etc. Il est même étrange qu'au 21e siècle, lorsque il semble que tous les atavismes tels que KOI8-R ou CP-1252 se soient éteints, les problèmes d'encodage des chaînes restent toujours d'actualité.

Enfin, il est intéressant de noter que l'ajout de mots russes au nuage de texte n'a pratiquement pas augmenté le contenu informationnel de l'image par rapport à la version anglaise - presque tous les termes informatiques sont anglophones, de sorte que la liste des mots russes a beaucoup moins changé de manière significative au cours des 10 dernières années. Probablement, pour voir les changements dans la langue russe, vous devez attendre 50-100 ans - après l'heure spécifiée, il y aura une occasion de mettre à jour l'article à nouveau;)

Source: https://habr.com/ru/post/fr442626/


All Articles