Hallo Habr.
Im letzten Teil von Habraiting wurde eine Methode zum Erstellen einer Wortwolke für englische Begriffe veröffentlicht. Natürlich ist die Aufgabe, russische Wörter zu analysieren, viel komplizierter, aber wie in den Kommentaren vorgeschlagen, gibt es dafür vorgefertigte Bibliotheken.
Lassen Sie uns herausfinden, wie man ein solches Bild erstellt:

Außerdem werden wir eine Wolke von Artikeln von Habr für alle Jahre sehen.
Wen interessiert es, was passiert ist, bitte unter der Katze.
Parsen
Der ursprüngliche Datensatz ist wie im vorherigen Fall csv mit den Überschriften der Artikel von Habr von 2006 bis 2019. Wenn jemand daran interessiert ist, es selbst zu versuchen, können Sie es
hier herunterladen.
Laden Sie zunächst die Daten in den Pandas-Datenrahmen und wählen Sie die Header für das gewünschte Jahr aus.
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)))]
Die Funktion unicode2str wird benötigt, um verschiedene knifflige Unicode-Zeichen aus der Konsolenausgabe zu entfernen, z. B. nicht standardmäßige Anführungszeichen. Unter OSX funktionierte dies ebenfalls. Bei der Ausgabe an Windows Powershell wurde der Fehler "UnicodeEncodeError: 'charmap'-Codec kann Zeichen nicht codieren" ausgegeben. Es war zu faul, mit Powershell-Einstellungen umzugehen, daher erwies sich diese Methode als die einfachste.
Der nächste Schritt besteht darin, russischsprachige Wörter von allen anderen zu trennen. Es ist ganz einfach - wir übersetzen die Zeichen in ASCII-Codierung und sehen, was noch übrig ist. Wenn mehr als 2 Zeichen übrig sind, betrachten wir das Wort "voll" (die einzige Ausnahme, die mir in den Sinn kommt, ist die Go-Sprache, aber diejenigen, die dies wünschen, können sie selbst hinzufügen).
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
Die nächste Aufgabe besteht darin, das Wort zu normalisieren. Um eine Wortwolke abzuleiten, muss jedes Wort in einem Fall und in einer Deklination angezeigt werden. Für Englisch entfernen wir einfach die "'s" am Ende und auch andere unlesbare Zeichen wie Klammern. Ich bin mir nicht sicher, ob diese Methode wissenschaftlich korrekt ist (und ich bin kein Linguist), aber für diese Aufgabe ist sie völlig ausreichend.
def normal_eng(s): for sym in ("'s", '{', '}', "'", '"', '}', ';', '.', ',', '[', ']', '(', ')', '-', '/', '\\'): s = s.replace(sym, ' ') return s.lower().strip()
Das Wichtigste, für das eigentlich alles begonnen hat, ist das Parsen russischer Wörter. Wie in den Kommentaren zum vorherigen Teil empfohlen, kann dies für Python mithilfe der pymorphy2-Bibliothek erfolgen. Mal sehen, wie es funktioniert.
import pymorphy2 morph = pymorphy2.MorphAnalyzer() res = morph.parse(u"") for r in res: print r.normal_form, r.tag.case
Für dieses Beispiel haben wir die folgenden Ergebnisse:
NOUN,inan,masc sing,datv datv NOUN,inan,masc sing,loc2 loc2 NOUN,inan,neut sing,datv datv NOUN,inan,masc sing,gen2 gen2
Für das Wort "Welt" definierte MorphAnalyzer "Normalform" als das Substantiv "Welt" (oder "Welt", ich weiß jedoch nicht, was es ist), Singular und mögliche Fälle als Dativ, Genitiv oder Lokativ.
Die Verwendung der MorphAnalyzer-Analyse ist recht einfach. Stellen Sie sicher, dass das Wort ein Substantiv ist, und leiten Sie seine normale Form ab.
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
Es bleibt alles zusammen zu sammeln und zu sehen, was passiert ist. Der Code sieht ungefähr so aus (irrelevante Fragmente entfernt):
from collections import Counter c_dict = Counter() for s in titles.values: for w in s.split(): if is_asciiword(w):
Am Ausgang haben wir ein Wörterbuch mit Wörtern und deren Anzahl. Wir leiten die ersten 100 ab und bilden daraus eine Wolke der Beliebtheit von Wörtern:
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()
Das Ergebnis erwies sich jedoch als sehr seltsam:

