上巻 第4章 練習問題#

ここでは、 本書の学習内容の定着 を目的とした練習問題を掲載します。 解答・解説は「解答例」ページを参照してください。 なお、問題の性質上、本書で取り上げた処理と重複することがあります。 ご了承ください。

前提#

以下のように、ライブラリのインポートと変数の定義が完了していることを前提とします。

Hide code cell content
# itertoolsモジュールのインポート
# 様々なパターンのループを効率的に実行可能
import itertools

# 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からFigureクラスのインポート
# 型ヒントの利用を主目的とする
from plotly.graph_objects import Figure
Hide code cell content
# データ格納ディレクトリのパス
DIR_IN = Path("../../../data/cm/input")

# ファイル名の定義
FN_CE = "cm_ce.csv"
FN_CC_CRT = "cm_cc_crt.csv"

# plotlyの描画設定の定義
# Jupyter Notebook環境のグラフ表示に適切なものを選択
RENDERER = "plotly_mimetype+notebook"
Hide code cell content
# 質的変数の描画用のカラースケールの定義(Okabe and Ito 2008基準)
OKABE_ITO = [
    "#000000",  # 黒 (Black)
    "#E69F00",  # 橙 (Orange)
    "#56B4E9",  # 薄青 (Sky Blue)
    "#009E73",  # 青緑 (Bluish Green)
    "#F0E442",  # 黄色 (Yellow)
    "#0072B2",  # 青 (Blue)
    "#D55E00",  # 赤紫 (Vermilion)
    "#CC79A7",  # 紫 (Reddish Purple)
]

また、本書中で取り上げた以下の関数も、同様に利用可能とします。

Hide 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)
Hide code cell content
def add_years_to_df(
    df: pd.DataFrame, unit_years: int = 10, col_date: str = "date"
) -> pd.DataFrame:
    """
    データフレームにunit_years単位で区切った年数を示す新しい列を追加

    Parameters
    ----------
    df : pd.DataFrame
        入力データフレーム
    unit_years : int, optional
        年数を区切る単位、デフォルトは10
    col_date : str, optional
        日付を含むカラム名、デフォルトは "date"

    Returns
    -------
    pd.DataFrame
        新しい列が追加されたデータフレーム
    """

    # 入力データフレームをコピー
    df_new = df.copy()

    # unit_years単位で年数を区切り、新しい列として追加
    df_new["years"] = (
        pd.to_datetime(df_new[col_date]).dt.year // unit_years * unit_years
    )

    # 'years'列のデータ型を文字列に変更
    df_new["years"] = df_new["years"].astype(str)

    return df_new
Hide code cell content
def resample_df_by_col_and_years(df: pd.DataFrame, col: str) -> pd.DataFrame:
    """
    指定されたカラムと年数に基づき、データフレームを再サンプル
    colとyearsの全ての組み合わせが存在するように0埋めを行う
    この処理は、作図時にX軸方向の順序が変わることを防ぐために必要

    Parameters
    ----------
    df : pd.DataFrame
        入力データフレーム
    col : str
        サンプリング対象のカラム名

    Returns
    -------
    pd.DataFrame
        再サンプルされたデータフレーム
    """

    # 入力データフレームを新しい変数にコピー
    df_new = df.copy()

    # データフレームからユニークな年数一覧を取得
    unique_years = df["years"].unique()

    # データフレームからユニークなcolの値一覧を取得
    unique_vals = df[col].unique()

    # 一意なカラムの値と年数の全ての組み合わせに対して処理
    for val, years in itertools.product(unique_vals, unique_years):
        # 対象のカラムの値と年数が一致するデータを抽出
        df_tmp = df_new[(df_new[col] == val) & (df_new["years"] == years)]

        # 該当するデータが存在しない場合
        if df_tmp.shape[0] == 0:
            # 0埋めのデータを作成
            default_data = {c: 0 for c in df_tmp.columns}
            # col列についてはvalで埋める
            default_data[col] = val
            # years列についてはyearで埋める
            default_data["years"] = years
            # 新たなレコードとして追加
            df_add = pd.DataFrame(default_data, index=[0])

            # 0埋めのデータをデータフレームに追加
            df_new = pd.concat([df_new, df_add], ignore_index=True)

    return df_new

