上巻 第4章 練習問題#
ここでは、 本書の学習内容の定着 を目的とした練習問題を掲載します。 解答・解説は「解答例」ページを参照してください。 なお、問題の性質上、本書で取り上げた処理と重複することがあります。 ご了承ください。
前提#
以下のように、ライブラリのインポートと変数の定義が完了していることを前提とします。
Show 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
Show 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"
Show 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)
]
また、本書中で取り上げた以下の関数も、同様に利用可能とします。
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 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
Show 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
以下のようにファイルを読み込んでいると仮定します。
Show 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作品を横棒グラフで可視化してください。
ヒント
マンガ作品名(
ccname)ごとにユニークな各話ID(ceid)の数をカウントしますsort_values()で降順にソートし、head()で上位を抽出します横棒グラフは
px.bar()でorientation="h"を指定します
基礎 問題2:ページ数の分布#
関連セクション: マンガデータの分布を見る
マンガ各話のページ数がどのように分布しているかを確認しましょう。
df_ceのページ数(pages)のヒストグラムを、ビン数30で作成してください。
ヒント
ヒストグラムは
px.histogram()で作成しますビン数は
nbins引数で指定できます(例:nbins=30)
標準 問題3:週刊少年ジャンプの合計話数上位作品#
関連セクション: マンガデータの量を見る
特定の雑誌に絞って分析することで、雑誌ごとの特徴が見えてきます。
週刊少年ジャンプ(mcnameが「週刊少年ジャンプ」)のみに絞り、合計話数上位10作品を横棒グラフで可視化してください。
ヒント
まず
df_ce[df_ce["mcname"] == "週刊少年ジャンプ"]でデータを絞り込みます絞り込んだデータに対して、問題1と同様の集計・可視化を行います
標準 問題4:4色カラー各話のページ数分布#
関連セクション: マンガデータの分布を見る
4色カラーで掲載された各話は、通常のモノクロ掲載とはページ数が異なる可能性があります。
four_coloredがTrueの各話のみに絞り、ページ数のヒストグラムを作成してください。
ヒント
df_ce[df_ce["four_colored"]]でカラー各話のみを抽出できます抽出したデータに対して
px.histogram()でヒストグラムを作成します
発展 問題5:マンガ作者別の合計ページ数#
関連セクション: マンガデータの量を見る
マンガ作者[1]がその生涯で「何ページ描いたか」は、その作業量を測る一つの指標となります。 ページ数という観点から、マンガ作者の 量 を可視化してみましょう。
df_ceとdf_cc_crtをccidをキーにマージしてください各マンガ作者(
crtname)ごとの合計ページ数(pages)を集計してください上位15名を横棒グラフで可視化してください
ヒント
2つのDataFrameの結合には
pd.merge()を使用します横棒グラフは
px.bar()でorientation="h"を指定しますソート後に
.head(15)で上位15件を取得できます
発展 問題6:合計話数の累積分布#
関連セクション: マンガデータの分布を見る
マンガ業界、とくに週刊少年誌は非常に厳しい世界です。 多くの作品が短期間で連載を終える一方で、ごく一部の作品だけが長期連載を勝ち取ります。 掲載された作品が、どれくらいの話数まで到達できるのか、その生存競争の過酷さを可視化してみましょう。
df_ceをccid(マンガ作品ID)でグループ化し、各作品の合計話数を集計してください集計した合計話数の累積ヒストグラムを作成してください
X軸の範囲を
0から200までに制限してください
ヒント
マンガ作品ごとの話数カウントには
.groupby("ccid")["ceid"].nunique()を使用します累積ヒストグラムは
px.histogram()でcumulative=Trueを指定しますX軸の範囲は
.update_xaxes(range=[min, max])で設定できます
発展 問題7:カラー掲載割合の年代別推移#
関連セクション: マンガデータの内訳を見る
時代とともに、マンガ雑誌の「カラー掲載」作品の扱いは変化してきたのでしょうか。
各年代(years)の中で、4色カラー各話が占める割合を比較してみましょう。
df_ceにadd_years_to_df()関数で年代情報を追加してください年代ごとにカラー有無の割合(合計を1.0としたスケーリング)を算出してください
積上げ棒グラフを作成し、配色には
OKABE_ITOカラーパレットを使用してください
ヒント
年代とカラー有無で
.groupby()してカウント後、割合を計算します各年代の合計は
.transform("sum")で各行に付与できます積上げ棒グラフは
px.bar()でbarmode="stack"を指定します
応用 問題8:初回ページ数と掲載位置の関係#
関連セクション: マンガデータの関係を見る
新連載がどのような条件でスタートするかは、雑誌ごとの編集戦略の違いを映し出します。 8話以上継続した作品の「第1話」について、掲載位置とページ数の関係を散布図で可視化しましょう。
8話以上継続した作品のIDを抽出し、各作品の第1話のみを取得してください
掲載位置(
page_start_position)とページ数(pages)の散布図を作成してください雑誌別にファセットを分割し、重なりを防いで各雑誌の傾向を詳しく見られるようにしてください
ヒント
作品ごとの話数は
.groupby("ccid")["ceid"].nunique()でカウントできます第1話の抽出は
.sort_values(["ccid", "date"]).groupby("ccid").head(1)で実現できますファセット分割は
px.scatter()のfacet_col引数で指定します