Bonjour, nous allons traiter de la théorie des graphes, une analyse de réseau dans l'article précédent](https://qiita.com/b_aka/items/9020e3237ff1a3e676e4) cette fois.
Dans l'article précédent, nous avons visualisé le réseau des parties de Pokemon Sword Shield Rank Battle. Cette fois, je vais réellement commencer l'analyse.
Le code et les données utilisés cette fois-ci se trouvent dans This Github Repository.
Le code complet est ici [https://github.com/moxak/pokemon-rankbattle-network-analysis/blob/master/002.ipynb)
Comme le titre l'indique, j'aimerais regrouper chaque nœud du Pokemon Swordsman Party Building Network. Nous souhaitons également capturer des nœuds importants en introduisant le concept de centralité avant le clustering.
Si vous pouvez faire quelque chose comme ça, vous avez atteint votre objectif.
Il y a une centralité dans la théorie des réseaux (théorie des graphes).
La centralité est un indicateur permettant d'évaluer et de comparer l'importance de chaque sommet d'un réseau.
[Apprentissage de l'analyse de réseau 2e édition avec R Data Science](https://www.amazon.co.jp/%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF % E3% 83% BC% E3% 82% AF% E5% 88% 86% E6% 9E% 90-% E7% AC% AC2% E7% 89% 88-R% E3% 81% A7% E5% AD% A6% E3% 81% B6% E3% 83% 87% E3% 83% BC% E3% 82% BF% E3% 82% B5% E3% 82% A4% E3% 82% A8% E3% 83% B3% E3% 82% B9-% E9% 88% B4% E6% 9C% A8-% E5% 8A% AA / dp / 4320113152 / ref = sr_1_4? __Mk_ja_JP =% E3% 82% AB% E3% 82% BF% E3 % 82% AB% E3% 83% 8A & dchild = 1 & keywords =% E3% 83% 8D% E3% 83% 83% E3% 83% 88% E3% 83% AF% E3% 83% BC% E3% 82% AF% À partir de E5% 88% 86% E6% 9E% 90 & sr = 8-4)
Il s'agit d'une tentative pour calculer mathématiquement à quel point chaque nœud est central = ** important ** dans le réseau.
Cette fois, j'aimerais utiliser cette théorie pour calculer l'importance de chaque nœud du réseau.
Cependant, il existe en fait de nombreux types de cette centralité.
La première centralité est la centralité de l'ordre.
L'ordre est le nombre d'arêtes du nœud. Le nombre de commandes devient central tel quel.
Plus il y a de nœuds connectés, plus c'est important! Bien que ce soit une centralité de base basée sur l'idée, je pense que cela aboutit souvent à des choses qui ne sont pas intuitives.
Viennent ensuite la centralité et l'excentricité de proximité, qui dérivent la centralité de la distance des autres nœuds.
Plus vous êtes proche du centre du réseau, plus c'est important! C'est l'idée.
La centralité de proximité prend l'inverse de la distance totale du propre nœud aux autres nœuds, et l'excentricité prend l'inverse de la distance maximale du propre nœud aux autres nœuds.
Puisque les résultats des deux utilisant la distance sont très similaires, j'aimerais utiliser la centralité de proximité cette fois.
Le plus couramment utilisé (je pense) est la centralité médiatisée.
En termes simples, l'idée est que plus elle est fréquemment localisée sur l'itinéraire le plus court, plus elle est importante (relais).
Un nœud avec un centre de médiation élevé dans un réseau communautaire signifie qu'il est dans une position où il n'est pas possible d'accéder à une autre communauté sans passer par ce nœud, ce qui semble intuitivement important. J'espère que vous pouvez comprendre cela.
La centralité des vecteurs propres est très différente des quatre centralités introduites jusqu'à présent, et c'est une centralité qui introduit l'idée de «à quel nœud est connecté».
En intégrant l'idée que «les nœuds connectés à des nœuds importants sont plus importants», le processus d'ajout des centralités des autres connectés à soi-même est répété, et la valeur convergée est définie comme centralité.
Centralité conçue par les fondateurs de Google Larry Page et Sergei Brin.
L'idée de base est la même que celle de la centralité des vecteurs propres. Pour comprendre ce qui est différent, nous devons connaître le problème de la centralité des vecteurs propres.
Supposons que vous ayez un nœud dans votre réseau qui n'a pas d'arêtes d'autres nœuds. La centralité de ce nœud est bien entendu 0. C'est bien pour l'instant, mais le prochain est un peu délicat. Supposons que vous ayez un nœud i connecté uniquement à un tel nœud. Naturellement, la centralité de i ne change pas par rapport aux nœuds connectés, donc la centralité de i est également 0. Je pense que c'est contre-intuitif.
De plus, disons que vous avez un nœud i qui est connecté à un nœud j qui a une énorme quantité de centralité. Dans le concept de centralité des vecteurs propres, la centralité du nœud j passe au nœud i, mais le nœud i n'est qu'un des nombreux nœuds auxquels le nœud j attache une arête. Toute la centralité du nœud j doit-elle être transférée vers le nœud i?
Le classement de page est un indice de centralité qui résout ces problèmes dans une certaine mesure.
Il est devenu la base de l'algorithme de recherche de Google et est toujours utilisé pour calculer le facteur d'impact des papiers.
Les données utilisées pour dériver la centralité sont les données de «classement Pokémon à adopter ensemble» et les données de classement d'adoption de la bataille de rang du bouclier d'épée Pokémon de la période précédente. Nous analyserons le réseau constitué des 100 meilleurs animaux du classement de recrutement.
df = pd.read_csv(FILEPATH_TEMOTI_POKEMON), encoding='utf-8')
df_rank = pd.read_csv(FILEPATH_ADO_RANK, encoding='utf-8')
df.columns = ['Season', 'Rule', 'Pokemon_From', 'Pokemon_To', 'Weight']
df['Weight'] = 10-df['Weight']
df_season11_double = df[(df['Season']==11)&(df['Rule']=='Double')]
df_season11_double = df_season11_double.drop(['Season', 'Rule'], axis=1)
#Limité aux 100 meilleurs taux de recrutement
df_season11_double = df_season11_double[df_season11_double['Pokemon_From'].isin(list(df_rank['Pokemon'])[:100])]
df_season11_double = df_season11_double[df_season11_double['Pokemon_To'].isin(list(df_rank['Pokemon'])[:100])]
df_season11_double.to_csv(OUTPUT_FILEPATH', index=False)
df_season11_double
index | Pokemon_From | Pokemon_To | Weight |
---|---|---|---|
91394 | Lézard | Kyukon | 9 |
91395 | Lézard | Tritodon | 8 |
91396 | Lézard | Pippi | 7 |
91397 | Lézard | Terrakion | 6 |
91398 | Lézard | Yami Lami | 5 |
504 rows × 3 columns
Créez un réseau à partir des données créées ci-dessus.
import networkx as nx
network_np = df_season11_double.values
G = nx.DiGraph()
G.add_weighted_edges_from(network_np)
degree_centers = nx.degree_centrality(G)
df_dc = pd.DataFrame(sorted(degree_centers.items(), key=lambda x: x[1], reverse=True), columns=['Pokemon', 'Degree centrality'])
df_dc.head(10)
index | Pokemon | Degree centrality |
---|---|---|
0 | Ulaos | 0.500000 |
1 | Flamme de Serre | 0.490291 |
2 | Achilleine | 0.451456 |
3 | Baril Moro | 0.419903 |
4 | Venteux | 0.359223 |
5 | Samayor | 0.308252 |
6 | Oronge | 0.293689 |
7 | Laplace | 0.291262 |
8 | Lézard | 0.269417 |
9 | Natley | 0.237864 |
close_centers = nx.closeness_centrality(G)
df_cc = pd.DataFrame(sorted(close_centers.items(), key=lambda x: x[1], reverse=True), columns=['Pokemon', 'Closeness centrality'])
df_cc.head(10)
index | Pokemon | Closeness centrality |
---|---|---|
0 | Ulaos | 0.648440 |
1 | Flamme de Serre | 0.646345 |
2 | Achilleine | 0.628081 |
3 | Baril Moro | 0.612691 |
4 | Venteux | 0.594483 |
5 | Samayor | 0.572371 |
6 | Laplace | 0.562711 |
7 | Oronge | 0.551085 |
8 | Pippi | 0.545078 |
9 | Natley | 0.545078 |
between_centers = nx.betweenness_centrality(G)
df_bc = pd.DataFrame(sorted(between_centers.items(), key=lambda x: x[1], reverse=True), columns=['Pokemon', 'Betweenness centrality'])
df_bc.head(10)
index | Pokemon | Betweenness centrality |
---|---|---|
0 | Kyukon | 0.046012 |
1 | persan | 0.036945 |
2 | Tritodon | 0.028901 |
3 | Lézard | 0.025690 |
4 | Terrakion | 0.021207 |
5 | Gracia | 0.019807 |
6 | Pain de sable | 0.018529 |
7 | Achilleine | 0.013435 |
8 | Nyai King | 0.011381 |
9 | Eleard | 0.009867 |
eigen_centers = nx.eigenvector_centrality_numpy(G)
df_ec = pd.DataFrame(sorted(eigen_centers.items(), key=lambda x: x[1], reverse=True), columns=['Pokemon', 'Eigen centrality'])
df_ec.head(10)
index | Pokemon | Eigen centrality |
---|---|---|
0 | Ulaos | 0.374252 |
1 | Achilleine | 0.362932 |
2 | Flamme de Serre | 0.341690 |
3 | Baril Moro | 0.332555 |
4 | Samayor | 0.297832 |
5 | Venteux | 0.292263 |
6 | Patch Ragon | 0.261000 |
7 | Natley | 0.259066 |
8 | Pippi | 0.237895 |
9 | Laplace | 0.218322 |
pageranks = nx.pagerank(G)
df_pr = pd.DataFrame(sorted(pageranks.items(), key=operator.itemgetter(1),reverse = True), columns=['Pokemon', 'Page Rank'])
df_pr.head(10)
J'ai essayé d'augmenter la police d'étiquette du nœud avec une grande centralité.
J'ai arrangé les classements publiés et chaque indice de centralité.
Dans le classement réduit aux 100 meilleurs animaux et aux 10 meilleurs animaux du classement combiné, on peut voir qu'Ulaos est plus élevé que le classement significativement publié dans n'importe quel indice. (Le sentiment d'être surfait)
À partir de maintenant, nous utiliserons le classement de page.
C'est enfin fini. Je voudrais entrer dans le clustering des structures de réseau, qui est le sujet de cette fois.
Il existe diverses méthodes de regroupement (extraction de communauté), telles que celles utilisant la centralité de médiation et la centralité des vecteurs propres dérivées plus tôt, la centralité de l'information, la méthode du verre de rotation et la marche aléatoire, qui ne sont pas introduites cette fois.
Cette fois, j'ai consacré une quantité considérable de texte à la dérivation de la centralité, je voudrais donc laisser l'exécution du clustering par chaque centralité et la comparaison des résultats à une autre opportunité.
Dépêchez-vous cette fois. Le clustering se fera en utilisant la méthode ici (Paper, Implementation Library).
Cette méthode est un indicateur de la densité du réseau ([Modularité](https://ja.wikipedia.org/wiki/%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%] A9% E3% 83% AA% E3% 83% 86% E3% 82% A3))) est une méthode de division au maximum, et elle diffère des k-moyennes en ce qu'il n'est pas nécessaire de spécifier le nombre de clusters à l'avance. il y a.
Les graphiques dirigés ne peuvent pas être utilisés dans cette implémentation, nous les convertirons donc en graphiques non orientés.
#Convertir un graphe orienté en graphe non orienté
G2 = nx.Graph(G)
import community
partition = community.best_partition(G2)
partition2 = {}
for i in partition.keys():
sub_dict = {'community' : partition[i]}
partition2[i] = sub_dict
labels = dict([(i, str(i)) for i in range(nx.number_of_nodes(G2))])
labels2 = {}
for i in range(len(labels)):
sub_dict = {'labels' : labels[i]}
labels2[list(partition.keys())[i]] = sub_dict
nx.set_node_attributes(G2, labels2)
nx.set_node_attributes(G2, partition2)
nx.write_gml(G2, ".//community.gml")
pd.DataFrame.from_dict(labels2).T.to_csv('.//community_labels.csv')
À la suite du regroupement, 6 clusters ont été extraits. Jetons un coup d'œil à chaque cluster.
df_pagerank = pd.DataFrame(sorted(pageranks.items(), key=operator.itemgetter(1),reverse = True), columns=['Pokemon', 'Page Rank'])
df_community = pd.concat([pd.DataFrame.from_dict(labels2).T, pd.DataFrame.from_dict(partition2).T], axis=1)
df_community = df_community.reset_index()
df_community.columns = ['Pokemon', 'label', 'community']
df_pagerank_community = pd.merge(left=df_pagerank, right=df_community, on = 'Pokemon')
Vérifiez la figure ci-dessous des Pokémon classés dans chaque cluster.
df_pagerank_community.groupby('community').count()['Pokemon'].plot.bar(rot=0, alpha=0.75)
Vous pouvez voir que le cluster 3 représente près de 30% du total.
Jetons un coup d'œil au contenu de chaque cluster.
df_pagerank_community[df_pagerank_community['community']==0].head(10)
index | Pokemon | Page Rank | label | community |
---|---|---|---|---|
13 | Lézard | 0.013742 | 0 | 0 |
18 | Tritodon | 0.007309 | 2 | 0 |
19 | Sekitanzan | 0.006604 | 32 | 0 |
20 | Kyukon | 0.006319 | 1 | 0 |
30 | Yami Lami | 0.002842 | 5 | 0 |
42 | Manœuvre | 0.001501 | 68 | 0 |
46 | Nura | 0.001235 | 55 | 0 |
53 | Kovalon | 0.001133 | 56 | 0 |
61 | Leafia | 0.000935 | 30 | 0 |
69 | Village | 0.000789 | 69 | 0 |
Est-ce une journée ensoleillée centrée sur Lizardon Kyukon? Lizardon est classé premier dans la centralité, et Tritodon, qui a une excellente compatibilité avec Lizardon, est classé à la deuxième place.
df_pagerank_community[df_pagerank_community['community']==1].head(10)
index | Pokemon | Page Rank | label | community |
---|---|---|---|---|
8 | Pippi | 0.033903 | 3 | 1 |
16 | Polygone Z | 0.012646 | 27 | 1 |
17 | Terrakion | 0.009129 | 4 | 1 |
41 | persan | 0.001544 | 33 | 1 |
80 | Rentler | 0.000630 | 64 | 1 |
81 | Ennute | 0.000629 | 92 | 1 |
Ensuite, le groupe 1 était ces 6 animaux. Polygon Z, qui peut produire de la puissance super-thermique, a été classé par la pierre brillante Pippi, qui a des performances de support extrêmement élevées, et l'adaptabilité Dimax. L'impression est qu'il existe de nombreux Pokémon polyvalents qui peuvent être utilisés à n'importe quelle fête.
df_pagerank_community[df_pagerank_community['community']==2].head(10)
index | Pokemon | Page Rank | label | community |
---|---|---|---|---|
7 | Natley | 0.038186 | 6 | 2 |
24 | Nymphie | 0.005511 | 20 | 2 |
28 | Peripper | 0.003061 | 57 | 2 |
29 | Wonoragon | 0.002859 | 46 | 2 |
32 | Roi Dora | 0.002468 | 49 | 2 |
33 | Nyorotono | 0.002321 | 47 | 2 |
35 | Runpapa | 0.002233 | 50 | 2 |
37 | Gamageroge | 0.001736 | 58 | 2 |
38 | Chevalgo | 0.001626 | 59 | 2 |
39 | Matadogas | 0.001572 | 44 | 2 |
Le cluster 2 est facile à comprendre, c'est un pa de pluie qui comprend peripper, kingdora, runpapa et ainsi de suite. La centralité du nutray, qui est excellente pour compléter la compatibilité avec le type d'eau, est élevée. De plus, le fait que Pokémon, comme Chevalgo, qui ne sont pas doués pour les types de flammes, soit composé de rain pas est conforme à mon intuition.
df_pagerank_community[df_pagerank_community['community']==3].head(10)
index | Pokemon | Page Rank | label | community |
---|---|---|---|---|
0 | Achilleine | 0.107503 | 7 | 3 |
1 | Flamme de Serre | 0.093996 | 12 | 3 |
4 | Venteux | 0.056541 | 15 | 3 |
5 | Patch Ragon | 0.049160 | 16 | 3 |
14 | Duraldon | 0.013730 | 24 | 3 |
15 | Oronge | 0.013617 | 29 | 3 |
21 | Amarjo | 0.006167 | 17 | 3 |
26 | Wogle | 0.003980 | 23 | 3 |
27 | Genger | 0.003799 | 43 | 3 |
34 | Lutin | 0.002254 | 28 | 3 |
Le cluster 3 semble être concentré dans la méta supérieure de l'environnement. Si vous regardez les considérations de construction de groupe qui roulent sur le net, vous pouvez souvent voir la combinaison de Achilleine Firelow Patch Ragon comme une construction réussie, donc le Pokémon qui a eu une grande influence dans le double environnement de la saison 11 Je suppose qu'il y en a beaucoup.
df_pagerank_community[df_pagerank_community['community']==4].head(10)
index | Pokemon | Page Rank | label | community |
---|---|---|---|---|
2 | Baril Moro | 0.083762 | 8 | 4 |
3 | Samayor | 0.061276 | 9 | 4 |
9 | Bord sur | 0.026956 | 25 | 4 |
11 | Dosaidon | 0.016228 | 21 | 4 |
12 | Dadarin | 0.014804 | 26 | 4 |
22 | Lumière Chu | 0.006124 | 13 | 4 |
25 | Garula | 0.005487 | 19 | 4 |
31 | hochet | 0.002758 | 39 | 4 |
40 | Yadran | 0.001563 | 40 | 4 |
45 | Raidisseur | 0.001322 | 82 | 4 |
Ce cluster est également très facile à comprendre. Samayor et Brimon, qui sont les déclencheurs du trille, Dosaidon, Dadarin et le hochet, qui sont les attaquants du trille, et Morobarrel, qui est le partisan, sont classés.
En regardant la centralité, nous pouvons voir que Morobarrel joue un rôle très important.
df_pagerank_community[df_pagerank_community['community']==5].head(10)
index | Pokemon | Page Rank | label | community |
---|---|---|---|---|
6 | Ulaos | 0.045935 | 10 | 5 |
10 | Laplace | 0.024565 | 22 | 5 |
23 | Kuwawa | 0.005706 | 14 | 5 |
36 | Numergon | 0.002140 | 88 | 5 |
50 | Onburn | 0.001201 | 83 | 5 |
55 | Kamex | 0.001056 | 11 | 5 |
63 | Mahip | 0.000880 | 94 | 5 |
90 | Togedemaru | 0.000463 | 93 | 5 |
Le dernier groupe est ces 8 animaux. Quel genre de rassemblement sont ces Pokémon? C'était difficile à interpréter avec mes connaissances, j'attends donc les commentaires.
Enfin, visualisez le réseau avec Cytoscape, qui a été confirmé comment l'utiliser la dernière fois.
Chargez community.gml
depuis ** Fichier> Importer> Réseau à partir d'un fichier ** et ** Importer une table à partir d'un fichier ** en haut (voir figure ci-dessous)
Depuis, chargez community_labels.csv
et définissez la boîte de dialogue affichée comme suit.
Notez que la partie rouge doit être modifiée par rapport à la valeur par défaut.
Tout ce que vous avez à faire est de changer la forme et la couleur de chaque cluster en utilisant pleinement ** Mappage continu ** à partir de l'onglet ** Style **.
J'ai essayé de visualiser le réseau avec la couleur de police comme groupe et la taille de police comme rang de page.
La prochaine fois, j'aimerais rechercher la méthode de clustering optimale pour ces données.
À la prochaine.
© 2020 Pokémon © 1995-2020 Nintendo / Creatures Inc./GAME FREAK Inc. Pocket Monsters, Pokemon et Pokémon sont des marques déposées de Nintendo, Creatures et Game Freak.
Recommended Posts