以下のようにファイルを読み込んでいると仮定します。

Hide code cell content
# マンガ各話に関するファイルの読み込み
df_ce = pd.read_csv(DIR_IN / "cm_ce.csv")
# マンガ作品と作者の対応関係に関するファイルの読み込み
df_cc_crt = pd.read_csv(DIR_IN / "cm_cc_crt.csv")
# date列をdatetime型に変換
df_ce["date"] = pd.to_datetime(df_ce["date"])

基礎 問題1:合計話数上位10作品#

関連セクション: マンガデータの量を見る

本書で紹介したマンガ作品の合計話数ランキングを復習しましょう。 合計話数が多い上位10作品を横棒グラフで可視化してください。

基礎 問題2:ページ数の分布#

関連セクション: マンガデータの分布を見る

マンガ各話のページ数がどのように分布しているかを確認しましょう。 df_ceのページ数(pages)のヒストグラムを、ビン数30で作成してください。

標準 問題3:週刊少年ジャンプの合計話数上位作品#

関連セクション: マンガデータの量を見る

特定の雑誌に絞って分析することで、雑誌ごとの特徴が見えてきます。 週刊少年ジャンプ(mcnameが「週刊少年ジャンプ」)のみに絞り、合計話数上位10作品を横棒グラフで可視化してください。

標準 問題4:4色カラー各話のページ数分布#

関連セクション: マンガデータの分布を見る

4色カラーで掲載された各話は、通常のモノクロ掲載とはページ数が異なる可能性があります。 four_coloredがTrueの各話のみに絞り、ページ数のヒストグラムを作成してください。

発展 問題5:マンガ作者別の合計ページ数#

関連セクション: マンガデータの量を見る

マンガ作者[1]がその生涯で「何ページ描いたか」は、その作業量を測る一つの指標となります。 ページ数という観点から、マンガ作者の を可視化してみましょう。

  • df_cedf_cc_crtccid をキーにマージしてください

  • 各マンガ作者(crtname)ごとの合計ページ数(pages)を集計してください

  • 上位15名を横棒グラフで可視化してください

発展 問題6:合計話数の累積分布#

関連セクション: マンガデータの分布を見る

マンガ業界、とくに週刊少年誌は非常に厳しい世界です。 多くの作品が短期間で連載を終える一方で、ごく一部の作品だけが長期連載を勝ち取ります。 掲載された作品が、どれくらいの話数まで到達できるのか、その生存競争の過酷さを可視化してみましょう。

  • df_ceccid(マンガ作品ID)でグループ化し、各作品の合計話数を集計してください

  • 集計した合計話数の累積ヒストグラムを作成してください

  • X軸の範囲を 0 から 200 までに制限してください

発展 問題7:カラー掲載割合の年代別推移#

関連セクション: マンガデータの内訳を見る

時代とともに、マンガ雑誌の「カラー掲載」作品の扱いは変化してきたのでしょうか。 各年代(years)の中で、4色カラー各話が占める割合を比較してみましょう。

  • df_ceadd_years_to_df() 関数で年代情報を追加してください

  • 年代ごとにカラー有無の割合(合計を1.0としたスケーリング)を算出してください

  • 積上げ棒グラフを作成し、配色には OKABE_ITO カラーパレットを使用してください

応用 問題8:初回ページ数と掲載位置の関係#

関連セクション: マンガデータの関係を見る

新連載がどのような条件でスタートするかは、雑誌ごとの編集戦略の違いを映し出します。 8話以上継続した作品の「第1話」について、掲載位置とページ数の関係を散布図で可視化しましょう。

  • 8話以上継続した作品のIDを抽出し、各作品の第1話のみを取得してください

  • 掲載位置(page_start_position)とページ数(pages)の散布図を作成してください

  • 雑誌別にファセットを分割し、重なりを防いで各雑誌の傾向を詳しく見られるようにしてください