[PYTHON] Analyse des composants principaux avec le corpus d'actualités Livedoor - Pratique--

À propos de cet article

Utilisez le Livedoor News Corpus pour contester l'analyse des composants principaux des données textuelles. Dernière fois, comme préparation avant analyse, le texte a été décomposé en éléments morphologiques et résumé sous forme de tableau.

Nous utiliserons ce tableau pour effectuer une analyse en composantes principales. Même s'il y a beaucoup de mots pondérés, c'est difficile, je vais donc me limiter aux 5 mots les plus fréquemment utilisés pour la nomenclature générale et la classification d'articles.

Vous pouvez également vous référer au code ci-dessous. https://github.com/torahirod/TextDataPCA

Tout d'abord, vérifiez les 5 mots les plus fréquemment utilisés pour chaque catégorie d'article.

Vérifiez les 5 mots les plus fréquents pour chaque catégorie d'article

python


import pandas as pd
import numpy as np

#Lire les données texte collectées dans un fichier en préparation
df = pd.read_csv('c:/temp/livedoor_corpus.csv')

#Les mots des parties sont réduits à la nomenclature générale
df = df[df['Partie'].str.startswith('nom,Général')].reset_index(drop=True)

#Agréger la fréquence d'apparition des mots pour chaque catégorie d'article
gdf = pd.crosstab([df['Classification des articles'],df['mot'],df['Partie']],
                  'nombre',
                  aggfunc='count',
                  values=df['mot']
                 ).reset_index()

#Classement par fréquence décroissante d'apparition des mots pour chaque catégorie d'article
gdf['Classement'] = gdf.groupby(['Classification des articles'])['nombre'].rank('dense', ascending=False)
gdf.sort_values(['Classification des articles','Classement'], inplace=True)

#Limitez-vous aux 5 mots les plus fréquemment utilisés pour chaque catégorie d'article
gdf = gdf[gdf['Classement'] <= 5]

#Vérifiez les 5 mots les plus fréquents pour chaque catégorie d'article
for k in gdf['Classification des articles'].unique():
    display(gdf[gdf['Classification des articles']==k])

** ・ Dokujotsushin ** image.png Les mots «femme» et «femme» sont bien classés car ils sont appelés «communication allemande».

** ・ it-life-hack ** image.png Dans les hacks de la vie informatique, des mots tels que «personnes» et «applications» semblent certainement être très pertinents. Qu'est-ce qu'un "produit"? Cela peut être quelque chose comme un gadget.

** ・ Kanen-chan e l ** image.png Dans le canal des appareils électroménagers, des mots tels que «sujet», «vente» et «vidéo» apparaissent fréquemment. Qu'est-ce qu'une «personne»? C'est un peu étrange qu'il apparaisse fréquemment dans la classification des articles du canal des appareils ménagers.

** ・ livingoor-homme ** image.png Live Door-Om est un article pour hommes. Le "golf" est-il un goût de gentleman? Il est également intéressant de noter que le «revenu annuel» est dans le Top 5.

** ・ entrée vidéo ** image.png Comme son nom l'indique, des mots tels que «film» et «travail» sont bien classés dans les films et les divertissements.

** ・ pêche ** image.png C'est aussi un article pour les femmes. Il semble difficile de le séparer de la communication allemande.

** ・ smax ** image.png Esmax semble être un article lié aux smartphones et aux mobiles. Il semble y avoir un piratage informatique et une couverture de contenu.

** ・ montre de sport ** image.png Les montres de sport sont comme "joueurs", "football" et "baseball". Je ne sais pas ce qu'est le "T". Je vérifierai à quoi ressemble la phrase plus tard.

** ・ sujet-actualités ** image.png Topic News était une image du traitement de divers articles, mais il peut y avoir de nombreux articles qui décrivent la réaction du public aux nouvelles à partir de mots tels que «net», «babillard» et «voix».

Vérifiez les phrases environnantes du mot qui vous tient à cœur

Auparavant, je craignais que des mots qui semblaient n'avoir aucun rapport dans la montre de sport arrivent en tête, alors vérifions-le.

#Définissez le mot qui vous intéresse
word = 'T'

df = pd.read_csv('c:/temp/livedoor_corpus.csv')

#Obtenez la position d'apparence du mot qui vous intéresse
idxes = df[(df['mot'] == word)
          &(df['Partie'].str.startswith('nom,Général'))].index.values.tolist()

