散布図#

準備#

Import#

Hide code cell content
# warningsモジュールのインポート
import warnings

# データ解析や機械学習のライブラリ使用時の警告を非表示にする目的で警告を無視
# 本書の文脈では、可視化の学習に議論を集中させるために選択した
# ただし、学習以外の場面で、警告を無視する設定は推奨しない
warnings.filterwarnings("ignore")
Hide 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

変数#

Hide 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"
)
Hide 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"
Hide code cell content
# 国内主要ゲームメーカーのプラットフォームとメーカー名の対応辞書
# キー: プラットフォーム名、値: メーカー名の略称
PF2MK = {
    "プレイステーション": "ソニー",
    "プレイステーション2": "ソニー",
    "プレイステーション・ポータブル": "ソニー",
    "プレイステーション3": "ソニー",
    "プレイステーションVita": "ソニー",
    "プレイステーション4": "ソニー",
    "ゲームアーカイブス": "ソニー",
    "SG-1000": "セガ",
    "SC-3000": "セガ",
    "SEGAマーク3": "セガ",
    "セガ・マスターシステム": "セガ",
    "メガドライブ": "セガ",
    "ゲームギア": "セガ",
    "セガサターン": "セガ",
    "ドリームキャスト": "セガ",
    "ファミリーコンピュータ": "任天堂",
    "ゲームボーイ": "任天堂",
    "スーパーファミコン": "任天堂",
    "NINTENDO64": "任天堂",
    "ゲームボーイアドバンス": "任天堂",
    "ニンテンドーゲームキューブ": "任天堂",
    "ニンテンドーDS": "任天堂",
    "ニンテンドー3DS": "任天堂",
    "Wii": "任天堂",
    "WiiU": "任天堂",
    "NintendoSwitch": "任天堂",
}
Hide 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)
]
Hide code cell content
# plotlyの描画設定の定義

# plotlyのグラフ描画用レンダラーの定義
# Jupyter Notebook環境のグラフ表示に適切なものを選択
RENDERER = "plotly_mimetype+notebook"

関数#

Hide 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)
Hide 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
Hide 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}'.")

可視化例#

マンガデータ#

Hide 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)
Hide 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": "マンガ雑誌名",
    }
)
Hide 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 週刊少年サンデー
Hide 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'.
Hide 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)
Hide 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)
Hide 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
Hide 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
Hide 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
)
Hide 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
Hide 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'.
Hide 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)
Hide 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)
Hide code cell content
# 発売日をdatetime型に変換し、発売年情報を取得
df_cm2["発売年"] = pd.to_datetime(df_cm2["発売日"]).dt.year
Hide 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)

アニメデータ#

Hide 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)
Hide 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": "声優数",
    }
)
Hide 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
Hide 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'.
Hide 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)
Hide 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)
Hide code cell content
# 全てのアニメ作品について、各話数が放送日数以上であることを確認
assert all(df_an["放送日数"] <= df_an["アニメ各話数"])
Hide 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
Hide 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
Hide 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

ゲームデータ#

Hide code cell content
# pandasのread_csv関数でCSVファイルの読み込み
df_pkg_pf = pd.read_csv(DIR_GM / FN_PKG_PF)
Hide 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": "平均価格",
    }
)
Hide 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
Hide 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'.
Hide 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)
Hide code cell content
# PF2MKに格納されているプラットフォームのみ抽出
df_gm2 = df_gm[df_gm["プラットフォーム名"].isin(PF2MK.keys())].reset_index(drop=True)
# PF2MKを用いて、プラットフォーム名からメーカー名をマッピング
df_gm2["メーカー名"] = df_gm2["プラットフォーム名"].map(PF2MK)
Hide 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 セガ
Hide 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'.
Hide 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)