[PYTHON] fastText ist unglaublich! Clustering "Yahoo! News"

Das letzte Mal dieser Artikel habe ich versucht, die Bücher von Aozora Bunko mit Doc2Vec zu gruppieren. Ich fragte mich, ob es ein wenig funktionierte, aber ehrlich gesagt war das Ergebnis subtil. Daher werde ich dieses Mal anstelle von Doc2Vec eine Bibliothek namens fastText verwenden, um Yahoo-Nachrichtenartikel zu gruppieren.

Was ist fastText?

fastText ist eine Open-Source-Bibliothek zur Verarbeitung natürlicher Sprache, die von Facebook entwickelt wurde. Es ist hochfunktional, hat eine gute Vorhersagegenauigkeit und macht Vorhersagen noch schneller. Die Hauptfunktionen sind die Klassifizierung durch überwachtes Lernen und die Vektorerzeugung von Wörtern durch unbeaufsichtigtes Lernen.

Dieses Mal werde ich versuchen, die Kategorie von Artikeln mithilfe der Klassifizierungsfunktion durch überwachtes Lernen vorherzusagen.

Weitere Informationen finden Sie unter offizielle offizielle FastText-Referenz! GitHub wurde detailliert über die Funktion von Python!

Entwicklungsumgebung

--Docker → hier

Implementierungsstart

import pandas as pd, numpy as np
import re
import MeCab
import fasttext
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
from sklearn.decomposition import PCA
import japanize_matplotlib

Erhalten Sie Nachrichtendaten

Laden Sie die Daten, die Sie mit dem in Scraping Yahoo News eingeführten Code erhalten haben. Es gibt viele internationale Nachrichten, weil es kurz nach den US-Präsidentschaftswahlen ist.

df = pd.read_csv('./YahooNews.csv')
df
title category text
0 Verlust? Azato süßer Riho Yoshioka Unterhaltung Die zweite Fotosammlung der Schauspielerin Yoshioka Riho 27 zum ersten Mal seit zwei Jahren. Riho-Sammlung von Asami Kiyokawa Shueisha ...
1 Teufels "heiliger Ort" Befeuchtendes Touristenziel Wirtschaft Die Filmversion der Devil's Blade, die trotz des Corona-Wracks einen ungewöhnlichen Blockbuster aufgenommen hat, ist nicht auf den Film der unendlichen Zugausgabe beschränkt ...
2 Dentsu G Corona halbiert das Betriebsergebnis Wirtschaft Die Dentsu Group gab am 10. bekannt, dass das konsolidierte Finanzergebnis für das im Dezember 2020 endende Geschäftsjahr 9 Umsatzerlöse aufweisen wird, die dem Umsatz entsprechen ...
3 Hongkonger Demokraten, alle zurückgetreten International 12 Nach Angaben der Beijing Joint Xinhua Electric Co., Ltd. wird Chinas Sitzung des Ständigen Ausschusses für alle Personen am 11. ... als Mitglied der Legislativversammlung 70 in Hongkong qualifiziert
4 Berufsorganisation Erhöhte Infektion bundesweit Inland Die Sitzung des Beirats, einer Expertenorganisation des Ministeriums für Gesundheit, Arbeit und Soziales, die über Maßnahmen gegen das neue Koronavirus berät, findet am 11. ... statt
... ... ... ...
512 Vier Personen stachen um das Weiße Haus herum International Laut US NBC TV und anderen versammelten sich Anhänger von Präsident Trump und dem ehemaligen Vizepräsidenten Byden bei den US-Präsidentschaftswahlen ...
513 Einseitige Siegeserklärung Die US-Reaktion ist International Washington vor 10 Uhr am 4., eine Nacht nach dem Wahltag der US-Präsidentschaftswahl von FNN Prime Online ...
514 Das Aktienwachstum in NY setzt sich fort und liegt vorübergehend bei über 600 USD International Am Morgen des 4., während der enge Kampf zwischen beiden Kandidaten Trump Byden bei den US-Präsidentschaftswahlen fortgesetzt wird, bei denen die aktuellen Angelegenheiten von New York eröffnet werden ...
515 Rückzug von Sega Sammy Gaesen Wirtschaft Sega Sammy Holdings beteiligt sich an Sega Entertainment Tokyo, einer konsolidierten Tochtergesellschaft, die am 4. ... Unterhaltungseinrichtungen betreibt
516 China setzt Waffen für die Sicherheit des Seeverkehrs ein International Der Gemeinsame Nationale Volkskongress der Nationalversammlung von China in Peking am 4. legt die Autorität des China Maritime Police Bureau fest, das für die Sicherheit des Seeverkehrs zuständig ist.

