散布図#
準備#
Import#
Show code cell content
# warningsモジュールのインポート
import warnings
# データ解析や機械学習のライブラリ使用時の警告を非表示にする目的で警告を無視
# 本書の文脈では、可視化の学習に議論を集中させるために選択した
# ただし、学習以外の場面で、警告を無視する設定は推奨しない
warnings.filterwarnings("ignore")
Show code cell content
# pathlibモジュールのインポート
# ファイルシステムのパスを扱う
from pathlib import Path
# numpy:数値計算ライブラリのインポート
# npという名前で参照可能
import numpy as np
# pandas:データ解析ライブラリのインポート
# pdという名前で参照可能
import pandas as pd
# plotly.expressのインポート
# インタラクティブなグラフ作成のライブラリ
# pxという名前で参照可能
import plotly.express as px
# plotly.graph_objectsのインポート
# より詳細なグラフ作成機能を利用可能
# goという名前で参照可能
import plotly.graph_objects as go
# plotly.graph_objectsからFigureクラスのインポート
# 型ヒントの利用を主目的とする
from plotly.graph_objects import Figure
変数#
Show code cell content
# マンガデータ保存ディレクトリのパス
DIR_CM = Path("../../../data/cm/input")
# アニメデータ保存ディレクトリのパス
DIR_AN = Path("../../../data/an/input")
# ゲームデータ保存ディレクトリのパス
DIR_GM = Path("../../../data/gm/input")
# マンガデータの分析結果の出力先ディレクトリのパス
DIR_OUT_CM = (
DIR_CM.parent / "output" / Path.cwd().parts[-2] / Path.cwd().parts[-1] / "scatter"
)
# アニメデータの分析結果の出力先ディレクトリのパス
DIR_OUT_AN = (
DIR_AN.parent / "output" / Path.cwd().parts[-2] / Path.cwd().parts[-1] / "scatter"
)
# ゲームデータの分析結果の出力先ディレクトリのパス
DIR_OUT_GM = (
DIR_GM.parent / "output" / Path.cwd().parts[-2] / Path.cwd().parts[-1] / "scatter"
)
Show code cell content
# 読み込み対象ファイル名の定義
# マンガ各話に関するファイル
FN_CE = "cm_ce.csv"
# マンガ作品と原作者の対応関係に関するファイル
FN_CC_CRT = "cm_cc_crt.csv"
# アニメ各話に関するファイル
FN_AE = "an_ae.csv"
# アニメ作品と声優の対応関係に関するファイル
FN_AC_ACT = "an_ac_act.csv"
# ゲームパッケージとプラットフォームの対応関係に関するファイル
FN_PKG_PF = "gm_pkg_pf.csv"
Show code cell content
# 国内主要ゲームメーカーのプラットフォームとメーカー名の対応辞書
# キー: プラットフォーム名、値: メーカー名の略称
PF2MK = {
"プレイステーション": "ソニー",
"プレイステーション2": "ソニー",
"プレイステーション・ポータブル": "ソニー",
"プレイステーション3": "ソニー",
"プレイステーションVita": "ソニー",
"プレイステーション4": "ソニー",
"ゲームアーカイブス": "ソニー",
"SG-1000": "セガ",
"SC-3000": "セガ",
"SEGAマーク3": "セガ",
"セガ・マスターシステム": "セガ",
"メガドライブ": "セガ",
"ゲームギア": "セガ",
"セガサターン": "セガ",
"ドリームキャスト": "セガ",
"ファミリーコンピュータ": "任天堂",
"ゲームボーイ": "任天堂",
"スーパーファミコン": "任天堂",
"NINTENDO64": "任天堂",
"ゲームボーイアドバンス": "任天堂",
"ニンテンドーゲームキューブ": "任天堂",
"ニンテンドーDS": "任天堂",
"ニンテンドー3DS": "任天堂",
"Wii": "任天堂",
"WiiU": "任天堂",
"NintendoSwitch": "任天堂",
}
Show code cell content
# 質的変数の描画用のカラースケールの定義
# Okabe and Ito (2008)基準のカラーパレット
# 色の識別性が高く、多様な色覚の人々にも見やすい色組み合わせ
# 参考URL: https://jfly.uni-koeln.de/color/#pallet
OKABE_ITO = [
"#000000", # 黒 (Black)
"#E69F00", # 橙 (Orange)
"#56B4E9", # 薄青 (Sky Blue)
"#009E73", # 青緑 (Bluish Green)
"#F0E442", # 黄色 (Yellow)
"#0072B2", # 青 (Blue)
"#D55E00", # 赤紫 (Vermilion)
"#CC79A7", # 紫 (Reddish Purple)
]
Show code cell content
# plotlyの描画設定の定義
# plotlyのグラフ描画用レンダラーの定義
# Jupyter Notebook環境のグラフ表示に適切なものを選択
RENDERER = "plotly_mimetype+notebook"
関数#
Show code cell source
def show_fig(fig: Figure, watermark: str = None, position: str = None) -> None:
"""
所定のレンダラーを用いてplotlyの図を表示する関数
オプションで図に透かしを追加可能
Parameters
----------
fig : Figure
表示対象のplotly図
watermark : str, optional
図に追加する透かしのテキスト
position : str, optional
透かしの位置 ('topleft', 'topright', 'bottomleft', 'bottomright')
Returns
-------
None
"""
# 図の周囲の余白を設定
fig.update_layout(margin=dict(t=25, l=25, r=25, b=25))
# 透かしの位置を辞書で定義
# キーは位置を表す文字列、値はx, y座標のタプル
position_dict = {
"topleft": (0.05, 0.95),
"topright": (0.95, 0.95),
"bottomleft": (0.05, 0.05),
"bottomright": (0.95, 0.05),
}
# 透かしを追加する場合の処理
# 指定された位置が辞書に存在する場合のみ、透かしを追加
if watermark and position in position_dict:
# 指定された位置に対応する座標を取得
x_pos, y_pos = position_dict[position]
# 透かしを図に追加
# 透かしはテキストで、指定された位置に表示される
# フォントサイズは60、色は薄い灰色
fig.add_annotation(
text=watermark,
xref="paper",
yref="paper",
x=x_pos,
y=y_pos,
showarrow=False,
font=dict(size=60, color="lightgrey"),
opacity=0.8,
)
# 所定のレンダラーを使用して図を表示
fig.show(renderer=RENDERER)
Show code cell content
def add_jitter(values: pd.Series, scale: float = 0.3, seed: int = None) -> pd.Series:
"""
与えられた値にジッタリング(ランダムなノイズ)を適用する
Parameters
----------
values : pd.Series
ジッタリングを適用する数値が含まれるPandasのSeries
scale : float, optional
ランダムノイズの大きさを調整するためのスケール因子、デフォルトは0.3
seed : int, optional
乱数生成のためのシード値、指定された場合再現可能なランダムノイズが生成される
Returns
-------
pd.Series
ジッタリングが適用された数値を含むPandasのSeries
"""
# シード値が指定された場合は、乱数ジェネレータを初期化
if seed is not None:
np.random.seed(seed)
# ランダムなノイズを生成して値に加える
return values + np.random.randn(len(values)) * scale
Show code cell content
def save_df_to_csv(df: pd.DataFrame, dir_save: Path, fn_save: str) -> None:
"""
DataFrameをCSVファイルとして指定されたディレクトリに保存する関数
Parameters
----------
df : pd.DataFrame
保存対象となるDataFrame
dir_save : Path
出力先ディレクトリのパス
fn_save : str
保存するCSVファイルの名前(拡張子は含めない)
"""
# 出力先ディレクトリが存在しない場合は作成
dir_save.mkdir(parents=True, exist_ok=True)
# 出力先のパスを作成
p_save = dir_save / f"{fn_save}.csv"
# DataFrameをCSVファイルとして保存する
df.to_csv(p_save, index=False, encoding="utf-8-sig")
# 保存完了のメッセージを表示する
print(f"DataFrame is saved as '{p_save}'.")
可視化例#
マンガデータ#
Show code cell content
# pandasのread_csv関数でCSVファイルの読み込み
df_ce = pd.read_csv(DIR_CM / FN_CE)
df_cc_crt = pd.read_csv(DIR_CM / FN_CC_CRT)
Show code cell content
# 可視化のための集計
# 各マンガ作品(cc)に紐づく原作者(crt)の情報をマージ
df_cm = pd.merge(df_ce, df_cc_crt[["ccid", "crtid", "crtname"]], on="ccid", how="outer")
# 雑誌の各巻号(miname)ごとにデータを集計
df_cm = (
df_cm.groupby(["miname"])[["ccid", "crtid", "page_end", "date", "price", "mcname"]]
.agg(
{
"ccid": "nunique", # 作品数:ユニークなccidの数
"crtid": "nunique", # 作者数:ユニークなcrtidの数
"page_end": "max", # 合計ページ数:page_endの最大値
"date": "first", # 発売日:dateの最初の値
"price": "first", # 価格:priceの最初の値
"mcname": "first", # 雑誌名:mcnameの最初の値
}
)
.reset_index()
)
# カラム名をわかりやすく変更
df_cm = df_cm.rename(
columns={
"miname": "マンガ雑誌巻号名",
"ccid": "マンガ作品数",
"crtid": "マンガ作者数",
"page_end": "合計ページ数",
"date": "発売日",
"price": "価格",
"mcname": "マンガ雑誌名",
}
)
Show code cell content
# 可視化対象のDataFrameを確認
df_cm.head()
| マンガ雑誌巻号名 | マンガ作品数 | マンガ作者数 | 合計ページ数 | 発売日 | 価格 | マンガ雑誌名 | |
|---|---|---|---|---|---|---|---|
| 0 | 週刊少年サンデー 1970年 表示号数32 | 12 | 14 | 284.0 | 1970-08-02 | 80.0 | 週刊少年サンデー |
| 1 | 週刊少年サンデー 1970年 表示号数33 | 12 | 16 | 307.0 | 1970-08-09 | 90.0 | 週刊少年サンデー |
| 2 | 週刊少年サンデー 1970年 表示号数34 | 13 | 17 | 314.0 | 1970-08-16 | 90.0 | 週刊少年サンデー |
| 3 | 週刊少年サンデー 1970年 表示号数35 | 13 | 17 | 305.0 | 1970-08-23 | 90.0 | 週刊少年サンデー |
| 4 | 週刊少年サンデー 1970年 表示号数36 | 13 | 17 | 305.0 | 1970-08-30 | 90.0 | 週刊少年サンデー |
Show code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_cm, DIR_OUT_CM, "cm")
DataFrame is saved as '../../../data/cm/output/vol2/04/scatter/cm.csv'.
Show code cell source
# px.scatter関数を使用して散布図を作成
# x軸に作品数、y軸に作者数をプロット
# 各点には雑誌巻号名、発売日、雑誌名をホバー情報として表示
fig = px.scatter(
df_cm,
x="マンガ作品数",
y="マンガ作者数",
hover_name="マンガ雑誌巻号名",
hover_data=["発売日", "マンガ雑誌名"],
)
# 散布図のマーカーのスタイルを更新
# サイズを10に設定し、線幅を1、透明度を0.5に設定
fig.update_traces(
marker={
"size": 10,
"line_width": 1,
"opacity": 0.5,
}
)
# 散布図を表示
show_fig(fig)
Show code cell source
# 直線y=xの最小値と最大値を規定
# 最小値は0、最大値は散布図の最大値の1.1倍
x_line = [0, df_cm["マンガ作品数"].max() * 1.1]
# 2点を使ってy = xの直線を追加
fig.add_trace(go.Scatter(x=x_line, y=x_line, mode="lines", name="y=x"))
# 散布図を表示
show_fig(fig)
Show code cell content
# assignメソッドで作品数-作者数を格納する列diffを一時的に作成し、それに基づき降順ソート
# headメソッドで上位5つを表示
df_cm.assign(diff=df_cm["マンガ作品数"] - df_cm["マンガ作者数"]).sort_values(
by="diff", ascending=False
).head()
| マンガ雑誌巻号名 | マンガ作品数 | マンガ作者数 | 合計ページ数 | 発売日 | 価格 | マンガ雑誌名 | diff | |
|---|---|---|---|---|---|---|---|---|
| 3933 | 週刊少年ジャンプ 2003年 表示号数37 | 40 | 22 | 463.0 | 2003-08-25 | 219.0 | 週刊少年ジャンプ | 18 |
| 2126 | 週刊少年サンデー 2013年 表示号数6 | 49 | 33 | 482.0 | 2013-01-09 | 267.0 | 週刊少年サンデー | 16 |
| 4224 | 週刊少年ジャンプ 2009年 表示号数37 | 32 | 27 | 535.0 | 2009-08-31 | 238.0 | 週刊少年ジャンプ | 5 |
| 8997 | 週刊少年マガジン 2012年 表示号数50 | 33 | 29 | 472.0 | 2012-11-28 | 248.0 | 週刊少年マガジン | 4 |
| 4565 | 週刊少年ジャンプ 2016年 表示号数44 | 25 | 22 | 497.0 | 2016-10-17 | 241.0 | 週刊少年ジャンプ | 3 |
Show code cell content
# 週刊少年ジャンプ 2003年 表示号数37に掲載された各話を表示
# df_ceとdf_cc_crtをマージした一時的なDataFrameを作成
df_tmp = pd.merge(
df_ce, df_cc_crt[["ccid", "crtid", "crtname"]], on="ccid", how="outer"
)
# df_ceデータフレームをフィルタリングして、
# '週刊少年ジャンプ 2003年 表示号数37'に掲載された作品の情報を抽出
# 必要なカラム(作品名、作者名、ページ数)のみを選択し、作者名で並べ替えて表示
df_tmp[df_tmp["miname"] == "週刊少年ジャンプ 2003年 表示号数37"][
["ccname", "crtname", "pages"]
].sort_values("crtname")
| ccname | crtname | pages | |
|---|---|---|---|
| 69587 | 旅の達人 | うすた京介 | 1.0 |
| 61449 | ピューと吹く!ジャガー | うすた京介 | 7.0 |
| 69314 | 神奈川磯南風天組 | かずはじめ | 19.0 |
| 69582 | 野津ケン割り!? | かずはじめ | 1.0 |
| 68872 | ごっちゃんです!! | つの丸 | 19.0 |
| 69591 | つってつって | つの丸 | 1.0 |
| 69595 | ケイゴとタダノブ | 久保帯人 | 1.0 |
| 59361 | BLEACH | 久保帯人 | 19.0 |
| 61747 | HUNTER×HUNTER | 冨樫義博 | 15.0 |
| 69585 | 夏休み | 冨樫義博 | 1.0 |
| 69594 | 阿加木と千葉の夏休み | 吉川雅之 | 1.0 |
| 69330 | キックスメガミックス | 吉川雅之 | 19.0 |
| 66462 | 武装錬金 | 和月伸宏 | 19.0 |
| 69592 | 嘘です | 和月伸宏 | 1.0 |
| 69579 | 西の瓜割り | 尾田栄一郎 | 1.0 |
| 54796 | ONE PIECE | 尾田栄一郎 | 20.0 |
| 56115 | NARUTO-ナルト- | 岸本斉史 | 35.0 |
| 69580 | 昆蟲採集 | 岸本斉史 | 1.0 |
| 63116 | アイシールド21 | 村田雄介 | 19.0 |
| 69588 | デビルバッツV.S.蚊 | 村田雄介 | 1.0 |
| 69586 | スラッガー平塚 | 森田まさのり | 1.0 |
| 69344 | ROOKIES | 森田まさのり | 19.0 |
| 69590 | きもだめし | 武井宏之 | 1.0 |
| 68362 | シャーマンキング | 武井宏之 | 19.0 |
| 66238 | いちご100% | 河下水希 | 19.0 |
| 69584 | 胸騒ぎの夏休み | 河下水希 | 1.0 |
| 65883 | ボボボーボ・ボーボボ | 澤井啓夫 | 15.0 |
| 69596 | 自由工作 | 澤井啓夫 | 1.0 |
| 69597 | 夜店 | 澤井啓夫 | 1.0 |
| 68652 | BLACK CAT | 矢吹健太朗 | 19.0 |
| 69593 | アジトにて | 矢吹健太郎 | 1.0 |
| 51536 | こちら葛飾区亀有公園前派出所 | 秋本治 | 19.0 |
| 69581 | 両さんの夏休み | 秋本治 | 1.0 |
| 69589 | デビルバッツV.S.蚊 | 稲垣理一郎 | 1.0 |
| 63117 | アイシールド21 | 稲垣理一郎 | 19.0 |
| 69577 | 恐怖のビーチ | 許斐剛 | 1.0 |
| 64287 | テニスの王子様 | 許斐剛 | 19.0 |
| 69578 | すいか割り日記 | 鈴木信也 | 1.0 |
| 65649 | Mr.FULLSWING | 鈴木信也 | 15.0 |
| 68907 | 遊☆戯☆王 | 高橋和希 | 19.0 |
| 69583 | 砂浜の遊☆戯☆王 | 高橋和希 | 1.0 |
| 69576 | ネコマジンみけ | 鳥山明 | 19.0 |
Show code cell content
# 可視化用に新たにDataFrameを作成
df_cm2 = df_cm.copy()
# add_jitter関数でランダムなノイズ(scaleで標準偏差を指定可能)を追加
# seedをそれぞれ指定することで再現性を確保
df_cm2["マンガ作品数(ジッタリング後)"] = add_jitter(
df_cm2["マンガ作品数"], scale=0.25, seed=0
)
df_cm2["マンガ作者数(ジッタリング後)"] = add_jitter(
df_cm2["マンガ作者数"], scale=0.25, seed=1
)
Show code cell content
# 可視化対象のDataFrameを確認
df_cm2.head()
| マンガ雑誌巻号名 | マンガ作品数 | マンガ作者数 | 合計ページ数 | 発売日 | 価格 | マンガ雑誌名 | マンガ作品数(ジッタリング後) | マンガ作者数(ジッタリング後) | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 週刊少年サンデー 1970年 表示号数32 | 12 | 14 | 284.0 | 1970-08-02 | 80.0 | 週刊少年サンデー | 12.441013 | 14.406086 |
| 1 | 週刊少年サンデー 1970年 表示号数33 | 12 | 16 | 307.0 | 1970-08-09 | 90.0 | 週刊少年サンデー | 12.100039 | 15.847061 |
| 2 | 週刊少年サンデー 1970年 表示号数34 | 13 | 17 | 314.0 | 1970-08-16 | 90.0 | 週刊少年サンデー | 13.244684 | 16.867957 |
| 3 | 週刊少年サンデー 1970年 表示号数35 | 13 | 17 | 305.0 | 1970-08-23 | 90.0 | 週刊少年サンデー | 13.560223 | 16.731758 |
| 4 | 週刊少年サンデー 1970年 表示号数36 | 13 | 17 | 305.0 | 1970-08-30 | 90.0 | 週刊少年サンデー | 13.466889 | 17.216352 |
Show code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_cm2, DIR_OUT_CM, "cm2")
DataFrame is saved as '../../../data/cm/output/vol2/04/scatter/cm2.csv'.
Show code cell source
# px.scatter関数を使用して散布図を作成
# x軸に作品数(ジッタリング後)、y軸に作者数(ジッタリング後)をプロット
# 各点には雑誌巻号名、発売日、雑誌名、作品数、作者数をホバー情報として表示
fig = px.scatter(
df_cm2,
x="マンガ作品数(ジッタリング後)",
y="マンガ作者数(ジッタリング後)",
hover_name="マンガ雑誌巻号名",
hover_data=["発売日", "マンガ雑誌名", "マンガ作品数", "マンガ作者数"],
)
# 散布図のマーカーのスタイルを更新
# サイズを10に設定し、線幅を1、透明度を0.5に設定
fig.update_traces(
marker={
"size": 10,
"line_width": 1,
"opacity": 0.5,
}
)
# 散布図を表示
show_fig(fig)
Show code cell source
# px.scatter関数を使用して散布図を作成
# x軸に作品数(ジッタリング後)、y軸に作者数(ジッタリング後)をプロット
# マンガ雑誌名に応じてOKABE_ITOパレットで色分けし、シンボルも変更
# 各点には雑誌巻号名、発売日、雑誌名、作品数、作者数をホバー情報として表示
fig = px.scatter(
df_cm2,
x="マンガ作品数(ジッタリング後)",
y="マンガ作者数(ジッタリング後)",
color="マンガ雑誌名",
symbol="マンガ雑誌名",
hover_name="マンガ雑誌巻号名",
hover_data=["発売日", "マンガ雑誌名", "マンガ作品数", "マンガ作者数"],
color_discrete_sequence=OKABE_ITO,
)
# 散布図のマーカーのスタイルを更新
# サイズを10に設定し、線幅を1、透明度を0.5に設定
fig.update_traces(
marker={
"size": 10,
"line_width": 1,
"opacity": 0.5,
}
)
# 散布図を表示
show_fig(fig)
Show code cell content
# 発売日をdatetime型に変換し、発売年情報を取得
df_cm2["発売年"] = pd.to_datetime(df_cm2["発売日"]).dt.year
Show code cell source
# px.scatter関数を使用して散布図を作成
# x軸に作品数(ジッタリング後)、y軸に作者数(ジッタリング後)を指定
# マンガ雑誌名に応じてファセットを分け、ファセットは最大2列で折り返す
# 各点には雑誌巻号名、発売日、雑誌名、作品数、作者数をホバー情報として表示
# 複数の散布図を同時に表示するため、heightを調整
fig = px.scatter(
df_cm2,
x="マンガ作品数(ジッタリング後)",
y="マンガ作者数(ジッタリング後)",
color="発売年",
facet_col="マンガ雑誌名",
facet_col_wrap=2,
hover_name="マンガ雑誌巻号名",
hover_data=["発売日", "マンガ雑誌名", "マンガ作品数", "マンガ作者数"],
height=600,
)
# 散布図のマーカーのスタイルを更新
# サイズを10に設定し、線幅を1、透明度を0.5に設定
fig.update_traces(
marker={
"size": 10,
"line_width": 1,
"opacity": 0.5,
}
)
# ファセット(雑誌ごとの散布図)のタイトルを簡潔にする処理
# デフォルトではタイトルは「雑誌名=xxx」という形式になっている
# この処理は「=」で文字列を分割して「xxx」の部分だけを取り出す
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))
# 散布図を表示
show_fig(fig)
アニメデータ#
Show code cell content
# pandasのread_csv関数でCSVファイルの読み込み
df_ae = pd.read_csv(DIR_AN / FN_AE)
df_ac_act = pd.read_csv(DIR_AN / FN_AC_ACT)
Show code cell content
# 可視化のための集計
# アニメ作品ごとの統計情報を集計して可視化用のデータフレームを作成
# 'acid'(アニメ作品ID)と'acname'(アニメ作品名)を基準にグルーピング
# 各アニメ作品ごとに'aeid'(各話ID)のユニーク数(各話数)と'date'(放送日)のユニーク数(放送日数)を計算
df_an = df_ae.groupby(["acid", "acname"])[["aeid", "date"]].nunique().reset_index()
# アニメ作品ごとに声優のユニーク数(声優数)を集計
# 'acid'(アニメ作品ID)を基準にグルーピングし、'actid'(声優ID)のユニーク数を計算
# その結果を辞書として保存し、アニメ作品IDをキーとして声優数を取得
acid2n_act = df_ac_act.groupby("acid")["actid"].nunique().to_dict()
df_an["n_act"] = df_an["acid"].apply(lambda x: acid2n_act.get(x, None))
# カラム名を変更して、結果をわかりやすくする
df_an = df_an.rename(
columns={
"acname": "アニメ作品名",
"aeid": "アニメ各話数",
"date": "放送日数",
"n_act": "声優数",
}
)
Show code cell content
# 可視化対象のDataFrameを確認
df_an.head()
| acid | アニメ作品名 | アニメ各話数 | 放送日数 | 声優数 | |
|---|---|---|---|---|---|
| 0 | C10001 | ギャラクシー エンジェル | 24 | 23 | 9.0 |
| 1 | C10003 | PROJECT ARMS | 26 | 26 | 11.0 |
| 2 | C10005 | 探偵少年カゲマン | 6 | 5 | 12.0 |
| 3 | C10006 | Mr.Digital TOKORO the comical cartoon [第1期] | 120 | 120 | NaN |
| 4 | C10008 | GEAR戦士[ギアファイター] 電童 | 38 | 38 | 10.0 |
Show code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_an, DIR_OUT_AN, "an")
DataFrame is saved as '../../../data/an/output/vol2/04/scatter/an.csv'.
Show code cell source
# アニメ作品の放送日数と各話数の関係を散布図で可視化
# '放送日数'をx軸に、'各話数'をy軸に取り、散布図を作成
# 'hover_name'引数に'アニメ作品名'を指定
fig = px.scatter(
df_an,
x="放送日数",
y="アニメ各話数",
hover_name="アニメ作品名",
)
# マーカーのスタイルを設定
# 'size'でマーカーのサイズを10に、'line_width'で境界線の幅を1に設定
# 'opacity'でマーカーの透明度を0.5に設定し、重複が多い部分の視認性を向上
fig.update_traces(
marker={
"size": 10,
"line_width": 1,
"opacity": 0.5,
}
)
# 散布図を表示
show_fig(fig)
Show code cell source
# 直線y=xの最小値と最大値を規定
# 最小値は0、最大値は散布図の最大値の1.1倍
x_line = [0, df_an["放送日数"].max() * 1.1]
# 2点を使ってy = xの直線を追加
fig.add_trace(go.Scatter(x=x_line, y=x_line, mode="lines", name="y=x"))
# 散布図を表示
show_fig(fig)
Show code cell content
# 全てのアニメ作品について、各話数が放送日数以上であることを確認
assert all(df_an["放送日数"] <= df_an["アニメ各話数"])
Show code cell content
# アニメ各話データにおいて、新世紀エヴァンゲリオンに部分一致するものを抽出
df_ae[df_ae["acname"].str.contains("新世紀エヴァンゲリオン")]
| aeid | aename | date | aeno | acid | acname | asid | |
|---|---|---|---|---|---|---|---|
| 9469 | M38296 | 第壱話 使徒、襲来 | 1995-10-04 | 第1話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9504 | M38297 | 第弐話 見知らぬ、天井 | 1995-10-11 | 第2話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9546 | M38298 | 第参話[縦書] 鳴らない、電 話 | 1995-10-18 | 第3話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9587 | M38299 | 第四話 雨、逃げ出した後 | 1995-10-25 | 第4話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9629 | M38300 | 第伍話 レイ、心のむこうに | 1995-11-01 | 第5話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9667 | M38301 | 第六話 決戦、第3新東京市 | 1995-11-08 | 第6話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9709 | M38302 | 第七話 人の造りしもの | 1995-11-15 | 第7話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9750 | M38303 | 第八話 アスカ、来日 | 1995-11-22 | 第8話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9790 | M38304 | 第九話 瞬間、心、重ねて | 1995-11-29 | 第9話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9829 | M38305 | 第拾話 マグマ ダイバー | 1995-12-06 | 第10話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9871 | M38306 | 第拾壱話 静止した闇の 中で | 1995-12-13 | 第11話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9912 | M38307 | 第拾弐話 奇跡の価値は | 1995-12-20 | 第12話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9952 | M38308 | 第拾参話 使徒、侵入 | 1995-12-27 | 第13話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9966 | M38309 | 第拾四話 ゼーレ、魂の座 | 1996-01-03 | 第14話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 9997 | M38310 | 第拾五話[縦書] 嘘*と沈黙 | 1996-01-10 | 第15話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 10036 | M38311 | 第拾六話[縦書] 死に至る 病、そして | 1996-01-17 | 第16話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 10077 | M38312 | 第拾七話 四人目 の適格者 | 1996-01-24 | 第17話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 10117 | M38313 | 第拾八話 命の 選択を | 1996-01-31 | 第18話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 10156 | M38314 | 第拾九話 男の戰い | 1996-02-07 | 第19話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 10196 | M38315 | 第弐拾話 心のかたち 人のかたち | 1996-02-14 | 第20話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 10234 | M38316 | 第弐拾壱話 ネルフ、誕生 | 1996-02-21 | 第21話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 10274 | M38317 | 第弐拾弐話 せめて、人間らしく | 1996-02-28 | 第22話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 10314 | M38318 | 第弐拾参話 涙 | 1996-03-06 | 第23話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 10354 | M38319 | 第弐拾四話 最後のシ者 | 1996-03-13 | 第24話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 10390 | M38320 | 第弐拾伍話 終わる世界 | 1996-03-20 | 第25話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
| 10419 | M38321 | 最終話 世界の中心で アイを叫んだ けもの | 1996-03-27 | 第26話 | C9249 | 新世紀エヴァンゲリオン | C1790 |
Show code cell content
# assignメソッドで放送日数-各話数を格納する列diffを一時的に作成し、それに基づき降順ソート
# headメソッドで上位5つを表示
df_an.assign(diff=df_an["アニメ各話数"] - df_an["放送日数"]).sort_values(
by="diff", ascending=False
).head()
| acid | アニメ作品名 | アニメ各話数 | 放送日数 | 声優数 | diff | |
|---|---|---|---|---|---|---|
| 3231 | C8849 | クレヨンしんちゃん | 1926 | 994 | 17.0 | 932 |
| 161 | C10364 | あたしンち | 668 | 333 | 17.0 | 335 |
| 2016 | C14783 | ふるさと 再生 日本の昔ばなし | 564 | 243 | 1.0 | 321 |
| 3131 | C7207 | サザエさん | 1175 | 855 | 10.0 | 320 |
| 2298 | C15087 | 妖怪ウォッチ | 374 | 151 | NaN | 223 |
Show code cell content
# アニメ各話データから、アニメ作品名がサザエさんのデータを抽出
df_ae[df_ae["acname"] == "サザエさん"]
| aeid | aename | date | aeno | acid | acname | asid | |
|---|---|---|---|---|---|---|---|
| 19266 | M20986 | もうすぐ ボーナス 作品No.4758(12/5) タラちゃん 走る 作品No.4759(1... | 1999-12-05 | 1550 | C7207 | サザエさん | C1945 |
| 19337 | M20987 | ワカメ ひみつの道草 作品No.4762(12/12) カツオ どこまで本当 作品No.47... | 1999-12-12 | 1551 | C7207 | サザエさん | C1945 |
| 19406 | M20988 | イクラの おばあ ちゃん 作品No.4764(12/19) わが家の リサイクル 作品No.... | 1999-12-19 | 1552 | C7207 | サザエさん | C1945 |
| 19470 | M20989 | ぼくたち 歳末障子組 作品No.4766(12/26) 今年最後の運だめし 作品No.476... | 1999-12-26 | 1553 | C7207 | サザエさん | C1945 |
| 19471 | M20990 | サザエさん一家の 珍諸国漫遊記(12/26) 75点の 天才!(再) | 1999-12-26 | S1 | C7207 | サザエさん | C1945 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 108216 | M21375 | 秘めたる 愛 情 作品No.7553 | 2016-12-18 | 2387B | C7207 | サザエさん | C1945 |
| 108217 | M21376 | サラリーマンの 休 日 作品No.7555 | 2016-12-18 | 2387C | C7207 | サザエさん | C1945 |
| 108346 | M21377 | ハチとタラちゃん 作品No.7556 | 2016-12-25 | 2388A | C7207 | サザエさん | C1945 |
| 108347 | M21378 | 暮れの 大仕事 作品No.7539 | 2016-12-25 | 2388B | C7207 | サザエさん | C1945 |
| 108348 | M21379 | おモチ 大好き 作品No.7208 | 2016-12-25 | 2388C | C7207 | サザエさん | C1945 |
1175 rows × 7 columns
ゲームデータ#
Show code cell content
# pandasのread_csv関数でCSVファイルの読み込み
df_pkg_pf = pd.read_csv(DIR_GM / FN_PKG_PF)
Show code cell content
# 可視化のための集計
# プラットフォームごとのパッケージ数、パブリッシャー数、平均価格を算出
# 'pfname'(プラットフォーム名)ごとに'pkgid'(パッケージID)、'publisher'(パブリッシャー)、
# そして'price'(価格)を集計
# 'pkgid'はユニークな値の数(パッケージ数)、'publisher'はユニークな値の数(パブリッシャー数)を計算
# 'price'は平均価格を計算
df_gm = (
df_pkg_pf.groupby("pfname")[["pkgid", "publisher", "price"]]
.agg({"pkgid": "nunique", "publisher": "nunique", "price": "mean"})
.reset_index()
)
# カラム名をわかりやすい名前に変更
df_gm = df_gm.rename(
columns={
"pfname": "プラットフォーム名",
"pkgid": "ゲームパッケージ数",
"publisher": "パブリッシャー数",
"price": "平均価格",
}
)
Show code cell content
# 可視化対象のDataFrameを確認
df_gm.head()
| プラットフォーム名 | ゲームパッケージ数 | パブリッシャー数 | 平均価格 | |
|---|---|---|---|---|
| 0 | 3DO | 115 | 68 | 8261.913043 |
| 1 | 64DD | 2 | 1 | NaN |
| 2 | ClassicMacOS | 13 | 3 | 615.384615 |
| 3 | MSX | 1 | 1 | 5800.000000 |
| 4 | MSX2 | 4 | 4 | 8800.000000 |
Show code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_gm, DIR_OUT_GM, "gm")
DataFrame is saved as '../../../data/gm/output/vol2/04/scatter/gm.csv'.
Show code cell source
# プラットフォームごとのパッケージ数とパブリッシャー数の関係を散布図で可視化
# 'df_gm'データフレームを用いて、x軸に'パッケージ数'、y軸に'パブリッシャー数'をプロット
# 各点はプラットフォームを表し、ホバーすると'プラットフォーム名'が表示される
fig = px.scatter(
df_gm,
x="ゲームパッケージ数",
y="パブリッシャー数",
hover_name="プラットフォーム名",
)
# 散布図のマーカーのスタイルを設定
# サイズは10、線の幅は1、透明度は0.5(重複が多いため)
fig.update_traces(
marker={
"size": 10,
"line_width": 1,
"opacity": 0.5,
}
)
# 散布図を表示
show_fig(fig)
Show code cell content
# PF2MKに格納されているプラットフォームのみ抽出
df_gm2 = df_gm[df_gm["プラットフォーム名"].isin(PF2MK.keys())].reset_index(drop=True)
# PF2MKを用いて、プラットフォーム名からメーカー名をマッピング
df_gm2["メーカー名"] = df_gm2["プラットフォーム名"].map(PF2MK)
Show code cell content
# 可視化対象のDataFrameを確認
df_gm2.head()
| プラットフォーム名 | ゲームパッケージ数 | パブリッシャー数 | 平均価格 | メーカー名 | |
|---|---|---|---|---|---|
| 0 | NINTENDO64 | 160 | 51 | 7054.012500 | 任天堂 |
| 1 | NintendoSwitch | 320 | 97 | 3370.728435 | 任天堂 |
| 2 | SC-3000 | 2 | 1 | 4300.000000 | セガ |
| 3 | SEGAマーク3 | 9 | 1 | 4944.444444 | セガ |
| 4 | SG-1000 | 2 | 1 | 4300.000000 | セガ |
Show code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_gm2, DIR_OUT_GM, "gm2")
DataFrame is saved as '../../../data/gm/output/vol2/04/scatter/gm2.csv'.
Show code cell source
# プラットフォームごとのパッケージ数とパブリッシャー数の関係を散布図で可視化
# 'df_gm2'データフレームを用いて、x軸に'パッケージ数'、y軸に'パブリッシャー数'を指定
# 'メーカー名'に応じてOKABE_ITOテーマで配色し、シンボルも変更
# 各点はプラットフォームを表し、ホバーすると'プラットフォーム名'が表示される
fig = px.scatter(
df_gm2,
x="ゲームパッケージ数",
y="パブリッシャー数",
color="メーカー名",
symbol="メーカー名",
hover_name="プラットフォーム名",
color_discrete_sequence=OKABE_ITO,
)
# 散布図のマーカーのスタイルを設定
# サイズは10、線の幅は1、透明度は0.5(重複が多いため)
fig.update_traces(
marker={
"size": 10,
"line_width": 1,
"opacity": 0.5,
}
)
# 散布図を表示
show_fig(fig)