#Taille de la fenêtre (définir le nombre de mots avant et après le mot qui vous intéresse)
ws = 20

#Obtenez les phrases environnantes du mot qui vous tient à cœur
l = []
for i, r in df.loc[idxes, :].iterrows():
    s = i - ws
    e = i + ws
    tmp = df.loc[s:e, :]
    tmp = tmp[tmp['nom de fichier']==r['nom de fichier']]
    lm = list(map(str, tmp['mot'].values.tolist()))
    ss = ''.join(lm)
    l.append([r['Classification des articles'],r['nom de fichier'],r['mot'],ss])
rdf = pd.DataFrame(np.array(l))
rdf.columns = ['Classification des articles','nom de fichier','mot','mot周辺文']

rdf.head(5)

image.png Apparemment, la seule lettre "T" fait partie de l'URL qui représente le temps. Si vous excluez l'URL, les 4e à 5e mots sont susceptibles de changer, donc après avoir exclu l'URL, vérifiez à nouveau le Top 5.

Traitement des données textuelles

Modifiez un peu le code de préparation, supprimez les espaces, les sauts de ligne et les URL, puis additionnez la morphologie de chaque fichier. Pour supprimer l'URL, regardez le résultat de la phrase autour du mot, et il semble que le type d'URL soit décidé dans une certaine mesure, je vais donc essayer de l'exclure avec une norme approximative. Ce n'est pas un beau processus qui supprime complètement la partie URL.

import pandas as pd
import numpy as np
import pathlib
import glob
import re

from janome.tokenizer import Tokenizer
tnz = Tokenizer()

pth = pathlib.Path('c:/temp/text')

l = []
for p in pth.glob('**/*.txt') :
    #Ignorer sauf les données d'article
    if p.name in ['CHANGES.txt','README.txt','LICENSE.txt']:
        continue
    
    #Ouvrez les données de l'article et analysez la morphologie avec janome ⇒ Conserver dans la liste sous forme d'un mot par ligne
    with open(p,'r',encoding='utf-8-sig') as f :
        s = f.read()
        s = s.replace(' ', '')
        s = s.replace(' ', '')
        s = s.replace('\n', '')
        s = re.sub(r'http://.*\+[0-9]{4}', '', s)
        #Supprimer les espaces, les sauts de ligne, les URL
        l.extend([[p.parent.name, p.name, t.surface, t.part_of_speech] for t in tnz.tokenize(s)])

#Convertir la liste en bloc de données
df = pd.DataFrame(np.array(l))

#Donnez le nom de la colonne
df.columns = ['Classification des articles','nom de fichier','mot','Partie']

#Trame de données de sortie CSV
df.to_csv('c:/temp/livedoor_corpus.csv', index=False)

Reconfirmez les 5 mots les plus fréquemment utilisés dans la montre de sport

** ・ montre de sport ** image.png Par rapport à avant le traitement, les 4e à 5e mots ont changé. «Équipe» semble être lié au sport.

Nous avons pu confirmer les 5 mots les plus fréquemment utilisés pour chaque catégorie d'article. Nous effectuerons l'analyse en composantes principales avec ces derniers comme poids.

Analyse en composantes principales (2D)

#Contient les 5 mots les plus fréquemment utilisés pour chaque catégorie d'article acquise dans la cellule supérieure sous forme de liste
words = gdf['mot'].unique().tolist()

df = pd.read_csv('c:/temp/livedoor_corpus.csv')
df = df[df['Partie'].str.startswith('nom,Général')].reset_index(drop=True)
df = df[df['mot'].isin(words)]

#Obtenez un tableau croisé des 5 mots les plus fréquents par classification de fichier et d'article
xdf = pd.crosstab([df['Classification des articles'],df['nom de fichier']],df['mot']).reset_index()
#Conserver sous forme de liste pour une sortie ultérieure sous forme d'étiquette de chargement de facteur
cls = xdf.columns.values.tolist()[2:]

#Un numéro de classification est attribué à chaque classification d'article pour un affichage graphique ultérieur.
ul = xdf['Classification des articles'].unique()
def _fnc(x):
    return ul.tolist().index(x)
xdf['Numéro de classe'] = xdf['Classification des articles'].apply(lambda x : _fnc(x))

#Préparation pour trouver le composant principal
data = xdf.values
labels = data[:,0]
d = data[:, 2:-1].astype(np.int64)
k = data[:, -1].astype(np.int64)