517 rows × 3 columns

Wörterbuch & Funktionsdefinition

#Geben Sie NEologd im MeCab-Wörterbuch an.
#Mecab ist für die Analyse mobiler Elemente, Wakati für das Teilen
mecab = MeCab.Tagger('-d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd/')
wakati = MeCab.Tagger("-Owakati -d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd/")


#Definieren Sie eine Funktion zur Durchführung einer morphologischen Analyse
#Wenn Sie eine Datei eingeben, wird die Datei ausgegeben, und wenn Sie eine Zeichenfolge übergeben, wird eine Zeichenfolge zurückgegeben. Ändern Sie mit der Argumentdatei.
#Wenn Sie nur trennen möchten, verwenden Sie Mecab als Argument=Dies kann mit Wakati erreicht werden.
def MecabMorphologicalAnalysis(path='./text.txt', output_file='wakati.txt', mecab=mecab, file=False):
    mecab_text = ''
    if file:
        with open(path) as f:
            for line in f:
                mecab_text += mecab.parse(line)
        with open(output_file, 'w') as f:
            print(mecab_text, file=f)
    else:
        for path in path.split('\n'):
            mecab_text += mecab.parse(path)
        return mecab_text


#Gibt die Kosinusähnlichkeit zwischen v1 und v2 aus.
def cos_sim(v1, v2):
    return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))

Datenvorverarbeitung

Es verwandelt sich in eine Form zur Verwendung mit fastText. Mit FastText können Sie auf einfache Weise überwachtes Lernen durchführen, indem Sie die Daten in der folgenden Form formatieren. Weitere Informationen finden Sie unter Offizielles Tutorial.

__label__sauce __label__cheese how much does potato starch affect a cheese sauce recipe ? 
__label__food-safety __label__acidity dangerous pathogens capable of growing in acidic environments
__label__cast-iron __label__stove how do i cover up the white spots on my cast iron stove ? 
__label__restaurant michelin three star restaurant; but if the chef is not there

Führen Sie die folgende Verarbeitung durch, um die obige Form zu erhalten. ① Fügen Sie vor der Nachrichtenkategorie __label__ ein → In Liste speichern (2) Schreiben Sie den Text separat mit der oben definierten Funktion "Mecab Morphological Analysis" → In der Liste speichern ③ Teilen Sie mit train_test_split in Zugdaten und gültige Daten ④ Kombinieren Sie Kategorien und Text mit Zug und gültig und speichern Sie in Datei

# ①
cat_lst = ['__label__' + cat for cat in df.category]
print("cat_lst[:5]:", cat_lst[:5]) #Überprüfen Sie den Inhalt
print("len(cat_lst):", len(cat_lst)) #Überprüfen Sie die Anzahl der Etiketten

cat_lst [: 5]: ['__ Label__ Unterhaltung', '__ Label__ Wirtschaft', '__ Label__ Wirtschaft', '__ Label__ International', '__ Label__ Inland'] len(cat_lst): 517

# ②
text_lst = [MecabMorphologicalAnalysis(text, mecab=wakati) for text in df.text]
print("text_lst[0][:50]:", text_lst[0][:50]) #Überprüfen Sie die erste Zeile
print("text_lst[1][:50]:", text_lst[1][:50]) #Überprüfen Sie die zweite Zeile
print("len(text_lst):", len(text_lst)) #Überprüfen Sie die Anzahl der Artikel

text_lst [0] [: 50]: Die zweite Fotosammlung der Schauspielerin Yoshioka Riho 27 zum ersten Mal seit zwei Jahren. Riho Collection von Asami Kiyok text_lst [1] [: 50]: Die Filmversion von Devil's Blade Infinite, die trotz der Corona-Trümmer einen ungewöhnlichen Blockbuster aufgenommen hat. len(text_lst): 517

# ③
text_train, text_valid, cat_train, cat_valid = train_test_split(
    text_lst, cat_lst, test_size=0.2, random_state=0, stratify=cat_lst
)


