等値線図#
準備#
Import#
Show code cell content
# warningsモジュールのインポート
import warnings
# データ解析や機械学習のライブラリ使用時の警告を非表示にする目的で警告を無視
# 本書の文脈では、可視化の学習に議論を集中させるために選択した
# ただし、学習以外の場面で、警告を無視する設定は推奨しない
warnings.filterwarnings("ignore")
Show code cell content
# pathlibモジュールのインポート
# ファイルシステムのパスを扱う
from pathlib import Path
# typingモジュールからの型ヒント関連のインポート
# 関数やクラスの引数・返り値の型を注釈するためのツール
from typing import Any, Dict, List, Optional, Union
# numpy:数値計算ライブラリのインポート
# npという名前で参照可能
import numpy as np
# pandas:データ解析ライブラリのインポート
# pdという名前で参照可能
import pandas as pd
# plotly.expressのインポート
# インタラクティブなグラフ作成のライブラリ
# pxという名前で参照可能
import plotly.express as px
# 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] / "contour"
)
# アニメデータの分析結果の出力先ディレクトリのパス
DIR_OUT_AN = (
DIR_AN.parent / "output" / Path.cwd().parts[-2] / Path.cwd().parts[-1] / "contour"
)
# ゲームデータの分析結果の出力先ディレクトリのパス
DIR_OUT_GM = (
DIR_GM.parent / "output" / Path.cwd().parts[-2] / Path.cwd().parts[-1] / "contour"
)
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
# plotlyの描画設定の定義
# plotlyのグラフ描画用レンダラーの定義
# Jupyter Notebook環境のグラフ表示に適切なものを選択
RENDERER = "plotly_mimetype+notebook"
関数#
Show code cell source
def show_fig(fig: Figure) -> None:
"""
所定のレンダラーを用いてplotlyの図を表示
Jupyter Bookなどの環境での正確な表示を目的とする
Parameters
----------
fig : Figure
表示対象のplotly図
Returns
-------
None
"""
# 図の周囲の余白を設定
# t: 上余白
# l: 左余白
# r: 右余白
# b: 下余白
fig.update_layout(margin=dict(t=25, l=25, r=25, b=25))
# 所定のレンダラーで図を表示
fig.show(renderer=RENDERER)
Show code cell content
def format_cols(df: pd.DataFrame, cols_rename: Dict[str, str]) -> pd.DataFrame:
"""
指定されたカラムのみをデータフレームから抽出し、カラム名をリネームする関数
Parameters
----------
df : pd.DataFrame
入力データフレーム
cols_rename : Dict[str, str]
リネームしたいカラム名のマッピング(元のカラム名: 新しいカラム名)
Returns
-------
pd.DataFrame
カラムが抽出・リネームされたデータフレーム
"""
# 指定されたカラムのみを抽出し、リネーム
df = df[cols_rename.keys()].rename(columns=cols_rename)
return df
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/contour/cm.csv'.
Show code cell source
# 等値線図を作成
# X軸として作品数を、Y軸として作者数を指定
fig = px.density_contour(df_cm, x="マンガ作品数", y="マンガ作者数")
# 視認性のため、度数に応じた塗り分けと数値の付記を設定
fig.update_traces(contours_coloring="fill", contours_showlabels=True)
# 等値線図を描画
show_fig(fig)
Show code cell source
# 等値線図を作成
# X軸として作品数を、Y軸として作者数を指定
# マンガ雑誌別に2列でファセットを分け、高さを調整
fig = px.density_contour(
df_cm,
x="マンガ作品数",
y="マンガ作者数",
facet_col="マンガ雑誌名",
facet_col_wrap=2,
height=600,
)
# 視認性を増すため、度数に応じた塗り分けと数値の付記を設定
# カラーバーの表示が壊れるのでshowscaleはFalseに
fig.update_traces(contours_coloring="fill", contours_showlabels=True, showscale=False)
# ファセット(マンガ雑誌ごとの等値線図)のタイトルを簡潔にする処理
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)
Show code cell content
# acid、acnameごとにdateの最小値(初回放送日)を集計
df_an = (
df_ae.groupby(["acid", "acname"])
.agg({"date": "min", "aeid": "nunique"})
.reset_index()
)
# dateをdatetime型に変換
df_an["date"] = pd.to_datetime(df_an["date"])
# acnameの文字数を取得して格納
df_an["l_acname"] = df_an["acname"].str.len()
# 可視化用に列名を変更
df_an = df_an.rename(
columns={"date": "初回放送日", "l_acname": "作品名の文字数", "aeid": "アニメ各話数"}
)
Show code cell content
# 可視化対象のDataFrameを確認
df_an.head()
| acid | acname | 初回放送日 | アニメ各話数 | 作品名の文字数 | |
|---|---|---|---|---|---|
| 0 | C10001 | ギャラクシー エンジェル | 2001-04-08 | 24 | 12 |
| 1 | C10003 | PROJECT ARMS | 2001-04-08 | 26 | 12 |
| 2 | C10005 | 探偵少年カゲマン | 2001-11-28 | 6 | 8 |
| 3 | C10006 | Mr.Digital TOKORO the comical cartoon [第1期] | 2000-10-03 | 120 | 43 |
| 4 | C10008 | GEAR戦士[ギアファイター] 電童 | 2000-10-04 | 38 | 19 |
Show code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_an, DIR_OUT_AN, "an")
DataFrame is saved as '../../../data/an/output/vol2/04/contour/an.csv'.
Show code cell source
# 等値線図を作成
# X軸として各話数を、Y軸として作品名の文字数を指定
fig = px.density_contour(df_an, x="アニメ各話数", y="作品名の文字数")
# 視認性のため、度数に応じた塗り分けと数値の付記を設定
fig.update_traces(contours_coloring="fill", contours_showlabels=True)
# 等値線図を表示
show_fig(fig)
Show code cell content
# 各話数が100話以内、かつ作品名の文字数が50文字以内のアニメ作品に限定
df_an2 = df_an[
(df_an["アニメ各話数"] <= 100) & (df_an["作品名の文字数"] <= 50)
].reset_index(drop=True)
Show code cell content
# 可視化対象のDataFrameの確認
df_an2.head()
| acid | acname | 初回放送日 | アニメ各話数 | 作品名の文字数 | |
|---|---|---|---|---|---|
| 0 | C10001 | ギャラクシー エンジェル | 2001-04-08 | 24 | 12 |
| 1 | C10003 | PROJECT ARMS | 2001-04-08 | 26 | 12 |
| 2 | C10005 | 探偵少年カゲマン | 2001-11-28 | 6 | 8 |
| 3 | C10008 | GEAR戦士[ギアファイター] 電童 | 2000-10-04 | 38 | 19 |
| 4 | C10010 | グラビテーション | 2000-10-04 | 13 | 8 |
Show code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_an2, DIR_OUT_AN, "an2")
DataFrame is saved as '../../../data/an/output/vol2/04/contour/an2.csv'.
Show code cell source
# 等値線図を作成
# X軸として各話数を、Y軸として作品名の文字数を指定
fig = px.density_contour(df_an2, x="アニメ各話数", y="作品名の文字数")
# 視認性のため、度数に応じた塗り分けと数値の付記を設定
fig.update_traces(contours_coloring="fill", contours_showlabels=True)
# 等値線図を表示
show_fig(fig)
ゲームデータ#
Show code cell content
# pandasのread_csv関数でCSVファイルの読み込み
df_pkg_pf = pd.read_csv(DIR_GM / FN_PKG_PF)
Show code cell content
# pkgidが重複しているものを可視化対象から除外
df_gm = df_pkg_pf[~df_pkg_pf["pkgid"].duplicated(keep=False)].reset_index(drop=True)
# 可視化用にdateをdatetime型に変換
df_gm["date"] = pd.to_datetime(df_gm["date"])
# dateで昇順ソートし、インデックスを新たに張替え
df_gm = df_gm.sort_values("date", ignore_index=True)
# 可視化用に列名を変更
cols_gm = {
"pkgid": "パッケージID",
"date": "ゲームパッケージの発売日",
"price": "価格",
"pfname": "プラットフォーム名",
}
df_gm = format_cols(df_gm, cols_gm)
Show code cell content
# 可視化対象のDataFrameを確認
df_gm.head()
| パッケージID | ゲームパッケージの発売日 | 価格 | プラットフォーム名 | |
|---|---|---|---|---|
| 0 | M735723 | 1982-04-25 | 3500.0 | PC-8801 |
| 1 | M735295 | 1982-05-25 | 3500.0 | PC-8801 |
| 2 | M735396 | 1982-06-25 | 3500.0 | PC-8801 |
| 3 | M735265 | 1982-07-25 | 3500.0 | PC-8801 |
| 4 | M735557 | 1982-08-01 | 16500.0 | PC-8801 |
Show code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_gm, DIR_OUT_GM, "gm")
DataFrame is saved as '../../../data/gm/output/vol2/04/contour/gm.csv'.
Show code cell source
# 等値線図を作成
# X軸として発売日を、Y軸として価格を指定
fig = px.density_contour(df_gm, x="ゲームパッケージの発売日", y="価格")
# 視認性を増すため、度数に応じた塗り分けと数値の付記を設定
fig.update_traces(contours_coloring="fill", contours_showlabels=True)
# 等値線図を表示
show_fig(fig)
Show code cell content
# 10000円以下のゲームパッケージに限定
df_gm2 = df_gm[df_gm["価格"] <= 10000].reset_index(drop=True)
Show code cell content
# 可視化対象のDataFrameを確認
df_gm2.head()
| パッケージID | ゲームパッケージの発売日 | 価格 | プラットフォーム名 | |
|---|---|---|---|---|
| 0 | M735723 | 1982-04-25 | 3500.0 | PC-8801 |
| 1 | M735295 | 1982-05-25 | 3500.0 | PC-8801 |
| 2 | M735396 | 1982-06-25 | 3500.0 | PC-8801 |
| 3 | M735265 | 1982-07-25 | 3500.0 | PC-8801 |
| 4 | M735792 | 1982-08-01 | 6500.0 | PC-8801 |
Show code cell content
# 可視化対象DataFrameを保存
save_df_to_csv(df_gm2, DIR_OUT_GM, "gm2")
DataFrame is saved as '../../../data/gm/output/vol2/04/contour/gm2.csv'.
Show code cell source
# 等値線図を作成
# X軸として発売日を、Y軸として価格を指定
fig = px.density_contour(df_gm2, x="ゲームパッケージの発売日", y="価格")
# 視認性を増すため、度数に応じた塗り分けと数値の付記を設定
fig.update_traces(contours_coloring="fill", contours_showlabels=True)
# 等値線図を表示
show_fig(fig)
Show code cell source
# 価格を1000で割った余りを格納する列を追加
df_gm2["価格%1000"] = df_gm2["価格"] % 1000
# 等値線図を作成
# X軸として発売日を、Y軸として価格%1000を指定
fig = px.density_contour(df_gm2, x="ゲームパッケージの発売日", y="価格%1000")
# 視認性を増すため、度数に応じた塗り分けと数値の付記を設定
fig.update_traces(contours_coloring="fill", contours_showlabels=True)
# 等値線図を表示
show_fig(fig)