#Standardisation des données * L'écart type est calculé par l'écart type non biaisé
X = (d - d.mean(axis=0)) / d.std(ddof=1,axis=0)

#Trouvez la matrice de corrélation
XX = np.round(np.dot(X.T,X) / (len(X) - 1), 2)

#Trouver la valeur propre et le vecteur de la valeur propre de la matrice de corrélation
w, V = np.linalg.eig(XX)

#Trouvez le premier composant principal
z1 = np.dot(X,V[:,0])

#Trouvez le deuxième composant principal
z2 = np.dot(X,V[:,1])

#Générer des objets pour les graphiques
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(111)

#Insérer des lignes de quadrillage
ax.grid()

#Limite des données à dessiner
lim = [-10.0, 10.0]
ax.set_xlim(lim)
ax.set_ylim(lim)

#Amenez les axes gauche et inférieur au milieu
ax.spines['bottom'].set_position(('axes', 0.5))
ax.spines['left'].set_position(('axes', 0.5))
#Effacer les axes droit et supérieur
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

#Ajuster l'espacement des échelles des axes
ticks = np.arange(-10.0, 10.0, 1.0)
ax.set_xticks(ticks)
ax.set_yticks(ticks)

#Ajouter une étiquette d'axe, ajuster la position
ax.set_xlabel('Z1', fontsize=16)
ax.set_ylabel('Z2', fontsize=16, rotation=0)
ax.xaxis.set_label_coords(1.02, 0.49)
ax.yaxis.set_label_coords(0.5, 1.02)

from matplotlib.colors import ListedColormap
colors = ['red','blue','gold','olive','green','dodgerblue','brown','black','grey']
cmap = ListedColormap(colors)
a = np.array(list(zip(z1,z2,k,labels)))
df = pd.DataFrame({'z1':pd.Series(z1, dtype='float'),
                   'z2':pd.Series(z2, dtype='float'),
                   'k':pd.Series(k, dtype='int'),
                   'labels':pd.Series(labels, dtype='str'),
                  })

#Tracé avec des couleurs différentes pour chaque catégorie d'article
for l in df['labels'].unique():
    d = df[df['labels']==l]
    ax.scatter(d['z1'],d['z2'],c=cmap(d['k']),label=l)
    ax.legend()

#dessin
plt.show()

image.png En regardant les résultats, selon la classification de l'article, les points sont rassemblés à des positions proches, mais il y a de nombreux points qui se chevauchent et il est difficile de comprendre les limites de chaque classification d'article.

Ensuite, vérifions le chargement des facteurs.

#Coordonnées avec le vecteur propre correspondant à la plus grande valeur propre sur l'axe horizontal et le vecteur propre correspondant à la deuxième plus grande valeur propre sur l'axe vertical.
V_ = np.array([(V[:,0]),V[:,1]]).T
V_ = np.round(V_,2)

#Données pour le dessin graphique
z1 = V_[:,0]
z2 = V_[:,1]

#Générer des objets pour les graphiques
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(111)

#Insérer des lignes de quadrillage
ax.grid()

#Limite des données à dessiner
lim = [-0.4, 0.4]
ax.set_xlim(lim)
ax.set_ylim(lim)

#Amenez les axes gauche et inférieur au milieu
ax.spines['bottom'].set_position(('axes', 0.5))
ax.spines['left'].set_position(('axes', 0.5))
#Effacer les axes droit et supérieur
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

#Ajuster l'espacement des échelles des axes
ticks = np.arange(-0.4, 0.4, 0.05)
ax.set_xticks(ticks)
ax.set_yticks(ticks)

#Ajouter une étiquette d'axe, ajuster la position
ax.set_xlabel('Z1', fontsize=16)
ax.set_ylabel('Z2', fontsize=16, rotation=0)
ax.xaxis.set_label_coords(1.02, 0.49)
ax.yaxis.set_label_coords(0.5, 1.02)

#Graphique de données
for (i,j,k) in zip(z1,z2,cls):
    ax.plot(i,j,'o')
    ax.annotate(k, xy=(i, j),fontsize=10)
    
#dessin
plt.show()

image.png En comparant avec le résultat de l'analyse des composants principaux précédemment, il semble que le mot lié à la classification des articles vient au groupe de chaque classification d'articles et à la position similaire.

Analyse en composantes principales (3D)