# ④
with open('./news.train', mode='w') as f:
    for i in range(len(text_train)):
        f.write(cat_train[i] + ' '+ text_train[i])
        
with open('./news.valid', mode='w') as f:
    for i in range(len(text_valid)):
        f.write(cat_valid[i] + ' ' + text_valid[i])

Modelllernen und Evaluieren

fastText ist "train_supervised" und kann leicht überwacht werden. Sie können eine n-Gramm-Verarbeitung durchführen, indem Sie ein Argument an wordNgrams übergeben, oder hs in Verlust setzen und "hierarchical softmax" verwenden, um eine Hochgeschwindigkeitsverarbeitung durchzuführen. Auf jeden Fall ist es sehr funktional! !!

Lernen ist großartig, aber ich denke, die Funktion von fastText besteht darin, dass Sie die Genauigkeit sofort mit "model.test" bewerten können. Wie unten gezeigt, können Sie sehen, dass die Genauigkeit selbst für gültige Daten recht gut ist.

model = fasttext.train_supervised(input='./news.train', lr=0.5, epoch=500,
                                  wordNgrams=3, loss='ova', dim=300, bucket=200000)

print("TrainData:", model.test('news.train'))
print("Valid", model.test('news.valid'))
TrainData: (413, 1.0, 1.0)
Valid (104, 0.75, 0.75)

Genauigkeitsbestätigung mit gültigen Daten

Lassen Sie uns die Genauigkeit des Modells anhand gültiger Daten überprüfen, die nicht für das Training verwendet werden. ① Speichern Sie den Inhalt gültiger Daten in l_strip (2) Speichern Sie Etikett, Text und Größe in einer Liste. Label ist die Nachrichtenkategorie, Text ist der Textkörper und Größe ist die Wahrscheinlichkeit, dass das Modell vorhergesagt wird. Der erforderliche Teil wird mit einem regulären Ausdruck extrahiert. ③ Nehmen Sie die Nachrichten einzeln heraus und versuchen Sie, die Kategorie vorherzusagen. Vorhersagen werden in absteigender Reihenfolge der Wahrscheinlichkeit durch die Anzahl der Argumente k von "Vorhersagen" angezeigt. Das nächste Array zeigt die entsprechenden Wahrscheinlichkeiten. Alle Fragen sind richtig, also ist es gut.

# ①
with open("news.valid") as f:
    l_strip = [s.strip() for s in f.readlines()] # strip()Entfernen Sie Zeilenvorschubzeichen mit
    

# ②    
labels = []
texts = []
sizes = []
for t in l_strip:
    labels.append(re.findall('__label__(.*?) ', t)[0])
    texts.append(re.findall(' (.*)', t)[0])
    sizes.append(model.predict(re.findall(' (.*)', t))[1][0][0])
