下巻 第2章 練習問題#
ここでは、 本書の学習内容の定着 を目的とした練習問題を掲載します。 解答・解説は「解答例」ページを参照してください。 なお、問題の性質上、本書で取り上げた処理と重複することがあります。 ご了承ください。
前提#
以下のように、ライブラリのインポートと変数の定義が完了していることを前提とします。
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.figure_factoryのインポート
# 高度なプロットとデータ可視化のためのユーティリティ
# ffという名前で参照可能
import plotly.figure_factory as ff
# plotly.graph_objectsからFigureクラスのインポート
# 型ヒントの利用を主目的とする
from plotly.graph_objects import Figure
# plotly.subplotsからmake_subplotsのインポート
# 複数のサブプロットを含む複合的な図を作成する際に使用
from plotly.subplots import make_subplots
Show code cell content
# マンガデータ保存ディレクトリのパス
DIR_CM = Path("../../../data/cm/input")
# アニメデータ保存ディレクトリのパス
DIR_AN = Path("../../../data/an/input")
# ゲームデータ保存ディレクトリのパス
DIR_GM = Path("../../../data/gm/input")
Show code cell content
# 読み込み対象ファイル名の定義
# Comic Episode関連のファイル名
FN_CE = "cm_ce.csv"
# Anime Episode関連のファイル名
FN_AE = "an_ae.csv"
# PacKaGeとPlatForm関連のファイル名
FN_PKG_PF = "gm_pkg_pf.csv"
Show code cell content
# plotlyの描画設定の定義
# plotlyのグラフ描画用レンダラーの定義
# Jupyter Notebook環境のグラフ表示に適切なものを選択
RENDERER = "plotly_mimetype+notebook"
Show code cell content
# Okabe and Ito 2008
# https://jfly.uni-koeln.de/color/#pallet
OKABE_ITO = [
"#000000", # 黒 (Black)
"#E69F00", # 橙 (Orange)
"#56B4E9", # 薄青 (Sky Blue)
"#009E73", # 青緑 (Bluish Green)
"#F0E442", # 黄色 (Yellow)
"#0072B2", # 青 (Blue)
"#D55E00", # 赤紫 (Vermilion)
"#CC79A7", # 紫 (Reddish Purple)
]
Show code cell content
# 各プラットフォームのタイプをまとめた辞書
pfname2type = {
"プレイステーション・ポータブル": "携帯型",
"プレイステーション": "据置型",
"プレイステーションVita": "携帯型",
"プレイステーション3": "据置型",
"プレイステーション2": "据置型",
}
また、本書中で取り上げた以下の関数も、同様に利用可能とします。
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 create_distplot(
df: pd.DataFrame,
x: str,
color: str = None,
show_hist: bool = False,
show_rug: bool = False,
**kwargs: Any
) -> Figure:
"""
データフレームから密度プロットとヒストグラムを作成する
Parameters
----------
df : pd.DataFrame
プロットするデータを含むデータフレーム
x : str
密度プロットの描画対象とするカラム名
color : str, optional
データを分割する基準とするカラム名、指定しない場合はx列の全データを用いる
show_hist : bool, optional
ヒストグラムを表示するか否か、デフォルトはFalse
show_rug : bool, optional
ラグプロットを表示するか否か、デフォルトはFalse
**kwargs
ff.create_distplotに渡すその他のキーワード引数
Returns
-------
Figure
作成されたプロットのFigureオブジェクト
"""
if color:
# colorカラムの値でデータをグループ分け
grouped = df.groupby(color)
# 各グループのxカラムのデータをリストに格納、可視化用に逆順に並び替え
hist_data = [group[x].values for _, group in grouped][::-1]
# 各グループの名前(colorカラムの値)をラベルとしてリストに格納、可視化用に逆順に並び替え
labels = [str(name) for name, _ in grouped][::-1]
# 密度プロットとヒストグラムを作成
fig = ff.create_distplot(
hist_data, labels, show_hist=show_hist, show_rug=show_rug, **kwargs
)
else:
# colorが指定されていない場合はx列の全データを用いる
hist_data = [df[x].values]
# 密度プロットを作成(ラベルはxを指定)
fig = ff.create_distplot(
hist_data,
group_labels=[x],
show_hist=show_hist,
show_rug=show_rug,
**kwargs
)
# x軸のタイトルをxに変更
fig.update_xaxes(title=x)
# y軸のタイトルを"確率密度"に変更
fig.update_yaxes(title="確率密度")
# 作成されたプロットを返す
return fig
以下のようにデータを読み込み済みとします。
Show code cell content
# マンガデータの読み込み
df_ce = pd.read_csv(DIR_CM / FN_CE)
# アニメデータの読み込み
df_ae = pd.read_csv(DIR_AN / FN_AE)
# ゲームデータの読み込み
df_pkg_pf = pd.read_csv(DIR_GM / FN_PKG_PF)
基礎 問題1:アニメ作品の合計話数の分布#
関連セクション: ヒストグラム
本書では、アニメ作品ごとの合計話数のヒストグラムを作成し、表示範囲を100話以下に制限して分布を観察しました。表示範囲を変えると、分布の見え方はどのように変わるでしょうか。
df_aeを用いて、アニメ作品ごとの合計話数を集計してください合計話数のヒストグラムを作成し、表示範囲を 50話 以下に制限してください
ヒント
groupby()とnunique()で各作品の話数を集計できますupdate_xaxes(range=[0, 50])で表示範囲を制限できます本文では100話以下でした
基礎 問題2:ゲーム価格の累積分布#
関連セクション: ヒストグラム
本書では、ゲームパッケージの価格の累積ヒストグラムを作成し、10,000円以下の範囲で累積分布を確認しました。表示範囲を広げると、価格分布の全体像がより明確になります。
df_pkg_pfを用いて、ゲームパッケージの価格の累積ヒストグラムを作成してください表示範囲を 15,000円 以下に制限してください
ヒント
px.histogram()でcumulative=Trueを指定すると累積ヒストグラムになりますupdate_xaxes(range=[0, 15000])で表示範囲を制限できます本書では10,000円以下でした
標準 問題3:週刊少年ジャンプのページ数分布#
関連セクション: ヒストグラム
本文では、4誌すべてのページ数分布をファセット表示で比較しました。特定の雑誌に絞り込むと、その雑誌固有の特徴がより詳細に観察できます。
df_ceから週刊少年ジャンプのデータのみに絞り込んでください一話あたりのページ数(50ページ以下)のヒストグラムを作成してください
ビン数を25に設定してください
ヒント
ブールインデックス
df[df["mcname"] == "週刊少年ジャンプ"]で絞り込みができますnbins=25でビン数を指定できます
標準 問題4:プレイステーション2の価格分布#
関連セクション: 箱ひげ図
本文の箱ひげ図では、プレイステーションシリーズの価格分布を中央値や四分位範囲で要約しました。しかし、箱ひげ図では分布の詳細な形状は見えません。特定のプラットフォームに絞り、ヒストグラムで分布を詳しく観察してみましょう。
df_pkg_pfからプレイステーション2のデータのみに絞り込んでください価格のヒストグラムを作成してください
表示範囲を10,000円以下に制限してください
ヒント
ブールインデックス
df[df["pfname"] == "プレイステーション2"]で絞り込みができますupdate_xaxes(range=[0, 10000])で表示範囲を制限できます
発展 問題5:ページ数分布の話数別変化#
関連セクション: ヒストグラム
連載の長さによって、1話あたりのページ数にどのような違いがあるでしょうか。読み切り作品(1話完結)と短期連載では、ページ数の決まり方が異なるかもしれません。
ccid(作品ID)ごとに合計話数を算出し、df_ceに結合してください合計話数が「1話」から「10話」までの作品に限定し、ページ数(50ページ以下)のヒストグラムをファセット表示で比較してください
ファセットは合計話数を基準に分けてください
ヒント
groupbyとnuniqueで各作品の話数を集計できますfacet_colとfacet_col_wrapを組み合わせると、見やすい配置になります
発展 問題6:プレイステーションシリーズの価格帯比較#
関連セクション: 箱ひげ図
ゲームプラットフォームの世代交代と販売価格の関係を整理しましょう。プレイステーションシリーズ5機種を対象に、「据置型」と「携帯型」で価格分布がどう異なるかを比較します。
辞書
pfname2typeを用いて各機種を「据置型」と「携帯型」に分類してください横軸を分類、縦軸を販売価格とした箱ひげ図を作成してください
ヒント
mapメソッドで辞書を適用すると、新しい分類列を作成できますdropnaで分類できなかった機種(PS以外)を除外できます
応用 問題7:平日・土日の話数分布の推移#
関連セクション: リッジラインプロット
本章では、深夜アニメの台頭によりクール化が進んだ可能性が示唆されました。この傾向を「平日(月〜金)」と「土日」の放送枠で分けて分析してみましょう。
曜日情報を抽出し、「平日」と「土日」に分類してください
平日と土日の両方で放送データが存在する作品は除外 してください(厳密な比較のため)
1990年代、2000年代、2010年代の作品について、年代ごとの合計話数分布(100話以下)をリッジラインプロットで比較してください
ヒント
dt.dayofweekで曜日番号(0:月〜6:日)を取得できます各作品が何種類の曜日種別に属するかを
nuniqueで確認し、1種類のみの作品に絞り込みますpx.violinのside='positive'で片側描画(リッジライン風)になります
応用 問題8:最終回の掲載位置分布#
関連セクション: 密度プロット
マンガ作品の「最終回」は、雑誌のどのあたりに掲載される傾向があるでしょうか。巻頭カラーで華々しく飾られる作品もあれば、そうでない作品もありそうです。
各作品の「最後の一話」を特定し、その掲載位置(
page_start_position)を抽出してくださいただし、データセット末尾の作品は連載中の可能性があります(右側打ち切り)。各雑誌の最新巻号に掲載されていない作品のみ を対象としてください[1]
雑誌ごとの分布を密度プロットで比較してください
ヒント
groupbyとmaxで各作品の最終掲載日を特定できます作品の最終掲載日が雑誌の最終発行日より前なら「完結済み」と判定できます
create_distplot関数で密度プロットを作成できます