メディア展開データの前処理#
本書の再現に、前処理の再実行は不要
前処理後のデータは全てvizbook-jupyter/data/*以下に格納されています。
本書の再現のため、前処理を再実行頂く必要はありません。
(仮に再実行したとしても、同じファイルが出力されるだけですので問題はありません。)
準備#
Import#
Show code cell content
# warningsモジュールのインポート
import warnings
# データ解析や機械学習のライブラリ使用時の警告を非表示にする目的で警告を無視
# 本書の文脈では、可視化の学習に議論を集中させるために選択した
# ただし、学習以外の場面で、警告を無視する設定は推奨しない
warnings.filterwarnings("ignore")
Show 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
変数#
Show 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")
Show 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"
関数#
Show 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)
出力先の生成#
Show code cell content
# DIR_OUTPUTという名前のディレクトリを作成する
# すでに存在する場合は何もしない
DIR_OUTPUT.mkdir(exist_ok=True, parents=True)
ac_cc.csvの準備#
Show code cell content
# DIR_EXTERNALディレクトリから、FN_AC_CCファイルを読み込み
df_ac_cc = pd.read_csv(DIR_EXTERNAL / FN_AC_CC)
Show 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への出力#
Show 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#
Show 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
)
Show code cell content
# アニメ作品のID(`acid`)とアニメ各話のID(`aeid`)を基準にデータを昇順にソートする
df_mix_ae_crt = df_mix_ae_crt.sort_values(["acid", "aeid"], ignore_index=True)
Show code cell content
# date列が存在する行のみ抽出
df_mix_ae_crt = df_mix_ae_crt.dropna(subset=["date"], ignore_index=True)
Show 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 | 皆川亮二 | 皆川亮二 | 皆川亮二 | 皆川亮二 | 皆川亮二 |
Show code cell content
# `aeid`と`crtid`の組み合わせで重複がないことを確認
assert df_mix_ae_crt.duplicated(subset=["aeid", "crtid"]).sum() == 0
Show 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#
Show 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"}
)
Show 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"}
)
Show 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 |
Show code cell content
# `df_mix_ce_ac`で、`ceid`と`acid`の組み合わせが重複していないことを確認
assert df_mix_ce_ac.duplicated(subset=["ceid", "acid"]).sum() == 0
Show 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)