[PYTHON] fastText est assez incroyable! "Yahoo! News" Clustering-Learning sans enseignants-

Dernière fois a utilisé la méthode train_supervised de fastText pour l'apprentissage supervisé et le regroupement des données d'articles de Yahoo News. Cette fois, utilisons la méthode train_unsupervised de fastText pour effectuer un apprentissage non supervisé et analyser si elle peut être regroupée aussi bien que la dernière fois.

Environnement de développement

Début de la mise en œuvre

① Charger la bibliothèque (2) Créez un fichier appelé utility.py pour stocker les fonctions créées jusqu'à présent. À partir de là, chargez les fonctions dont vous avez besoin cette fois. ③ Utilisez la fonction YN pour obtenir des articles Yahoo News. Vous pouvez obtenir environ 500 articles sur environ 10. Cette fonction est introduite sur ici.

# ①
import pandas as pd, numpy as np
from sklearn.model_selection import train_test_split
import fasttext
from sklearn import preprocessing
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import japanize_matplotlib
import re
# ②
import utility as util 
wakati = util.wakati
M2A = util.MecabMorphologicalAnalysis
YN = util.YahooNews
cos_sim = util.cos_sim
# ③
df = YN(1000)
# df = pd.read_csv('./YahooNews.csv') #Si vous avez déjà acquis les données, lisez-les et lancez l'analyse!
df

[====================] 502 articles

title category text
0 Transféré dans une société holding à Pana 22 Économie Bloomberg Panasonic a annoncé le 13 qu'il passerait à une structure de société holding à partir d'avril 2022 ...
1 Plus de 1700 personnes infectées dans tout le pays, le nombre le plus élevé jamais enregistré Domestique Nippon News Network NNN La nouvelle personne infectée par le nouveau virus corona le 13e jour est N ...
2 Respect du mariage de Mako pour Leurs Majestés Domestique Le bureau de Miyauchi sera avec Mako Akishino, la fille aînée de M. et Mme Akishino, et Kei Komuro, un camarade de classe de l'ère ICU de l'Université chrétienne internationale, 29 ...
3 Les conseils de M. Trump sont partagés International Le président de CNN, Trump, qui est sûr d'être vaincu à l'élection présidentielle américaine, est celui qui a le plus confiance en lui alors qu'il élabore la stratégie du prochain mouvement ...
4 Ministre des affaires étrangères "Je veux étendre GoTo" Domestique CopyrightC Japan News Network All rights reser...
... ... ... ...
497 M. Byden au discours télévisé pour le public International Actualités AFP Le candidat à la présidence du Parti démocrate américain Joe Biden est dans la nuit du 6 et le matin du 7, heure du Japon ...
498 Alertes aux affrontements et aux émeutes aux États-Unis International All Nippon NewsNetworkANN Le vainqueur de l'élection présidentielle est incertain aux États-Unis ...
499 A accepté de reprendre le trafic commercial entre le Japon et la Chine Domestique Le trafic des hommes d'affaires, que les gouvernements japonais et chinois ont limité pour contrer le nouveau virus corona, reprendra au milieu de ce mois ...
500 Recomptage de l'élection présidentielle en Géorgie International Actualité AFP Le démocrate Joe Biden à l'élection présidentielle américaine est le républicain Donald Tran ...
501 Le président du CIO, Bach, viendra au Japon le 15 Sports Thomas Bach du Comité International Olympique CIO sur les Jeux Paralympiques de Tokyo reportés à l'été prochain ...

502 rows × 3 columns

À propos du sous-mot

