メディア展開データの前処理#

本書の再現に、前処理の再実行は不要

前処理後のデータは全てvizbook-jupyter/data/*以下に格納されています。 本書の再現のため、前処理を再実行頂く必要はありません。 (仮に再実行したとしても、同じファイルが出力されるだけですので問題はありません。)

準備#

Import#

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

# データ解析や機械学習のライブラリ使用時の警告を非表示にする目的で警告を無視
# 本書の文脈では、可視化の学習に議論を集中させるために選択した
# ただし、学習以外の場面で、警告を無視する設定は推奨しない
warnings.filterwarnings("ignore")
Hide code cell content
# jsonモジュールのインポート
# JSON形式のデータの読み書きをサポート
import json

# osモジュールのインポート
# オペレーティングシステムとのインターフェースを提供
import os

# reモジュールのインポート
# 正規表現操作をサポート
import re

# zipfileモジュールのインポート
# ZIPアーカイブファイルの読み書きをサポート
import zipfile

# pathlibモジュールのインポート
# ファイルシステムのパスを扱う
from pathlib import Path

# pprintモジュールのインポート
# データ構造を見やすく整形して表示するための関数
from pprint import pprint

# typingモジュールからの型ヒント関連のインポート
# 関数やクラスの引数・返り値の型を注釈するためのツール
from typing import Any, Dict, List, Optional, Union

# ijsonモジュールのインポート
# ストリームから大きなJSONオブジェクトを効率的に解析・抽出
import ijson

# numpy:数値計算ライブラリのインポート
# npという名前で参照可能
import numpy as np

# pandas:データ解析ライブラリのインポート
# pdという名前で参照可能
import pandas as pd

# tqdm_notebookのインポート
# Jupyter Notebook内でのプログレスバー表示をサポート
from tqdm import tqdm_notebook as tqdm

変数#

Hide code cell content
# 入出力ディレクトリの定義

# マンガデータの中間出力ファイルが格納されているディレクトリのパス
DIR_CM = Path("../../../data/cm/interim")

# アニメデータの中間出力ファイルが格納されているディレクトリのパス
DIR_AN = Path("../../../data/an/interim")

# 外部データソースから作成したファイルを格納しているディレクトリのパス
# (今回は、事前に作成したマンガ作品とアニメ作品の紐づけファイル)
DIR_EXTERNAL = Path("../../../data/mix/external")

# 出力ファイルを保存するディレクトリのパス
DIR_OUTPUT = Path("../../../data/mix/input")
Hide code cell content
# アニメ作品の結合用データのファイル名を定義
FN_AC_MERGE = "ac_merge.csv"

# アニメ各話に関するデータのファイル名を定義
FN_AE = "ae.csv"

# マンガ作品の結合用データのファイル名を定義
FN_CC_MERGE = "cc_merge.csv"

# マンガ作品とマンガ作者の対応関係に関するデータのファイル名を定義
FN_CC_CRT = "cc_crt.csv"

# マンガ各話に関するデータのファイル名を定義
FN_CE = "ce.csv"

# マンガ作者に関するデータのファイル名を定義
FN_CRT = "crt.csv"

# マンガ雑誌巻号に関するデータのファイル名を定義
FN_MI = "mi.csv"

# アニメ作品とマンガ作品の対応関係に関するデータのファイル名を定義
FN_AC_CC = "ac_cc.csv"

関数#

Hide code cell content
def save_json(path: Union[str, Path], dct: Dict) -> None:
    """
    辞書をjson形式で保存

    Parameters
    ----------
    path : Union[str, Path]
        保存先のファイルパス
    dct : Dict
        保存する辞書

    Returns
    -------
    None
    """

    # 指定したパスのjsonファイルを書き込みモードで開く
    with open(path, "w", encoding="utf-8") as f:
        # json.dumpを使用して、辞書の内容をjson形式でファイルに書き込む
        # ensure_ascii=Falseで非ASCII文字もそのまま保存し、indent=4で整形して保存
        json.dump(dct, f, ensure_ascii=False, indent=4)

出力先の生成#

Hide code cell content
# DIR_OUTPUTという名前のディレクトリを作成する
# すでに存在する場合は何もしない
DIR_OUTPUT.mkdir(exist_ok=True, parents=True)

ac_cc.csvの準備#

Hide code cell content
# DIR_EXTERNALディレクトリから、FN_AC_CCファイルを読み込み
df_ac_cc = pd.read_csv(DIR_EXTERNAL / FN_AC_CC)
Hide code cell content
# head()メソッドを利用して先頭5行を確認
df_ac_cc.head()
acid ccid
0 C10003 C92062
1 C10012 C91434
2 C10016 C91240
3 C10026 C92178
4 C10030 C93085

DIR_OUTPUTへの出力#

Hide code cell content
# ファイルから各データフレームを読み込む

# アニメ作品に関する情報を読み込む
df_ac_merge = pd.read_csv(DIR_AN / FN_AC_MERGE)
# アニメ各話に関する情報を読み込む
df_ae = pd.read_csv(DIR_AN / FN_AE)

# マンガ作品に関する情報を読み込む
df_cc_merge = pd.read_csv(DIR_CM / FN_CC_MERGE)
# マンガ作品とマンガ作者の対応関係に関する情報を読み込む
df_cc_crt = pd.read_csv(DIR_CM / FN_CC_CRT)
# マンガ各話に関する情報を読み込む
df_ce = pd.read_csv(DIR_CM / FN_CE)
# マンガ作者に関する情報を読み込む
df_crt = pd.read_csv(DIR_CM / FN_CRT)
# マンガ雑誌巻号に関する情報を読み込む
df_mi = pd.read_csv(DIR_CM / FN_MI)

# マンガ作品とアニメ作品の対応関係に関する情報を読み込む
df_ac_cc = pd.read_csv(DIR_EXTERNAL / FN_AC_CC)

mix_ae_crt.csv#

Hide code cell content
# アニメ各話のデータとアニメ作品の統合データをマージする
df_mix_ae_crt = pd.merge(df_ae, df_ac_merge, on="acid", how="inner").reset_index(
    drop=True
)

# 上記の結果とアニメ作品とマンガ作品の関連データをさらにマージする
df_mix_ae_crt = pd.merge(df_mix_ae_crt, df_ac_cc, on="acid", how="inner").reset_index(
    drop=True
)

# 上記の結果とマンガ作品とマンガ作者の関連データをさらにマージする
df_mix_ae_crt = pd.merge(df_mix_ae_crt, df_cc_crt, on="ccid", how="inner").reset_index(
    drop=True
)

# 上記の結果とマンガ作品の統合データの一部をマージする
df_mix_ae_crt = pd.merge(
    df_mix_ae_crt, df_cc_merge[["ccid", "ccname", "mcname"]], on="ccid", how="inner"
).reset_index(drop=True)

# 最後に、上記の結果とマンガ作者のデータをマージする
df_mix_ae_crt = pd.merge(df_mix_ae_crt, df_crt, on="crtid", how="inner").reset_index(
    drop=True
)
Hide code cell content
# アニメ作品のID(`acid`)とアニメ各話のID(`aeid`)を基準にデータを昇順にソートする
df_mix_ae_crt = df_mix_ae_crt.sort_values(["acid", "aeid"], ignore_index=True)
Hide code cell content
# date列が存在する行のみ抽出
df_mix_ae_crt = df_mix_ae_crt.dropna(subset=["date"], ignore_index=True)
Hide code cell content
# head()メソッドを用いて、先頭5行を転置して表示
df_mix_ae_crt.head().T
0 1 2 3 4
aeid M53249 M53250 M53251 M53252 M53253
aename 共 振 バイブレーション 発 動 トランス 悪 夢 ナイトメア 迎 撃 インターセプト 反 撃 カウンターアタック
date 2001-04-08 2001-04-15 2001-04-22 2001-04-29 2001-05-06
aeno 1 2 3 4 5
acid C10003 C10003 C10003 C10003 C10003
acname PROJECT ARMS PROJECT ARMS PROJECT ARMS PROJECT ARMS PROJECT ARMS
asid C2484 C2484 C2484 C2484 C2484
n_ae 26 26 26 26 26
first_date 2001-04-08 2001-04-08 2001-04-08 2001-04-08 2001-04-08
last_date 2001-09-30 2001-09-30 2001-09-30 2001-09-30 2001-09-30
ccid C92062 C92062 C92062 C92062 C92062
crtid CCRT02576 CCRT02576 CCRT02576 CCRT02576 CCRT02576
ccname ARMS ARMS ARMS ARMS ARMS
mcname 週刊少年サンデー 週刊少年サンデー 週刊少年サンデー 週刊少年サンデー 週刊少年サンデー
crtname 皆川亮二 皆川亮二 皆川亮二 皆川亮二 皆川亮二
Hide code cell content
# `aeid`と`crtid`の組み合わせで重複がないことを確認
assert df_mix_ae_crt.duplicated(subset=["aeid", "crtid"]).sum() == 0
Hide code cell content
# データフレーム`df_mix_ae_crt`をCSVファイルとして保存
# 保存先のパスは、`DIR_OUTPUT`ディレクトリ内の`mix_ae_crt.csv`
df_mix_ae_crt.to_csv(DIR_OUTPUT / "mix_ae_crt.csv", index=False)

mix_ce_ac.csv#

Hide code cell content
# アニメ作品とマンガ作品のマージ用のデータフレーム`df_ac_cc_merge`を作成する
# `ccid`に複数の`acid`が紐づいている場合、`first_date`が最も早いものを選択する
df_ac_cc_merge = pd.merge(df_ac_cc, df_ac_merge, on="acid", how="inner").reset_index(
    drop=True
)
df_ac_cc_merge = df_ac_cc_merge.sort_values(["ccid", "first_date"], ignore_index=True)
df_ac_cc_merge = df_ac_cc_merge.drop_duplicates("ccid", ignore_index=True)

# 可読性向上のため、一部の列名を変更する
df_ac_cc_merge = df_ac_cc_merge.rename(
    columns={"first_date": "first_date_ac", "last_date": "last_date_ac"}
)
Hide code cell content
# マンガ各話のデータフレーム`df_ce`とマンガ雑誌巻号のデータフレーム`df_mi`を統合する
# 主に雑誌発売日の情報を追加することが目的
df_mix_ce_ac = pd.merge(
    df_ce, df_mi[["miid", "date"]], on="miid", how="left"
).reset_index(drop=True)

# 上記の結果とマンガ作品のデータフレーム`df_cc_merge`を統合する
df_mix_ce_ac = pd.merge(df_mix_ce_ac, df_cc_merge, on="ccid", how="inner").reset_index(
    drop=True
)

# 上記の結果とアニメ作品のマンガ作品とのマッピングデータフレーム`df_ac_cc_merge`をさらに統合する
df_mix_ce_ac = pd.merge(
    df_mix_ce_ac, df_ac_cc_merge, on="ccid", how="left"
).reset_index(drop=True)

# 列名が重複するため、マンガ作品の公開日情報の列名を変更して可読性を向上させる
df_mix_ce_ac = df_mix_ce_ac.rename(
    columns={"first_date": "first_date_cc", "last_date": "last_date_cc"}
)
Hide code cell content
# head()メソッドを用いて先頭5行を、見やすいように転置して表示
df_mix_ce_ac.head().T
0 1 2 3 4
ceid CE00000 CE00026 CE00062 CE00086 CE00112
cename 第238話/この世代 第237話/トーナメント 第236話/絆 第235話/指先から… 第234話/何にも出来ないワケじゃない
ccid C90829 C90829 C90829 C90829 C90829
miid M535428 M535429 M535430 M535431 M535432
page_start 10.0 125.0 223.0 183.0 221.0
page_end 31.0 144.0 242.0 204.0 240.0
pages 22.0 20.0 20.0 22.0 20.0
page_start_position 0.021368 0.23855 0.478541 0.405765 0.472222
two_colored False False False False False
four_colored True False False False False
date 2011-05-25 2011-05-18 2011-05-04 2011-04-27 2011-04-20
ccname ダイヤのA ダイヤのA ダイヤのA ダイヤのA ダイヤのA
n_ce 425 425 425 425 425
n_2c 0 0 0 0 0
n_4c 39 39 39 39 39
first_date_cc 2006-05-31 2006-05-31 2006-05-31 2006-05-31 2006-05-31
last_date_cc 2016-01-08 2016-01-08 2016-01-08 2016-01-08 2016-01-08
mcid C119033 C119033 C119033 C119033 C119033
mcname 週刊少年マガジン 週刊少年マガジン 週刊少年マガジン 週刊少年マガジン 週刊少年マガジン
acid C14866 C14866 C14866 C14866 C14866
acname ダイヤのA[エース] ダイヤのA[エース] ダイヤのA[エース] ダイヤのA[エース] ダイヤのA[エース]
asid C5641 C5641 C5641 C5641 C5641
n_ae 75.0 75.0 75.0 75.0 75.0
first_date_ac 2013-10-06 2013-10-06 2013-10-06 2013-10-06 2013-10-06
last_date_ac 2015-03-29 2015-03-29 2015-03-29 2015-03-29 2015-03-29
Hide code cell content
# `df_mix_ce_ac`で、`ceid`と`acid`の組み合わせが重複していないことを確認
assert df_mix_ce_ac.duplicated(subset=["ceid", "acid"]).sum() == 0
Hide code cell content
# データフレーム`df_mix_ce_ac`をCSVファイルとして保存
# 保存先のパスは、`DIR_OUTPUT`ディレクトリ内の`mix_ce_ac.csv`
df_mix_ce_ac.to_csv(DIR_OUTPUT / "mix_ce_ac.csv", index=False)