#Contient les 5 mots les plus fréquemment utilisés pour chaque catégorie d'article acquise dans la cellule supérieure sous forme de liste
words = gdf['mot'].unique().tolist()

df = pd.read_csv('c:/temp/livedoor_corpus.csv')
df = df[df['Partie'].str.startswith('nom,Général')].reset_index(drop=True)
df = df[df['mot'].isin(words)]

#Obtenez un tableau croisé des 5 mots les plus fréquents par classification de fichier et d'article
xdf = pd.crosstab([df['Classification des articles'],df['nom de fichier']],df['mot']).reset_index()
#Conserver sous forme de liste pour une sortie ultérieure sous forme d'étiquette de chargement de facteur
cls = xdf.columns.values.tolist()[2:]

#Un numéro de classification est attribué à chaque classification d'article pour un affichage graphique ultérieur.
ul = xdf['Classification des articles'].unique()
def _fnc(x):
    return ul.tolist().index(x)
xdf['Numéro de classe'] = xdf['Classification des articles'].apply(lambda x : _fnc(x))

#Préparation pour trouver le composant principal
data = xdf.values
labels = data[:,0]
d = data[:, 2:-1].astype(np.int64)
k = data[:, -1].astype(np.int64)

#Standardisation des données * L'écart type est calculé par l'écart type non biaisé
X = (d - d.mean(axis=0)) / d.std(ddof=1,axis=0)

#Trouvez la matrice de corrélation
XX = np.round(np.dot(X.T,X) / (len(X) - 1), 2)

#Trouver la valeur propre et le vecteur de la valeur propre de la matrice de corrélation
w, V = np.linalg.eig(XX)

#Trouvez le premier composant principal
z1 = np.dot(X,V[:,0])

#Trouvez le deuxième composant principal
z2 = np.dot(X,V[:,1])

#Trouvez le troisième composant principal
z3 = np.dot(X,V[:,2])

#Générer des objets pour les graphiques
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(111, projection='3d')

#Insérer des lignes de quadrillage
ax.grid()

#Limite des données à dessiner
lim = [-10.0, 10.0]
ax.set_xlim(lim)
ax.set_ylim(lim)

#Amenez les axes gauche et inférieur au milieu
ax.spines['bottom'].set_position(('axes', 0.5))
ax.spines['left'].set_position(('axes', 0.5))
#Effacer les axes droit et supérieur
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

#Ajuster l'espacement des échelles des axes
ticks = np.arange(-10.0, 10.0, 1.0)
ax.set_xticks(ticks)
ax.set_yticks(ticks)

#Ajouter une étiquette d'axe, ajuster la position
ax.set_xlabel('Z1', fontsize=16)
ax.set_ylabel('Z2', fontsize=16, rotation=0)
ax.xaxis.set_label_coords(1.02, 0.49)
ax.yaxis.set_label_coords(0.5, 1.02)

from matplotlib.colors import ListedColormap
colors = ['red','blue','gold','olive','green','dodgerblue','brown','black','grey']
cmap = ListedColormap(colors)

a = np.array(list(zip(z1,z2,z3,k,labels)))
df = pd.DataFrame({'z1':pd.Series(z1, dtype='float'),
                   'z2':pd.Series(z2, dtype='float'),
                   'z3':pd.Series(z3, dtype='float'),
                   'k':pd.Series(k, dtype='int'),
                   'labels':pd.Series(labels, dtype='str'),
                  })

for l in df['labels'].unique():
    d = df[df['labels']==l]
    ax.scatter(d['z1'],d['z2'],d['z3'],c=cmap(d['k']),label=l)
    ax.legend()

#dessin
plt.show()

image.png

Même si vous le regardez en trois dimensions, chaque point se chevauche toujours et il semble difficile de tracer une ligne de démarcation nette. Cependant, puisque vous pouvez faire pivoter le graphique, il est intéressant de le voir en le faisant pivoter.

image.png Je l'ai retourné.

Chargement factoriel (3D)

#Coordonnées avec le vecteur propre correspondant à la plus grande valeur propre sur l'axe horizontal et le vecteur propre correspondant à la deuxième plus grande valeur propre sur l'axe vertical.
V_ = np.array([(V[:,0]),V[:,1],V[:,2]]).T
V_ = np.round(V_,2)

#Données pour le dessin graphique
z1 = V_[:,0]
z2 = V_[:,1]
z3 = V_[:,2]