In Textform sah es so aus:
3958 3619 1828 840 2018 496 389 375 375
Die Wörter "Performing", "Second" und "Century" waren mit großem Abstand führend. Und obwohl es im Prinzip möglich ist (Sie können sich vorstellen, dass eine Überschrift wie „Das Durchsuchen von Passwörtern mit einer Geschwindigkeit von 1000 Mal pro Sekunde dauert ein Jahrhundert“), war es verdächtig, dass es so viele dieser Wörter gab. Und nicht umsonst - wie das Debuggen zeigte, definierte MorphAnalyzer das Wort "c" als "Sekunde" und das Wort "c" als "Jahrhundert". Das heißt, In der Überschrift "Verwenden von Technologie ..." hat MorphAnalyzer drei Wörter hervorgehoben - "Sekunde", "Hilfe", "Technologie", was offensichtlich falsch ist. Die nächsten obskuren Wörter waren "wann" ("bei Verwendung ...") und "bereits", die als das Substantiv "direkt" bzw. "bereits" definiert wurden. Die Lösung war einfach: Berücksichtigen Sie beim Parsen nur Wörter, die länger als 2 Zeichen sind, und geben Sie eine Liste der Ausnahmewörter in russischer Sprache ein, die von der Analyse ausgeschlossen werden. Auch dies ist vielleicht nicht ganz wissenschaftlich (zum Beispiel wäre ein Artikel über das „Beobachten eines Farbwechsels durch bereits“ aus der Analyse herausgefallen), aber für diese Aufgabe ist bereits :) ausreichend.
Das Endergebnis ist mehr oder weniger der Wahrheit ähnlich (mit Ausnahme von Go und möglichen Artikeln über Schlangen). Es bleibt noch alles in einem GIF zu speichern (der GIF-Generierungscode befindet sich im
vorherigen Teil ), und wir erhalten ein animiertes Ergebnis in Form der Beliebtheit von Schlüsselwörtern in den Überschriften von Habr von 2006 bis 2019.

Fazit
Wie Sie sehen, erwies sich die Analyse des russischen Textes mit Hilfe von vorgefertigten Bibliotheken als recht einfach. Natürlich ist die gesprochene Sprache mit einigen Vorbehalten ein flexibles System mit vielen Ausnahmen und dem Vorhandensein eines Kontextgefühls je nach Kontext, und es ist wahrscheinlich unmöglich, hier überhaupt 100% ige Sicherheit zu erhalten. Für die jeweilige Aufgabe reicht jedoch der obige Code aus.
Die Arbeit mit kyrillischen Texten in Python selbst ist übrigens alles andere als perfekt - kleinere Probleme mit der Ausgabe von Zeichen auf der Konsole, fehlerhafte Ausgabe von Arrays per Druck, die Notwendigkeit, u "" in Zeilen für Python 2.7 anzuhängen usw. Es ist sogar seltsam, dass im 21. Jahrhundert, wenn Es scheint, dass alle Atavismen wie KOI8-R oder CP-1252 ausgestorben sind. Die Probleme bei der Zeichenfolgencodierung bleiben weiterhin relevant.
Schließlich ist es interessant festzustellen, dass das Hinzufügen russischer Wörter zur Textwolke den Informationsgehalt des Bildes im Vergleich zur
englischen Version praktisch nicht erhöht hat - fast alle IT-Begriffe sprechen Englisch, sodass sich die Liste der russischen Wörter in den letzten 10 Jahren wesentlich weniger geändert hat. Um die Änderungen in der russischen Sprache zu sehen, müssen Sie wahrscheinlich 50 bis 100 Jahre warten - nach der angegebenen Zeit wird es eine Gelegenheit geben, den Artikel erneut zu aktualisieren;)