nishio 東大谷口研の2022年参院選でのデータからUMAPで可視化した、共産島(共産党の島)とかができてる
nishio 共産島と近くの混在島
nishio 自民島・公明島と近くの大きな混在島
nishio 維新島
from pPolis2024-05-27 pPolis
py
import umap
# UMAPによる次元削減
reducer = umap.UMAP(
n_neighbors=15, min_dist=0.1, n_components=2, random_state=42, n_jobs=1
)
embedding = reducer.fit_transform(matrix)
# UMAPの結果を含むDataFrameを作成し、matrixのインデックス(User_ID)を含める
umap_df = pd.DataFrame(embedding, columns=["UMAP1", "UMAP2"])
umap_df["User_ID"] = matrix.index # matrixのインデックスをUser_IDとする
# dataにUser_ID列を追加してから、umap_dfとマージ
data = data.reset_index().rename(
columns={"index": "User_ID"}
) # User_IDとしてインデックスを追加
merged_data = pd.merge(data, umap_df, on="User_ID", how="inner") # User_IDで結合
# 政党名の列を追加
merged_data["PARTY_NAME"] = merged_data["PARTY"].map(political_parties)
data = merged_data
# カラーマップの準備
unique_parties = data["PARTY"].unique()
colors = plt.cm.tab10(np.linspace(0, 1, len(unique_parties)))
parties_letter = {
"自民党": "自",
"立憲民主党": "立",
"公明党": "公",
"日本維新の会": "維",
"国民民主党": "国",
"共産党": "共",
"社民党": "社",
"れいわ新選組": "れ",
"NHK党": "N",
"参政党": "参",
"諸派": "諸",
"無所属候補": "無",
}
# 可視化
plt.figure(figsize=(10, 7))
for i, party in enumerate(unique_parties):
party_data = data[data["PARTY"] == party]
pname = political_parties[party]
pletter = parties_letter[political_parties[party]]
plt.scatter(
party_data["UMAP1"],
party_data["UMAP2"],
s=0,
marker="+",
color=colors[i],
label=f"{pname}({pletter})",
)
for p in party_data.iterrows():
plt.text(
p[1]["UMAP1"],
p[1]["UMAP2"],
s=pletter,
color=colors[i],
fontsize=5,
ha="center",
va="center",
)
plt.title("Political Parties UMAP Visualization")
plt.xlabel("UMAP1")
plt.ylabel("UMAP2")
plt.legend(title="政党")
plt.show()
割とクラスタが分かれてくれるので、次はこれにPolis的クラスタ特徴抽出を掛けて、世論地図的なAIクラスタ解説をすると面白い
2022年参院選のPolis的可視化に関して、以前はPCAでやってて、先日その主成分軸をAIに解説させてあまり面白くなくて それを踏まえて「じゃあ軸に意味が見出せなくてもいいから別の方法で可視化してもいいよね」とTalk to the Cityで使われてるUMAPを使ってみたものがこちら なんかそれっぽく別れてますね
共産党だけで集まってる離れ小島の「過激な共産党」と他の政党と同居してる「マイルド共産党」がいて面白い 自民もそう 維新の離れ小島に混ざってる自民党の人は誰だw(もちろん調べればわかる)
UMAPしてからクラスタリングしてAIに解説させようかと思ってたけど、こんな感じに別れるならはっきり分かれてるのは人間が範囲指定してクラスタにしての大きい島だけクラスタリングで数個に分けた方が納得感が高いかも
文脈を補うと、600人でPCAしたら二分割にしかならなかったこのデータでもUMAPしたら6つにわかれたわけなので、世論地図の二分割になってるものもUMAPを使えば細かく分かれた詳細地図ができるかもねという予備実験でした
Scatterから範囲選択してどこが選択されたか表示 py
# 選択範囲内のデータを表示する関数
def on_select(eclick, erelease):
x1, y1 = eclick.xdata, eclick.ydata # 選択範囲の開始点
x2, y2 = erelease.xdata, erelease.ydata # 選択範囲の終了点
# 選択範囲とデータを表示
print(
f"Selected range: x=[{min(x1, x2):.2f}, {max(x1, x2):.2f}], y=[{min(y1, y2):.2f}, {max(y1, y2):.2f}]"
)
from matplotlib.widgets import RectangleSelector
# RectangleSelectorを使用して選択イベントを監視
fig, ax = plt.subplots()
selector = RectangleSelector(ax, on_select, useblit=True, button=[1], interactive=True)
# 可視化
# plt.figure(figsize=(10, 7))
for i, party in enumerate(unique_parties):
party_data = data[data["PARTY"] == party]
pname = political_parties[party]
pletter = parties_letter[political_parties[party]]
ax.scatter(
party_data["UMAP1"],
party_data["UMAP2"],
s=0,
marker="+",
color=colors[i],
label=f"{pname}({pletter})",
)
for p in party_data.iterrows():
ax.text(
p[1]["UMAP1"],
p[1]["UMAP2"],
s=pletter,
color=colors[i],
fontsize=5,
ha="center",
va="center",
)
plt.title("Political Parties UMAP Visualization")
plt.xlabel("UMAP1")
plt.ylabel("UMAP2")
plt.legend(title="政党")
plt.show()
from ブラックボックスと掘り下げ
同じように世論地図のデータもUMAPして政党アイコンを出せば政党に代表されていない意見クラスタがわかるかもな〜
2024-10-31
nishio 1枚目この範囲の議員が持ってる特徴的な意見ベクトルが2枚目
nishio AIが勝手にクラスタリングするだけではなく、人間が「この範囲」と指定して分析できるようになったって話 nishio つまりここまでできたということ
このクラスタの中でさらに左上の純粋共産島と他の部分にどういう意見の差があるのか見たくなってきた
諦めて個別クラスタをやったら意外と目的が達成された
結果はここにおいた