Je ne l'ai pas mentionné la dernière fois, mais cette fois, je vais considérer le sous-mot, qui est une caractéristique majeure de fastText. Un sous-mot consiste à diviser un mot en «sous-mots» plus petits pour saisir la pertinence des mots. Par exemple, vous pouvez apprendre la pertinence de mots qui ont une partie commune telle que «Go» et «Going». L'application d'un sous-mot a amélioré la précision, je vais donc l'utiliser. Au contraire, il semble qu'il y ait un effet néfaste sur la langue katata. Il peut être implémenté en passant maxn et minn aux arguments de train_supervised et train_unsupervised. Les valeurs par défaut sont différentes pour train_supervised et train_unsupervised. Pour plus d'informations, accédez à GitHub.

Apprentissage supervisé (train_supervised)

Tout d'abord, à titre de comparaison, exécutez le contenu de Dernière fois à la fois.

#Stocker la catégorie et le corps dans la liste respectivement
cat_lst = ['__label__' + cat for cat in df.category]
text_lst = [M2A(text, mecab=wakati) for text in df.text]

#Divisé en train et valide
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
)

#Créer un train et des fichiers valides
with open('./s_train', mode='w') as f:
    for i in range(len(text_train)):
        f.write(cat_train[i] + ' '+ text_train[i])
        
with open('./s_valid', mode='w') as f:
    for i in range(len(text_valid)):
        f.write(cat_valid[i] + ' ' + text_valid[i])

#Apprentissage de modèle
model = fasttext.train_supervised(input='./s_train', lr=0.5, epoch=500, minn=3, maxn=5,
                                  wordNgrams=3, loss='ova', dim=300, bucket=200000)

#Vérifiez la précision du modèle
# print("TrainData:", model.test('./s_news_train'))
print("ValidData:", model.test('./s_valid'))

#Préparation d'un graphique bidimensionnel à l'aide de données valides
with open("./s_valid") as f:
    l_strip = [s.strip() for s in f.readlines()] # strip()Supprimer les caractères de saut de ligne à l'aide de
    
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])

#Génération de vecteur à partir d'un corps d'article valide
vectors = []
for t in texts:
    vectors.append(model.get_sentence_vector(t))

#Convertir en numpy
vectors = np.array(vectors)
labels = np.array(labels)
sizes = np.array(sizes)

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

#Réduction de dimension
pca = PCA()
pca.fit(vectors_std)
feature = pca.transform(vectors_std)
feature = feature[:, :2]

#terrain
x0, y0, z0 = feature[labels=='Divertissement', 0], feature[labels=='Divertissement', 1], sizes[labels=='Divertissement']*1000
x1, y1, z1 = feature[labels=='Des sports', 0], feature[labels=='Des sports', 1], sizes[labels=='Des sports']*1000
x2, y2, z2 = feature[labels=='la vie', 0], feature[labels=='la vie', 1], sizes[labels=='la vie']*1000
x3, y3, z3 = feature[labels=='National', 0], feature[labels=='National', 1], sizes[labels=='National']*1000
x4, y4, z4 = feature[labels=='international', 0], feature[labels=='international', 1], sizes[labels=='international']*1000
x5, y5, z5 = feature[labels=='surface', 0], feature[labels=='surface', 1], sizes[labels=='surface']*1000
x6, y6, z6 = feature[labels=='Économie', 0], feature[labels=='Économie', 1], sizes[labels=='Économie']*1000

plt.figure(figsize=(14, 10))
plt.rcParams["font.size"]=20
plt.scatter(x0, y0, label="Divertissement", s=z0)
plt.scatter(x1, y1, label="Des sports", s=z1)
plt.scatter(x2, y2, label="la vie", s=z2)
plt.scatter(x3, y3, label="National", s=z3)
plt.scatter(x4, y4, label="international", s=z4)
plt.scatter(x5, y5, label="surface", s=z5)
plt.scatter(x6, y6, label="Économie", s=z6)
plt.title("Yahoo Actualités")
plt.xlabel('1st dimension')
plt.ylabel('2nd dimension')
plt.legend(title="category")
plt.show()
ValidData: (101, 0.801980198019802, 0.801980198019802)

output_5_1.png

Apprentissage non supervisé (train_unsupervised)

Préparation des données