# ③-1
print("<{}>".format(labels[0]))
print(texts[0])
print(model.predict(texts[0], k=3))
Die Dentsu-Gruppe gab am 10. bekannt, dass das konsolidierte Finanzergebnis für das im Dezember 2020 endende Geschäftsjahr 676,3 Milliarden Yen betragen wird, was einem Umsatzrückgang von 94 entspricht, der dem Umsatz entspricht. Das Betriebsergebnis, das den Gewinn des Hauptgeschäfts anzeigt, wurde auf 18,5 Milliarden Yen halbiert. Aufgrund der Auswirkungen der Krankheit ist die Nachfrage nach Fernseh- und Internetwerbung in Japan und Übersee zurückgegangen. Das Betriebsergebnis wird von Ende des Jahres bis März nächsten Jahres halbiert, ebenso wie die Gründung eines neuen Unternehmens, das Geschäfte an Rentner auslagert. Eine Reihe von MA-Fusionsakquisitionskosten war niedriger als erwartet, da Strukturreformkosten in Höhe von 25,1 Milliarden Yen verbucht wurden. Infolgedessen stieg der Nettogewinn um das 22-fache auf 10,2 Milliarden Yen. US Media Storm beschloss, ihn im Februar zu einer Tochtergesellschaft zu machen. Der Wert vieler Unternehmen, einschließlich Unternehmen, ist gesunken, und die geschätzten Kosten für den Erwerb zusätzlicher Aktien sind um etwa 30 Milliarden Yen gesunken. (('__ label__ Economy', '__ label__ Domestic', '__ label__ life'), Array ([9.88678277e-01, 1.48057193e-01, 3.89984576e-04]))
# ③-2
print("<{}>".format(labels[1]))
print(texts[1])
print(model.predict(texts[1], k=3))
Nintendo gab am 5. bekannt, dass der kumulierte weltweite Verkauf von Nintendo Switch, einem Spielautomaten für den Heimgebrauch, Ende September 68,3 Millionen Einheiten erreicht hatte. Der damit einhergehende Verbrauch von Nestern war Rückenwind, und der Wechsel, der in etwa dreieinhalb Jahren seit seiner Einführung im März 2017 erreicht wurde, kann als Spiel gespielt werden, selbst wenn er verschoben oder getragen wird, und er wurde von einer Vielzahl von Generationen unterstützt. Kein Mori war ein Hit und steigerte den Verkauf von Schaltern. Allein im September 2008 wurden 12,53 Millionen Einheiten verkauft. (('__ label__ Economy', '__ label__ sports', '__ label__domestic'), Array ([0.00338661, 0.00206074, 0.00081409]))
# ③-3
print("<{}>".format(labels[2]))
print(texts[2])
print(model.predict(texts[2], k=3))
JERA Seregi Giant 6-2 Yakult 7. Tokyo Dome Die Ruhestandszeremonie von Giant Hisashi Iwakuma 39, der erst in dieser Saison aus dem aktiven Dienst ausscheiden wird, fand am 7. nach der 23. Runde des Yakult Tokyo Dome statt, der höchsten Anzahl in dieser Saison. Vor menschlichen Fans schloss Iwakuma heute den Vorhang für 21 Jahre professionelles Baseballleben. Er sagte, dass er 21 Jahre lang mit wunderbaren Teamkollegen gesegnet war und das beste Baseballleben führen konnte und voller Dankbarkeit war. Und die Giants für die letzten zwei Jahre. Ich konnte nicht zur 1. Armee zurückkehren, aber ich bin froh, dass ich am Ende meiner Karriere die Giants-Uniform tragen konnte, und ich bin froh, diesen Tag zu haben. Ich möchte weiterhin jemanden durch Baseball glücklich machen können. Danach hielt ich eine Rede, in der ich mich 21 Jahre lang sehr bedankte. Danach erhielt ich einen Blumenstrauß von Shima, die mit meinem Teamkollegen Aoki Rakuten in der Mariners-Ära in Yakult spielte, und einen Blumenstrauß von Kanno. Er eilte selbst zu Iwakuma und machte mit Nine ein Erinnerungsfoto. Schließlich erhielt er einen Blumenstrauß von drei Kindern und machte erneut ein Erinnerungsfoto, um sich von den Fans zu verabschieden. ((('__ label__ sports', '__ label__ Entertainment', '__ label__ life')), Array ([8.55861187e-01, 1.00888625e-01, 7.65405654e-04]))

Analyse der Vektordarstellung

Sie können die Analyse bis zu diesem Punkt beenden, aber verwenden wir die Funktion "get_sentence_vector" von fastText, um den Vektor für jeden Artikel abzurufen und eine weitere Analyse durchzuführen. (1) Erhalten Sie für jeden Artikel einen Vektor und speichern Sie ihn in der Liste. (2) Ändern Sie den Vektor, die Beschriftung und die Größe in ein Numpy-Array. (Bereits für Etikett und Größe erworben) ③ Standardisieren Sie den Vektor mit "Standard Scaler" ④ Dimensionsreduzierung mit dem Hauptkomponentenanalysator "PCA" (5) Berechnen Sie die Ähnlichkeit für jeden Artikel mit der oben definierten cos_sim-Funktion. Artikel derselben Kategorie weisen die höchste Ähnlichkeit auf. ⑥ Zweidimensionales Diagramm des Vektors. Die Größe des Punktes ändert sich abhängig vom Wert der Größen. (Größen speichern Vorhersehbarkeit.)

# ①
vectors = []
for t in texts:
    vectors.append(model.get_sentence_vector(t))

    
# ②
vectors = np.array(vectors)
labels = np.array(labels)
sizes = np.array(sizes)


# ③
ss = preprocessing.StandardScaler()
vectors_std = ss.fit_transform(vectors)


