La dernière fois cet article j'ai essayé de regrouper les livres d'Aozora Bunko avec Doc2Vec. Je me suis demandé si cela fonctionnait un peu, mais honnêtement, le résultat était subtil. Donc, cette fois, au lieu de Doc2Vec, j'utiliserai une bibliothèque appelée fastText pour regrouper les articles de presse Yahoo.
fastText est une bibliothèque de traitement de langage naturel open source développée par Facebook. Il est hautement fonctionnel, a une bonne précision de prédiction et rend les prédictions encore plus rapides. Les principales fonctions sont la classification par apprentissage supervisé et la génération vectorielle de mots par apprentissage non supervisé.
Cette fois, je vais essayer de prédire la catégorie d'articles en utilisant la fonction de classification par apprentissage supervisé.
Pour plus de détails, rendez-vous sur Référence officielle de fastText! GitHub a été détaillé sur la fonction sur Python!
--Docker → ici
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
Chargez les données obtenues à l'aide du code introduit dans Scraping Yahoo News. Il y a beaucoup de nouvelles internationales parce que c'est juste après l'élection présidentielle américaine.
df = pd.read_csv('./YahooNews.csv')
df
title | category | text | |
---|---|---|---|
0 | Perte? Azato mignon Riho Yoshioka td> | Divertissement td> | Deuxième collection de photos de l'actrice Yoshioka Riho 27 pour la première fois en deux ans Collection Riho par Asami Kiyokawa Shueisha ... td> |
1 | Destination touristique hydratante "lieu sacré" du diable td> | Économie td> | La version cinématographique de la lame du diable, qui a enregistré un blockbuster inhabituel malgré l'épave corona, ne se limite pas au film édition train infini ... td> |
2 | Dentsu G Corona divise par deux son résultat opérationnel td> | Économie td> | Le Groupe Dentsu a annoncé le 10 que les résultats financiers consolidés de l'exercice clos en décembre 2020 auront 9 revenus équivalents au chiffre d'affaires ... td> |
3 | Démocrates de Hong Kong, tous démissionnaires td> | International td> | 12 Selon Beijing Joint Xinhua Electric Co., Ltd., la réunion du Comité permanent chinois pour toutes les personnes sera qualifiée de membre de l'Assemblée législative de Hong Kong 70 le 11 ... td> |
4 | Organisation professionnelle Augmentation de l'infection dans tout le pays td> | Domestique td> | La réunion du comité consultatif, une organisation experte du ministère de la Santé, du Travail et du Bien-être, qui conseille sur les mesures contre le nouveau virus corona, se tiendra le 11 ... td> |
... | ... | ... | ... |
512 | Quatre personnes poignardées autour de la Maison Blanche td> | International td> | Selon US NBC TV et d'autres, les partisans du président Trump et de l'ancien vice-président Byden se sont rassemblés lors de l'élection présidentielle américaine ... td> |
513 | Déclaration de victoire unilatérale La réaction des États-Unis est td> | International td> | FNN Prime Online Washington avant 10h00 le 4, une nuit après le jour du vote de l'élection présidentielle américaine ... td> |
514 | La croissance des actions de New York se poursuit, temporairement supérieure à 600 $ td> | International td> | Le matin du 4, alors que la bataille serrée entre les deux candidats Trump Byden se poursuit à l'élection présidentielle américaine, où les affaires courantes de New York sont ouvertes ... |
515 | Retrait de Sega Sammy Gaesen td> | Économie td> | Actions de Sega Sammy Holdings dans Sega Entertainment Tokyo, une filiale consolidée qui exploite des installations de divertissement le 4 ... td> |
516 | La Chine utilisera des armes pour la sécurité maritime td> | International td> | L'Assemblée nationale mixte du Congrès national populaire de Chine de Pékin, le 4, stipule l'autorité du Bureau de la police maritime chinoise, qui est en charge de la sécurité maritime ... td> |
517 rows × 3 columns
#Spécifiez NEologd dans le dictionnaire MeCab.
#mecab est pour l'analyse des éléments mobiles, wakati est pour le partage
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/")
#Définir une fonction pour effectuer une analyse morphologique
#Lorsque vous entrez un fichier, il génère le fichier et lorsque vous transmettez une chaîne de caractères, il renvoie une chaîne de caractères. Changez avec le fichier d'arguments.
#Si vous voulez juste séparer, mecab comme argument=Ceci peut être réalisé avec wakati.
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
#Produit la similitude cosinus entre v1 et v2.
def cos_sim(v1, v2):
return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
Il se transforme en une forme à utiliser avec fastText. fastText peut facilement effectuer un apprentissage supervisé en formatant les données sous la forme suivante. Pour plus de détails, reportez-vous au Tutoriel officiel.
__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
Effectuez le traitement suivant pour lui donner la forme ci-dessus.
① Insérez __label__
avant la catégorie de nouvelles → Store dans la liste
(2) Ecrire le texte séparément en utilisant la fonction d'analyse morphologique Mecab
définie ci-dessus → Stocker dans la liste
③ Divisez en données de train et données valides en utilisant train_test_split
④ Combinez les catégories et le texte avec train et validez et enregistrez dans un fichier
# ①
cat_lst = ['__label__' + cat for cat in df.category]
print("cat_lst[:5]:", cat_lst[:5]) #Vérifiez le contenu
print("len(cat_lst):", len(cat_lst)) #Vérifiez le nombre d'étiquettes
cat_lst [: 5]: ['__ label__ divertissement', '__ label__ économie', '__ label__ économie', '__ label__ international', '__ label__ national'] len(cat_lst): 517
# ②
text_lst = [MecabMorphologicalAnalysis(text, mecab=wakati) for text in df.text]
print("text_lst[0][:50]:", text_lst[0][:50]) #Vérifiez la première ligne
print("text_lst[1][:50]:", text_lst[1][:50]) #Vérifiez la deuxième ligne
print("len(text_lst):", len(text_lst)) #Vérifiez le nombre d'articles
text_lst [0] [: 50]: Deuxième collection de photos de l'actrice Yoshioka Riho 27 pour la première fois en deux ans Collection Riho par Asami Kiyok text_lst [1] [: 50]: La version cinématographique de Devil's Blade Infinite, qui a enregistré un blockbuster inhabituel malgré le désastre de Corona. 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])
fastText est train_supervised
et vous pouvez facilement faire un apprentissage supervisé.
Vous pouvez effectuer un traitement de n-gramme en passant un argument à wordNgrams, ou mettre hs en perte et utiliser hiérarchique softmax
pour effectuer un traitement à grande vitesse. Quoi qu'il en soit, c'est très fonctionnel! !!
L'apprentissage est excellent, mais je pense que la fonctionnalité de fastText est que vous pouvez évaluer la précision immédiatement en utilisant model.test
.
Comme indiqué ci-dessous, vous pouvez voir que la précision est assez bonne même pour des données valides.
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)
Vérifions l'exactitude du modèle en utilisant des données valides qui ne sont pas utilisées pour l'entraînement. ① Stockez le contenu des données valides dans l_strip (2) Stockez l'étiquette, le texte et la taille dans une liste. label est la catégorie de nouvelles, le texte est le corps et la taille est la probabilité que le modèle soit prédit. La partie nécessaire est extraite à l'aide d'une expression régulière. ③ Sortez les nouvelles une par une et essayez de prédire la catégorie. Les prédictions sont affichées par ordre décroissant de probabilité par le nombre d'arguments k de «prédire». Le tableau suivant montre les probabilités correspondantes. Toutes les questions sont correctes, donc c'est bien.
# ①
with open("news.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])
# ③-1
print("<{}>".format(labels[0]))
print(texts[0])
print(model.predict(texts[0], k=3))
# ③-2
print("<{}>".format(labels[1]))
print(texts[1])
print(model.predict(texts[1], k=3))
# ③-3
print("<{}>".format(labels[2]))
print(texts[2])
print(model.predict(texts[2], k=3))
Vous pouvez terminer l'analyse jusqu'à ce point, mais utilisons la fonction appelée get_sentence_vector
de fastText pour obtenir le vecteur de chaque article et effectuer une analyse plus approfondie.
(1) Obtenez un vecteur pour chaque article et enregistrez-le dans la liste.
(2) Changez le vecteur, l'étiquette et la taille en un tableau numpy. (Déjà acquis pour l'étiquette et la taille)
③ Standardisez le vecteur en utilisant Standard Scaler
④ Réduction de dimension à l'aide de l'analyseur de composants principaux PCA
⑤ Calculez la similitude pour chaque article en utilisant la fonction cos_sim
définie ci-dessus. Les articles de la même catégorie présentent la plus grande similitude.
⑥ Tracé bidimensionnel du vecteur. La taille du point change en fonction de la valeur des tailles. (les tailles stockent la prévisibilité.)
# ①
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])
# ⑤-2
print("<{}><{}>".format(labels[1], labels[2]))
cos_sim(vectors[1], vectors[2])
# ⑤-3
print("<{}><{}>".format(labels[0], labels[2]))
cos_sim(vectors[0], vectors[2])
# ⑥
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()
―― «Divertissement» et «Sports» sont très proches l'un de l'autre. Il y a de nombreuses parties qui se chevauchent dans la première dimension, mais elles sont clairement séparées dans la deuxième dimension. C'est logique. ―― «International» et «domestique» sont bien séparés, et l'économie se situe entre les deux. C'est également convaincant. ―― «Sports» et «domestique» sont proches, mais est-ce parce que Yahoo News couvre plus d'articles de sport nationaux qu'à l'étranger?
Je pense qu'ils se regroupent bien dans l'ensemble.
Cette fois, j'ai obtenu une intrigue qui a été soigneusement classée par catégorie, ce qui peut être dû au fait que j'ai fait un apprentissage supervisé en utilisant des étiquettes de catégorie. Je pense qu'il est utile de pouvoir créer un modèle qui peut regrouper proprement des données valides qui ne sont pas utilisées pour la formation. Cependant, si l'apprentissage non supervisé produit des résultats similaires, je pense que c'est intéressant. C'est pourquoi j'aimerais essayer le clustering en utilisant l'apprentissage non supervisé la prochaine fois! → * Suite Apprendre sans enseignant
Yahoo! News Regroupement des livres d'Aozora Bunko avec Doc2Vec fastText GitHub (fastText/python) Création d'un environnement mecab (dictionnaire NEologd) avec Docker (ubuntu) Scraping Yahoo News fastText tutorial(Text classification) [Python NumPy] Comment trouver la similitude cosinus Comprendre l'analyse des composants principaux en Python matplotlib Scatter plots with a legend