Aucune étiquette n'est requise pour l'apprentissage non supervisé, il vous suffit donc d'écrire les données pour l'apprentissage. (1) La catégorie est stockée dans cat_lst, et les phrases sont séparées par la fonction M2A et stockées dans text_lst. (2) Divisez en données de train et données valides. ③ Enregistrez le texte dans un fichier.

# ①
cat_lst = [cat for cat in df.category]
text_lst = [M2A(text, mecab=wakati) for text in df.text]

# ②
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('./u_train', mode='w') as f:
    for i in range(len(text_train)):
        f.write(text_train[i])
        
with open('./u_valid', mode='w') as f:
    for i in range(len(text_valid)):
        f.write(text_valid[i])

Apprentissage de modèle

L'apprentissage non supervisé utilise train_unsupervised.

model = fasttext.train_unsupervised('./u_train', epoch=500, lr=0.01, minn=3, maxn=5, dim=300)

analyse des données de train

Comparaison de la similitude des vecteurs de phrases

Utilisez le modèle entraîné pour calculer la similitude du contenu de l'article. ① Utilisez la méthode get_sentence_vector pour générer un vecteur de phrase à partir du modèle entraîné. ② Affichez la catégorie d'article et le texte. (3) Calculez la similitude cosinus en utilisant la fonction cos_sim lue ci-dessus.

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

# ②
print("<{}>".format(cat_train[0]))
print(text_train[0][:200], end="\n\n")
print("<{}>".format(cat_train[1]))
print(text_train[1][:200], end="\n\n")
print("<{}>".format(cat_train[2]))
print(text_train[2][:200], end="\n\n")

# ③
print("<{}><{}>".format(cat_train[0], cat_train[1]), cos_sim(vectors[0], vectors[1]))
print("<{}><{}>".format(cat_train[1], cat_train[2]), cos_sim(vectors[1], vectors[2]))
print("<{}><{}>".format(cat_train[0], cat_train[2]), cos_sim(vectors[0], vectors[2]))
Shigeru Omi, président du sous-comité gouvernemental de lutte contre le nouveau virus Corona, président de l'Organisation régionale de promotion de la fonction médicale a tenu une conférence de presse urgente le 9, et il ne fait aucun doute que le nombre d'infections augmente dans tout le pays. Il s'est maintenant plaint que cela conduirait probablement à une tendance d'expansion graduelle mais rapide et comme une recommandation urgente au gouvernement 1 jusqu'à présent. Le sénateur Kawai, qui a été accusé d'avoir pris le contrôle de l'élection de la Chambre des représentants en juillet de l'année dernière, a violé la loi sur l'élection de l'emploi public. Lors du premier procès, il a affirmé à plusieurs reprises que c'était une célébration de l'élection et une sympathie pour l'équipe, et il a déclaré que ce n'était pas illégal. Le président américain Donald Trump est occupé à répondre à M. Trump, qui n'admet pas sa défaite à l'élection présidentielle, révélant qu'il a limogé le secrétaire à la Défense Mark Esper dans un message sur Twitter Twitter le 9. Mark Esper a posté dans un post de M. Trump, encore secoué par l'administration.

0.91201633 0.9294117 0.9201762

Tracé 2D

Tracons enfin en deux dimensions. ① Convertir respectivement le vecteur et l'étiquette en tableau numpy ② Standardiser le vecteur ③ Réduction dimensionnelle du vecteur à l'aide de l'ACP ④ Tracez avec matplotlib. Contrairement à train_supervised, vous ne pouvez pas obtenir la probabilité de la prédiction, donc tous les graphiques ont la même taille.

# ①
vectors = np.array(vectors)
labels = np.array(cat_train)


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


# ③
pca = PCA()
pca.fit(vectors_std)
feature = pca.transform(vectors_std)
feature = feature[:, :2]


