0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

乃木撮を使ってnetworkXについて勉強する。Vol.02

Posted at

はじめに

前回は「乃木撮を使ってnetworkXについて勉強する。Vol.01」という記事で、写真集から作成したリストデータを使って、とりあえずグラフを描画してみました。

photos_01 = [
    ('新内眞衣', '齋藤飛鳥'),  # 01-001
    ('若月佑美', '白石麻衣', '衛藤美彩'),  # 01-002
    ('斉藤優里', '西野七瀬'),  # 01-003
    ('堀未央奈', '衛藤美彩', '秋元真夏'),  # 01-004
    ('秋元真夏', '生田絵梨花'),  # 01-005
    ('秋元真夏', '白石麻衣'),  # 01-006
    ('伊藤万理華', '星野みなみ', '西野七瀬', '若月佑美', '松村沙友理'),  # 01-007
    ('伊藤万理華', '松村沙友理'),  # 01-008
    ('斉藤優里', '生田絵梨花'),  # 01-009
    ('伊藤万理華', '西野七瀬', '衛藤美彩', '高山一実', '秋元真夏'),  # 01-010
         .
         .
         .
     中略
    ]

image.png

今回の目標としては、より見やすいグラフを描画するために、

  1. 期別にノードの色を変える
  2. 登場回数に応じてノードの大きさを変える
  3. 関係性の強さに応じてエッジの太さを変える
    を実装しようと思います。

新たなメンバーデータの作成

前回はphotos_01という写真を撮った人、写っている人を羅列したリストをもとにノードのデータを作成しましたが、今回は「乃木撮」内のメンバーデータまとめから下記のように辞書データを作成しました。
何期生か、生年月日、血液型、星座、身長という順番に並んでいます。今回使用するのは何期生かというデータです。

member_data = {
    '秋元真夏': (1, '1993/08/20', 'B', '獅子座', 154),
    '生田絵梨花': (1, '1997/01/22', 'A', '水瓶座', 160),
    '伊藤かりん': (2, '1993/05/26', 'O', '双子座', 153),
    '伊藤純奈': (2, '1998/11/30', 'A', '射手座', 166),
    '伊藤理々杏': (3, '2002/10/08', 'B', '天秤座', 154),
    .
    .
    
    .
    .    
    }
print(member_data['秋元真夏'][0]) # 何期生かという情報を取り出す。
# 1

今回はこのmember_dataからノードを作成し、属性情報をノードに入れることとします。

# ライブラリのインポート
import networkx as nx
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import font_manager

# 日本語表記のためIPAexフォントをダウンロードして解凍してできたipaexg.ttfを入れる。
font_manager.fontManager.addfont('/content/drive/MyDrive/ipaexg.ttf') 
matplotlib.rc('font', family='IPAexGothic')

# 無向グラフの作成
G = nx.Graph()

# 今回はmember_dataからノードを作成する。
G.add_nodes_from(member_data.keys())

# ノードに属性情報(期、生年月日、血液型、星座、身長)を入力する
for person in G.nodes:
    G.nodes[person]['generation'] = member_data[person][0]
    G.nodes[person]['dateofbirth'] = member_data[person][1]
    G.nodes[person]['bloodtype'] = member_data[person][2]
    G.nodes[person]['constellations'] = member_data[person][3]
    G.nodes[person]['height'] = member_data[person][4]

撮影回数、被撮影回数データを作る

写真を撮影した回数と写真に写った回数を数えて使用します。

# 撮影者、つまりphotos_01[i][0]を取り出す。
photographer = {person: 0 for person in G.nodes}  # 各人にvalue=0を入れた辞書データを作成する
for photo in photos_01:
    photographer[photo[0]] += 1

# 被写体の回数。
subject = {person: 0 for person in G.nodes}
for photo in photos_01:
    for person in photo[1:]: # photo[0]以外を数える
        subject[person] += 1

# 撮影回数、被写体回数もノードの属性情報に入れる
for person in G.nodes:
    G.nodes[person]['photographer'] = photographer[person]
    G.nodes[person]['subject'] = subject[person]

属性情報をもとに、ノードの形と大きさを変える

期別毎にノードの色を変え、被写体の回数でノードの大きさを変えるように設定します。

node_color = []
# 乃木撮Vol.01には3期生までしか登場しないが、今後を見越して5期生まで色を決めている
for person in G.nodes:
    if G.nodes[person]["generation"] == 1:
        node_color.append("red")
    elif G.nodes[person]["generation"] == 2:
        node_color.append("skyblue")
    elif G.nodes[person]["generation"] == 3:
        node_color.append("lime")
    elif G.nodes[person]["generation"] == 4:
        node_color.append("lightyellow")
    elif G.nodes[person]["generation"] == 5:
        node_color.append("violet")
    else:
        node_color.append("grey")
        