# ④
pca = PCA()
pca.fit(vectors_std)
feature = pca.transform(vectors_std)
feature = feature[:, :2]
# ⑤-1
print("<{}><{}>".format(labels[0], labels[1]))
cos_sim(vectors[0], vectors[1])

0.9514279

# ⑤-2
print("<{}><{}>".format(labels[1], labels[2]))
cos_sim(vectors[1], vectors[2])

0.9299138

# ⑤-3
print("<{}><{}>".format(labels[0], labels[2]))
cos_sim(vectors[0], vectors[2])

0.79527444

# ⑥
x0, y0, z0 = feature[labels=='Unterhaltung', 0], feature[labels=='Unterhaltung', 1], sizes[labels=='Unterhaltung']*1000
x1, y1, z1 = feature[labels=='Sport', 0], feature[labels=='Sport', 1], sizes[labels=='Sport']*1000
x2, y2, z2 = feature[labels=='Leben', 0], feature[labels=='Leben', 1], sizes[labels=='Leben']*1000
x3, y3, z3 = feature[labels=='Inländisch', 0], feature[labels=='Inländisch', 1], sizes[labels=='Inländisch']*1000
x4, y4, z4 = feature[labels=='International', 0], feature[labels=='International', 1], sizes[labels=='International']*1000
x5, y5, z5 = feature[labels=='Bereich', 0], feature[labels=='Bereich', 1], sizes[labels=='Bereich']*1000
x6, y6, z6 = feature[labels=='Wirtschaft', 0], feature[labels=='Wirtschaft', 1], sizes[labels=='Wirtschaft']*1000


plt.figure(figsize=(14, 10))
plt.rcParams["font.size"]=20
plt.scatter(x0, y0, label="Unterhaltung", s=z0)
plt.scatter(x1, y1, label="Sport", s=z1)
plt.scatter(x2, y2, label="Leben", s=z2)
plt.scatter(x3, y3, label="Inländisch", s=z3)
plt.scatter(x4, y4, label="International", s=z4)
plt.scatter(x5, y5, label="Bereich", s=z5)
plt.scatter(x6, y6, label="Wirtschaft", s=z6)
plt.title("Yahoo Nachrichten")
plt.xlabel('1st dimension')
plt.ylabel('2nd dimension')
plt.legend(title="category")
plt.show()

output_22_2.png

Erwägung

―― „Unterhaltung“ und „Sport“ liegen sehr nahe beieinander. In der ersten Dimension gibt es viele überlappende Teile, in der zweiten Dimension sind sie jedoch klar voneinander getrennt. Das macht Sinn. ―― „International“ und „Inland“ sind gut voneinander getrennt, und die Wirtschaft liegt dazwischen. Das überzeugt auch. ―― „Sport“ und „Inland“ sind nahe beieinander, aber liegt es daran, dass Yahoo News mehr inländische Sportartikel als in Übersee abdeckt?

  • "Region" wird in der Nähe von "Inland" dargestellt, aber die Wahrscheinlichkeit ist gering, da es klein dargestellt ist. Sicherlich kann es schwierig sein, den Artikel "Region" zu lesen und festzustellen, ob er "inländisch" oder "regional" ist.

Ich denke, sie gruppieren sich insgesamt gut.

Dieses Mal bekam ich eine Handlung, die ordentlich nach Kategorien klassifiziert war, was möglicherweise daran liegt, dass ich das Lernen mithilfe von Kategorielabels überwacht habe. Ich denke, es ist wertvoll, ein Modell erstellen zu können, das gültige Daten, die nicht für das Training verwendet werden, sauber gruppieren kann. Wenn unbeaufsichtigtes Lernen jedoch zu ähnlichen Ergebnissen führt, finde ich es interessant. Aus diesem Grund möchte ich beim nächsten Mal versuchen, Clustering mit unbeaufsichtigtem Lernen durchzuführen! → * Fortsetzung Lernen ohne Lehrer

Verweise

Yahoo! News Clustering von Büchern von Aozora Bunko mit Doc2Vec fastText GitHub (fastText/python) Erstellen einer Mecab-Umgebung (NEologd Dictionary) mit Docker (Ubuntu) Scraping Yahoo News fastText tutorial(Text classification) [Python NumPy] So finden Sie die Kosinusähnlichkeit Grundlegendes zur Analyse von Hauptkomponenten in Python matplotlib Scatter plots with a legend