# ④
x0, y0 = feature[labels=='Divertissement', 0], feature[labels=='Divertissement', 1]
x1, y1 = feature[labels=='Des sports', 0], feature[labels=='Des sports', 1]
x2, y2 = feature[labels=='la vie', 0], feature[labels=='la vie', 1]
x3, y3 = feature[labels=='National', 0], feature[labels=='National', 1]
x4, y4 = feature[labels=='international', 0], feature[labels=='international', 1]
x5, y5 = feature[labels=='surface', 0], feature[labels=='surface', 1]
x6, y6 = feature[labels=='Économie', 0], feature[labels=='Économie', 1]

plt.figure(figsize=(14, 10))
plt.rcParams["font.size"]=20
plt.scatter(x0, y0, label="Divertissement", s=300)
plt.scatter(x1, y1, label="Des sports", s=300)
plt.scatter(x2, y2, label="la vie", s=300)
plt.scatter(x3, y3, label="National", s=300)
plt.scatter(x4, y4, label="international", s=300)
plt.scatter(x5, y5, label="surface", s=300)
plt.scatter(x6, y6, label="Économie", s=300)
plt.title("Yahoo Actualités")
plt.xlabel('1st dimension')
plt.ylabel('2nd dimension')
plt.legend(title="category")
plt.show()

output_13_0.png

analyse de données valides

Ensuite, regroupons les données valides. Le contenu est le même que celui de l'analyse des données de train, donc l'explication est omise.

vectors = []
for t in text_valid:
    vectors.append(model.get_sentence_vector(t.strip()))

print("<{}>".format(cat_valid[0]))
print(text_valid[0][:200], end="\n\n")
print("<{}>".format(cat_valid[1]))
print(text_valid[1][:200], end="\n\n")
print("<{}>".format(cat_valid[2]))
print(text_valid[2][:200], end="\n\n")
print("<{}><{}>".format(cat_valid[0], cat_valid[1]), cos_sim(vectors[0], vectors[1]))
print("<{}><{}>".format(cat_valid[1], cat_valid[2]), cos_sim(vectors[1], vectors[2]))
print("<{}><{}>".format(cat_valid[0], cat_valid[2]), cos_sim(vectors[0], vectors[2]))
KNT-CT Holdings HD, propriétaire de Kinki Japan Tourist, a annoncé le 11 qu'il réduirait un tiers des quelque 7 000 employés du groupe d'ici mars 2025 en raison d'une retraite volontaire, etc. 138 dans tout le pays Les deux tiers des magasins seront fermés d'ici mars 2010 en raison d'une forte baisse de la demande de voyages en raison de la propagation de la nouvelle infection à coronavirus

<Région> Le 9 novembre, il a été constaté que le nombre de personnes infectées par le nouveau virus corona à Hokkaido devait dépasser 200, le nombre le plus élevé jamais enregistré.Plus de 100 personnes pour le cinquième jour consécutif devraient enfin atteindre le niveau de 200 et la propagation de l'infection est attendue. Il semble qu'un nouveau cluster ait été confirmé: à Hokkaido, 119 personnes infectées ont été confirmées le 5.

Hitachi, Ltd. a annoncé le 28 décembre qu'elle encouragerait l'acquisition de congés payés jusqu'au 8 janvier de l'année prochaine en réponse à la politique du gouvernement de demander l'acquisition distribuée de vacances pour les vacances de fin d'année et du Nouvel An, généralement à partir du 30 décembre. Jusqu'au 3 janvier, environ 150 000 personnes, y compris les salariés des sociétés du groupe, prendront des vacances pour éviter d'organiser en interne des événements de fin d'année et de nouvel an et des réunions inutiles et non urgentes.

<Région> 0.9284181 <Région> 0,90896636 0,9533808

vectors = np.array(vectors)
labels = np.array(cat_valid)

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

pca = PCA()
pca.fit(vectors_std)
feature = pca.transform(vectors_std)
feature = feature[:, :2]