#Générer des objets pour les graphiques
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(111, projection='3d')

#Insérer des lignes de quadrillage
ax.grid()

#Limite des données à dessiner
lim = [-0.4, 0.4]
ax.set_xlim(lim)
ax.set_ylim(lim)

#Amenez les axes gauche et inférieur au milieu
ax.spines['bottom'].set_position(('axes', 0.5))
ax.spines['left'].set_position(('axes', 0.5))
#Effacer les axes droit et supérieur
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

#Ajuster l'espacement des échelles des axes
ticks = np.arange(-0.4, 0.4, 0.05)
ax.set_xticks(ticks)
ax.set_yticks(ticks)

#Ajouter une étiquette d'axe, ajuster la position
ax.set_xlabel('Z1', fontsize=16)
ax.set_ylabel('Z2', fontsize=16)
ax.set_zlabel('Z3', fontsize=16)

ax.xaxis.set_label_coords(1.02, 0.49)
ax.yaxis.set_label_coords(0.5, 1.02)

#Graphique de données
for zdir, x, y, z in zip(cls, z1, z2, z3):
    ax.scatter(x, y, z)
    ax.text(x, y, z, zdir)

#dessin
plt.show()

image.png

Code source

https://github.com/torahirod/TextDataPCA

Impressions

Il était intéressant de pouvoir confirmer visuellement un certain degré de cohésion simplement en analysant les principaux composants en utilisant les 5 mots les plus fréquemment utilisés pour chaque classification d'article.

Il peut également être intéressant d'essayer ce qui suit et de voir les résultats.

・ Développer jusqu'à Top10. ・ Du Top5, essayez d'exclure les mots qui apparaissent dans plusieurs catégories d'articles en double. ・ Essayez le Top 5 avec des fonctionnalités telles que TF-IDF au lieu du Top 5 avec une fréquence d'apparition simple.

À partir de là, je voudrais contester la classification des documents en utilisant les informations de coordonnées 2D et 3D obtenues par l'analyse en composantes principales en combinaison avec des k-moyennes.

Recommended Posts

Analyse des composants principaux avec le corpus d'actualités Livedoor - Pratique--
Analyse des composants principaux avec Livedoor News Corpus --Préparation--
Analyse des composants principaux avec Spark ML
Ceci et cela de l'analyse en composantes principales
Analyse en composantes principales (Analyse en composantes principales: ACP)
Compression dimensionnelle par auto-encodeur et analyse des composants principaux
J'ai essayé d'analyser les principaux composants avec les données du Titanic!
Filtrage coordonné avec analyse des composants principaux et clustering K-means
Défiez l'analyse des composants principaux des données textuelles avec Python
Apprendre sans enseignant 3 Analyse des principales composantes
Analyse des composants principaux à l'aide de python de nim avec nimpy
Analyse pratique des composants principaux avec PyCaret [Normalisation + visualisation (tracé)] Mémo
Reconnaissance faciale à l'aide de l'analyse des composants principaux
Python: apprentissage non supervisé: analyse principale
<Cours> Machine learning Chapitre 4: Analyse des principaux composants
PRML Chapitre 12 Mise en œuvre de l'analyse principale bayésienne Python
Commençons l'analyse multivariée et l'analyse des composants principaux avec Pokemon! Coopération entre R et Tableau
2. Analyse multivariée décrite dans Python 3-2. Analyse en composantes principales (algorithme)
Compréhension mathématique de l'analyse en composantes principales depuis le début
Clustering et analyse en composantes principales par méthode K-means (débutant)
Analyse en composantes principales Analyser les nombres manuscrits à l'aide de l'ACP. Partie 2
Analyse en composants principaux (PCA) et analyse en composants indépendants (ICA) avec python
Analyse en composantes principales Analyser les nombres manuscrits à l'aide de l'ACP. Partie 1
2. Analyse multivariée expliquée dans Python 3-1. Analyse en composantes principales (scikit-learn)
Analyse de données avec python 2
Analyse du panier avec Spark (1)
Analyse de dépendance avec CaboCha
Analyse vocale par python
Analyse vocale par python
Analyse dynamique par Valgrind
Effectuer une analyse de régression avec NumPy
Analyse de données avec Python
Défis d'apprentissage automatique de Coursera en Python: ex7-2 (analyse principale)
Visualisez la matrice de corrélation par l'analyse des composants principaux avec Python