node_size = []
for node in G.nodes:
    node_size.append(G.nodes[node]['subject']*100)

関係性の強さを表現する

それぞれの写真について、撮影者と被写体、被写体が複数の場合は被写体同士にも繋がりがあるとしてエッジを作成します。intertools.combinationsを利用します。第一引数にリストまたは集合、第二引数に選択する個数を渡すと、その組み合わせを返してくれます。
繋がりができた回数を数えます。

import itertools
from collections import defaultdict # defaultdictで辞書データを作成します

connection = defaultdict(int)
for photo in photos_01:
    connects = list(itertools.combinations(set(photo), 2)) # 自撮りがあるのでset(photo)とする
    for connect in connects:
        connection[connect[0], connect[1]] += 1 
        connection[connect[1], connect[0]] += 1 # 組み合わせを考慮して2方向から数え上げる。

# connectionをもとにしてエッジを作成する
G.add_edges_from(connection.keys())

# 繋がりの現れた回数をエッジの属性情報に入れる。
for edge in G.edges:
    G.edges[edge]['weight'] = connection[edge]

# エッジの太さを変える
edge_weight = []
for edge in G.edges:
    edge_weight.append(round(G.edges[edge]['weight'] * 0.1, 1))

グラフ完成!

pos = nx.spring_layout(G)

plt.figure(figsize=(30, 30))
nx.draw_networkx(G,
                 pos,
                 node_color=node_color,
                 node_size=node_size,
                 width=edge_weight,
                 edge_color='black',
                 with_labels=True,
                 font_family="IPAexGothic",
                 font_size=20,
                 alpha=0.5,
                 )

plt.show()

image.png

よりわかりやすいグラフが作成できました。
ここから読み取れることとしては、

  • 1期生の選抜常連組(白石麻衣、西野七瀬、齋藤飛鳥、秋元真夏、若月佑美、衛藤美彩、松村沙友理、生田絵梨花)がやっぱり中心メンバー
  • 選抜回数からすると、斉藤優里の存在感が目立つ
  • 大まかに期別に分かれていると言える
  • 1期生と2期生は渾然一体となっている感じがある
  • 特に新内眞衣はほとんど1期生(ラジオでは桜井玲香や松村沙友理の名前がよく出ていた記憶があり、確かに関係性が近いことをうかがわせる。また、意外に齋藤飛鳥と仲が良い?)
  • それと比べると3期生はまだこの時点ではまだ交流が少ないのでは(与田祐希、大園桃子はガンガン絡んでいる模様)
  • 選抜、アンダーを考慮する必要があるのかもしれない

おまけ

登場回数ランキングを作成してみました。

# 撮影回数順に並び替える
photographer = dict(sorted(photographer.items(), key=lambda x: x[1], reverse=True))

# ヒストグラム作成
names = list(photographer.keys())
values = list(photographer.values())

plt.figure(figsize=(10, 6))  # 図のサイズを調整
plt.bar(names, values)
plt.title('写真撮影回数')
plt.xticks(rotation=90)  # x軸のラベルを回転
plt.tight_layout()  # ラベルが重ならないように調整
plt.show()
写真撮影回数
1位 秋元真夏  123回
2位 若月佑美  92回
3位 斉藤優里  57回
4位 樋口日奈  45回
5位 吉田綾乃  30回

image.png

被写体回数
 1位 西野七瀬  81回
 2位 白石麻衣  75回
 3位 齋藤飛鳥  70回
 4位 秋元真夏  61回
 5位 衛藤美彩  49回

image.png

関係性が強いメンバー
1位 西野七瀬、斉藤優里  33回
2位 白石麻衣、秋元真夏  30回
   秋元真夏、若月佑美  30回
4位 白石麻衣、若月佑美  27回
5位 秋元真夏、衛藤美彩  25回
   西野七瀬、秋元真夏  25回
   秋元真夏、松村沙友理 25回
8位 齋藤飛鳥、秋元真夏  23回
9位 秋元真夏、斉藤優里 20回
10位 西野七瀬、若月佑美 19回
    白石麻衣、松村沙友理 19回

数が多すぎるのでヒストグラムは作成できませんでした。
西野七瀬と斉藤優里の関係性が一番強いという意外な結果が出ています。
ちなみに、ほとんどが楽屋などの仕事に関係のある写真でしたが、この二人の写真は旅行先や食事などプライベートの写真が多いのも特筆に値すると思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?