x0, y0 = feature[labels=='Divertissement', 0], feature[labels=='Divertissement', 1]
x1, y1 = feature[labels=='Des sports', 0], feature[labels=='Des sports', 1]
x2, y2 = feature[labels=='la vie', 0], feature[labels=='la vie', 1]
x3, y3 = feature[labels=='National', 0], feature[labels=='National', 1]
x4, y4 = feature[labels=='international', 0], feature[labels=='international', 1]
x5, y5 = feature[labels=='surface', 0], feature[labels=='surface', 1]
x6, y6 = feature[labels=='Économie', 0], feature[labels=='Économie', 1]

plt.figure(figsize=(14, 10))
plt.rcParams["font.size"]=20
plt.scatter(x0, y0, label="Divertissement", s=300)
plt.scatter(x1, y1, label="Des sports", s=300)
plt.scatter(x2, y2, label="la vie", s=300)
plt.scatter(x3, y3, label="National", s=300)
plt.scatter(x4, y4, label="international", s=300)
plt.scatter(x5, y5, label="surface", s=300)
plt.scatter(x6, y6, label="Économie", s=300)
plt.title("Yahoo Actualités")
plt.xlabel('1st dimension')
plt.ylabel('2nd dimension')
plt.legend(title="category")
plt.show()

output_16_0.png

Considération

Apprendre avec un enseignant

―― En adoptant le sous-mot, la précision a été encore améliorée depuis le moment de l'article précédent. 0,75 → 0,80 ――Semblable à la dernière fois, il existe de nombreuses parties qui se chevauchent entre le «divertissement» et le «sport» dans la première dimension, mais elles sont clairement séparées dans la seconde dimension. Je suis convaincu que «divertissement» et «sport» sont proches l'un de l'autre. ―― «International» et «domestique» sont bien séparés et il existe une «économie» entre eux. Comme pour la dernière fois, c'est également convaincant. ――Dans l'article précédent, la "région" n'était pas claire, mais cette fois les caractéristiques sont fortes dans le sens bidimensionnel. «Dans l'ensemble, il se sent plus clairement classé que la dernière fois.

Apprendre sans professeur

données de train

  • Il y a de nombreuses parties qui se chevauchent pour chaque catégorie. ―― «International» et «domestique» sont clairement séparés. «C'était la tendance habituelle de dire que« l'économie »se situe entre« internationale »et« domestique », mais cette fois, elle a été tracée dans un large éventail. ―― «Divertissement» et «Sports» se chevauchent beaucoup, mais dans la direction unidimensionnelle, «Divertissement» était légèrement à droite et «Sports» était à gauche. ―― «Région» n'a pratiquement aucun chevauchement avec «international», ce qui est convaincant. Il y a un chevauchement considérable entre «domestique» et «économie».

données valides

――Il y a peu de parties qui se chevauchent et il a été soigneusement classé dans son ensemble. DomesticIl y a «domestique» au centre, «international» à gauche et «économie» au centre. C'est assez différent qu'avant. «Bien que« sports »et« divertissements »soient assez proches cette fois-ci, les« sports »étaient répartis sur une large gamme. ―― La «région» est divisée en deux. Cette tendance peut être vue même par les apprenants supervisés, il peut donc y avoir certains critères.

Cette fois, je l'ai analysé en apprenant sans professeur, mais j'ai été surpris que le classement soit réussi. Puisqu'il n'y a pas d'étiquette, cela signifie que vous pouvez obtenir "international" ou "sports" à partir du texte. Je suis très curieux de savoir quel type de fonctionnalités le modèle acquiert et reflète réellement dans la création de vecteurs. Je veux creuser plus profondément dans fastText! !! !!

Références

Yahoo! News fastText Explication de l'installation et de l'utilisation de fastText publiée par Facebook Effets indésirables du sous-mot fastText fastText tutorial(Word representations) GitHub (fastText/python) fastText est incroyable! Clustering "Yahoo! News"