Pandasの基本#

Hide code cell content
# pandasをpdという名前でインポート
import pandas as pd

# バージョンを確認
pd.__version__
'2.1.1'

基本的なデータ構造#

pandas.DataFrame#

Hide code cell content
# SPY×FAMILYを例に、forger家を表現する辞書を作成
# キーには"名前"、"役割"、"秘密"というラベルを、
# それぞれの値にはリストを使って登場人物の情報を格納
forger = {
    "名前": ["ロイド", "ヨル", "アーニャ"],
    "役割": ["父", "母", "娘"],
    "秘密": ["スパイ", "殺し屋", "超能力者"],
}

# 上で作成したforger辞書を使ってDataFrameを作成
# pandasのDataFrameは表形式のデータを扱うのに適した構造で、
# ここではforgerのキーが列のヘッダーに、値のリストが各列のデータになる
df = pd.DataFrame(forger)
Hide code cell content
# データフレームの内容を表示
df
名前 役割 秘密
0 ロイド スパイ
1 ヨル 殺し屋
2 アーニャ 超能力者
Hide code cell content
# DataFrameを入れ子の辞書に変換
df.to_dict()
{'名前': {0: 'ロイド', 1: 'ヨル', 2: 'アーニャ'},
 '役割': {0: '父', 1: '母', 2: '娘'},
 '秘密': {0: 'スパイ', 1: '殺し屋', 2: '超能力者'}}
Hide code cell content
# DataFrameを行ごとに辞書化されたリストに変換
df.to_dict("records")
[{'名前': 'ロイド', '役割': '父', '秘密': 'スパイ'},
 {'名前': 'ヨル', '役割': '母', '秘密': '殺し屋'},
 {'名前': 'アーニャ', '役割': '娘', '秘密': '超能力者'}]
Hide code cell content
# ループの冒頭に「フォージャー家の秘密」という文字列を表示
print("フォージャー家の秘密")

# df.to_dict("records")で、データフレームdfを辞書のリストに変換
# 各要素r(辞書)についてループを回す
for r in df.to_dict("records"):
    # 変数nameに辞書rから"名前"の値を代入
    name = r["名前"]
    # 変数roleに辞書rから"役割"の値を代入
    role = r["役割"]
    # 変数secretに辞書rから"秘密"の値を代入
    secret = r["秘密"]
    # name、role、secretの値を用いてフォーマットされた文字列を出力
    print(f"- {name}は「{role}」を演じているが、実は{secret}だ")
フォージャー家の秘密
- ロイドは「父」を演じているが、実はスパイだ
- ヨルは「母」を演じているが、実は殺し屋だ
- アーニャは「娘」を演じているが、実は超能力者だ

pandas.Series#

Hide code cell content
# namesというリストを作成
# リスト内には"ロイド"、"ヨル"、"アーニャ"という3人の名前を格納
names = ["ロイド", "ヨル", "アーニャ"]

# namesリストを使ってpandasのSeriesを作成
s = pd.Series(names)
Hide code cell content
# Seriesの内容を表示
s
0     ロイド
1      ヨル
2    アーニャ
dtype: object

pandas.DataFrame型とpandas.Series型の相互変換#

Hide code cell content
# DataFrameから'役割'列を抽出し、Seriesに変換
roles = df["役割"]
Hide code cell content
# rolesというSeriesの中身を表示
roles
0    父
1    母
2    娘
Name: 役割, dtype: object
Hide code cell content
# コードネームを格納するリストを作成
codenames = ["黄昏", "いばら姫", "被験体007"]

# リストを元にSeriesを作成
s = pd.Series(codenames)

# SeriesからDataFrameを作成
# 列名として「コードネーム」を指定
df_c = pd.DataFrame(s, columns=["コードネーム"])
Hide code cell content
# Seriesから作成したDataFrameを確認
df_c
コードネーム
0 黄昏
1 いばら姫
2 被験体007
Hide code cell content
# dfにdf_cをコードネーム列として追加
df["コードネーム"] = df_c["コードネーム"]
Hide code cell content
# dfの内容を表示
df
名前 役割 秘密 コードネーム
0 ロイド スパイ 黄昏
1 ヨル 殺し屋 いばら姫
2 アーニャ 超能力者 被験体007

データの読み込みと書き出し#

読み込み#

Hide code cell content
# cm_ce.csvの中身をheadコマンドで確認
!head ../../../data/cm/input/cm_ce.csv
ceid,cename,ccid,miid,page_start,page_end,pages,page_start_position,two_colored,four_colored,miname,mcid,mcname,date,price,ccname
CE00000,第238話/この世代,C90829,M535428,10.0,31.0,22.0,0.0213675213675213,False,True,週刊少年マガジン 2011年 表示号数24,C119033,週刊少年マガジン,2011-05-25,248.0,ダイヤのA
CE00001,#134 話の続き,C90482,M535428,33.0,50.0,18.0,0.0705128205128205,False,False,週刊少年マガジン 2011年 表示号数24,C119033,週刊少年マガジン,2011-05-25,248.0,君のいる町
CE00002,第5話 チア・ザ・マシンガン!,C90297,M535428,51.0,68.0,18.0,0.1089743589743589,False,False,週刊少年マガジン 2011年 表示号数24,C119033,週刊少年マガジン,2011-05-25,248.0,アゲイン!!
CE00003,第233話 妖精の輝き,C89978,M535428,69.0,88.0,20.0,0.1474358974358974,False,False,週刊少年マガジン 2011年 表示号数24,C119033,週刊少年マガジン,2011-05-25,248.0,FAIRY TAIL
CE00004,-BOUT 71- From Dark Zone,C89929,M535428,89.0,108.0,20.0,0.1901709401709401,False,False,週刊少年マガジン 2011年 表示号数24,C119033,週刊少年マガジン,2011-05-25,248.0,A-BOUT!
CE00005,第94話,C90168,M535428,109.0,130.0,22.0,0.2329059829059829,False,True,週刊少年マガジン 2011年 表示号数24,C119033,週刊少年マガジン,2011-05-25,248.0,我間乱 ~GAMARAN~
CE00006,第36話 星,C89936,M535428,131.0,150.0,20.0,0.2799145299145299,False,False,週刊少年マガジン 2011年 表示号数24,C119033,週刊少年マガジン,2011-05-25,248.0,AKB49 ~恋愛禁止条例~
CE00007,#164 どうやって,C89939,M535428,151.0,168.0,18.0,0.3226495726495726,False,False,週刊少年マガジン 2011年 表示号数24,C119033,週刊少年マガジン,2011-05-25,248.0,Baby Steps ベイビーステップ
CE00008,code:133 覚悟の証,C89961,M535428,169.0,188.0,20.0,0.3611111111111111,False,False,週刊少年マガジン 2011年 表示号数24,C119033,週刊少年マガジン,2011-05-25,248.0,CODE:BREAKER コード:ブレイカー
Hide code cell content
# マンガ各話データを格納するcm_ceを読み出し
df = pd.read_csv("../../../data/cm/input/cm_ce.csv")
Hide code cell content
# headメソッドで冒頭5行を確認
cols = ["ceid", "cename", "pages", "page_start_position", "ccname", "mcname", "date"]
df[cols].head()
ceid cename pages page_start_position ccname mcname date
0 CE00000 第238話/この世代 22.0 0.021368 ダイヤのA 週刊少年マガジン 2011-05-25
1 CE00001 #134 話の続き 18.0 0.070513 君のいる町 週刊少年マガジン 2011-05-25
2 CE00002 第5話 チア・ザ・マシンガン! 18.0 0.108974 アゲイン!! 週刊少年マガジン 2011-05-25
3 CE00003 第233話 妖精の輝き 20.0 0.147436 FAIRY TAIL 週刊少年マガジン 2011-05-25
4 CE00004 -BOUT 71- From Dark Zone 20.0 0.190171 A-BOUT! 週刊少年マガジン 2011-05-25
Hide code cell content
# headメソッドで末尾5行を確認
df[cols].tail()
ceid cename pages page_start_position ccname mcname date
180071 CE190276 SPIN.82/決裂のセカンドドライブ 20.0 0.799523 少年ラケット 週刊少年チャンピオン 2017-02-02
180072 CE190277 第105話 助っ人土井 20.0 0.852029 Gメン 週刊少年チャンピオン 2017-02-02
180073 CE190278 第194話 「卒業しよう!」 20.0 0.899761 実は私は 週刊少年チャンピオン 2017-02-02
180074 CE190279 最終話 ユグドラシル 18.0 0.947494 マル勇 九ノ島さん 週刊少年チャンピオン 2017-02-02
180075 CE190280 鯨井先輩の巻 68 2.0 0.997613 木曜日のフルット 週刊少年チャンピオン 2017-02-02
Hide code cell content
# dfの最初の5行を抽出し、行と列を転置して表示
df[cols].head().T
0 1 2 3 4
ceid CE00000 CE00001 CE00002 CE00003 CE00004
cename 第238話/この世代 #134 話の続き 第5話 チア・ザ・マシンガン! 第233話 妖精の輝き -BOUT 71- From Dark Zone
pages 22.0 18.0 18.0 20.0 20.0
page_start_position 0.021368 0.070513 0.108974 0.147436 0.190171
ccname ダイヤのA 君のいる町 アゲイン!! FAIRY TAIL A-BOUT!
mcname 週刊少年マガジン 週刊少年マガジン 週刊少年マガジン 週刊少年マガジン 週刊少年マガジン
date 2011-05-25 2011-05-25 2011-05-25 2011-05-25 2011-05-25

書き出し#

Hide code cell content
# 一部の列を指定し、冒頭500行のみを抽出して小型化
df_save = df[cols].head(500)

# データをCSVファイルに書き出す
df_save.to_csv("../../../data/sandbox/cm_ce_small.csv")
Hide code cell content
# CSVファイルの中身をheadコマンドで確認
!head ../../../data/sandbox/cm_ce_small.csv
,ceid,cename,pages,page_start_position,ccname,mcname,date
0,CE00000,第238話/この世代,22.0,0.0213675213675213,ダイヤのA,週刊少年マガジン,2011-05-25
1,CE00001,#134 話の続き,18.0,0.0705128205128205,君のいる町,週刊少年マガジン,2011-05-25
2,CE00002,第5話 チア・ザ・マシンガン!,18.0,0.1089743589743589,アゲイン!!,週刊少年マガジン,2011-05-25
3,CE00003,第233話 妖精の輝き,20.0,0.1474358974358974,FAIRY TAIL,週刊少年マガジン,2011-05-25
4,CE00004,-BOUT 71- From Dark Zone,20.0,0.1901709401709401,A-BOUT!,週刊少年マガジン,2011-05-25
5,CE00005,第94話,22.0,0.2329059829059829,我間乱 ~GAMARAN~,週刊少年マガジン,2011-05-25
6,CE00006,第36話 星,20.0,0.2799145299145299,AKB49 ~恋愛禁止条例~,週刊少年マガジン,2011-05-25
7,CE00007,#164 どうやって,18.0,0.3226495726495726,Baby Steps ベイビーステップ,週刊少年マガジン,2011-05-25
8,CE00008,code:133 覚悟の証,20.0,0.3611111111111111,CODE:BREAKER コード:ブレイカー,週刊少年マガジン,2011-05-25
Hide code cell content
# インデックス以外のデータをCSVファイルに書き出す
df_save.to_csv("../../../data/sandbox/cm_ce_small_wo_index.csv", index=False)
Hide code cell content
# CSVファイルの中身をheadコマンドで確認
!head ../../../data/sandbox/cm_ce_small_wo_index.csv
ceid,cename,pages,page_start_position,ccname,mcname,date
CE00000,第238話/この世代,22.0,0.0213675213675213,ダイヤのA,週刊少年マガジン,2011-05-25
CE00001,#134 話の続き,18.0,0.0705128205128205,君のいる町,週刊少年マガジン,2011-05-25
CE00002,第5話 チア・ザ・マシンガン!,18.0,0.1089743589743589,アゲイン!!,週刊少年マガジン,2011-05-25
CE00003,第233話 妖精の輝き,20.0,0.1474358974358974,FAIRY TAIL,週刊少年マガジン,2011-05-25
CE00004,-BOUT 71- From Dark Zone,20.0,0.1901709401709401,A-BOUT!,週刊少年マガジン,2011-05-25
CE00005,第94話,22.0,0.2329059829059829,我間乱 ~GAMARAN~,週刊少年マガジン,2011-05-25
CE00006,第36話 星,20.0,0.2799145299145299,AKB49 ~恋愛禁止条例~,週刊少年マガジン,2011-05-25
CE00007,#164 どうやって,18.0,0.3226495726495726,Baby Steps ベイビーステップ,週刊少年マガジン,2011-05-25
CE00008,code:133 覚悟の証,20.0,0.3611111111111111,CODE:BREAKER コード:ブレイカー,週刊少年マガジン,2011-05-25
Hide code cell content
# インデックス以外のデータをExcelファイルに書き出す
df_save.to_excel("../../../data/sandbox/cm_ce_small_wo_index.xlsx", index=False)

データの選択とフィルタリング#

カラムの選択#

Hide code cell content
# 先ほど保存した小型化した各話データを再度読み込む
df = pd.read_csv("../../../data/sandbox/cm_ce_small_wo_index.csv")
Hide code cell content
# cename列の内容を表示
df["cename"]
0                             第238話/この世代
1                              #134 話の続き
2                        第5話 チア・ザ・マシンガン!
3                            第233話 妖精の輝き
4               -BOUT 71- From Dark Zone
                     ...                
495                            Trick:299
496                        第65話 伝統シー・ロール
497              File.290 西本、「劇団四季」に入門!?
498                            第310話 風待ち
499    第92話 a man-made mountain:人の造り給いし山
Name: cename, Length: 500, dtype: object
Hide code cell content
# cename列とccname列を同時に表示
df[["cename", "ccname"]]
cename ccname
0 第238話/この世代 ダイヤのA
1 #134 話の続き 君のいる町
2 第5話 チア・ザ・マシンガン! アゲイン!!
3 第233話 妖精の輝き FAIRY TAIL
4 -BOUT 71- From Dark Zone A-BOUT!
... ... ...
495 Trick:299 エア・ギア
496 第65話 伝統シー・ロール だぶるじぇい
497 File.290 西本、「劇団四季」に入門!? もう、しませんから。
498 第310話 風待ち あひるの空
499 第92話 a man-made mountain:人の造り給いし山 エデンの檻

500 rows × 2 columns

行の選択#

Hide code cell content
# ceidをインデックス列として指定
df = df.set_index("ceid")
Hide code cell content
# インデックス0の行を選択する
df.iloc[0]
cename                 第238話/この世代
pages                        22.0
page_start_position      0.021368
ccname                      ダイヤのA
mcname                   週刊少年マガジン
date                   2011-05-25
Name: CE00000, dtype: object
Hide code cell content
# インデックスのラベルが"CE00000"行を選択する
df.loc["CE00000"]
cename                 第238話/この世代
pages                        22.0
page_start_position      0.021368
ccname                      ダイヤのA
mcname                   週刊少年マガジン
date                   2011-05-25
Name: CE00000, dtype: object

条件に基づくフィルタリング#

Hide code cell content
# pages列が1と一致するか否かを表すシリーズを作成
df["pages"] == 1
ceid
CE00000    False
CE00001    False
CE00002    False
CE00003    False
CE00004    False
           ...  
CE00495    False
CE00496    False
CE00497    False
CE00498    False
CE00499    False
Name: pages, Length: 500, dtype: bool
Hide code cell content
# "pages"が1と一致する行を抽出
df[df["pages"] == 1]
cename pages page_start_position ccname mcname date
ceid
CE00443 『毎日かあさん』 1.0 1.0 マガジンシアター 週刊少年マガジン 2011-01-29
CE00444 49号 1.0 1.0 [プレゼント当選者発表] 週刊少年マガジン 2011-01-29
CE00470 48号 1.0 1.0 [プレゼント当選者発表] 週刊少年マガジン 2011-01-22
Hide code cell content
# "pages"が5未満、かつ"page_start_position"が0.5以下
df[(df["pages"] < 5) & (df["page_start_position"] <= 0.5)]
cename pages page_start_position ccname mcname date
ceid
CE00054 #132 / 視線の先 / 紳士的飲み方 / 男の放課後 / おべんきょ / 乙女の園 / ... 4.0 0.182403 生徒会役員共 週刊少年マガジン 2011-05-04
CE00187 エビ・フラ彦さん / まんじゅう / ディナー 2.0 0.278761 チョイとだけ劇場 週刊少年マガジン 2011-03-30
CE00191 #128 / ひまつぶし / 約束の時 / ベリベリ / カチコチ / 激しく運動 / 精神... 4.0 0.400442 生徒会役員共 週刊少年マガジン 2011-03-30
CE00214 #127 / 愛情×2 / 要望メニュー / 好物頂戴 / あっ / おいしくできました /... 4.0 0.310573 生徒会役員共 週刊少年マガジン 2011-03-23
CE00265 #125 / 隠れ巨乳共 / おだて名人 / 抜きポイント / 青い時代 / あの頃から今 ... 4.0 0.162222 生徒会役員共 週刊少年マガジン 2011-03-09
CE00322 #123 / 血がたぎる / くせもの / もったいないおばけ / 裏の組織 / 復活の日 ... 4.0 0.478541 生徒会役員共 週刊少年マガジン 2011-02-23

データの整形と操作#

欠損値の処理#

Hide code cell content
# isnaでcename(各話名)に欠損値のある行を抽出
df_na = df[df["cename"].isna()]
Hide code cell content
# 欠損値のある行を確認
df_na
cename pages page_start_position ccname mcname date
ceid
CE00036 NaN 4.0 0.601145 ネギほ(幼)文 週刊少年マガジン 2011-05-18
CE00064 NaN 4.0 0.564378 竹植物語 週刊少年マガジン 2011-05-04
CE00154 NaN 2.0 0.997912 ミヤジマがお知らせします。 週刊少年マガジン 2011-04-13
CE00211 NaN 20.0 0.174009 さんかれあ 週刊少年マガジン 2011-03-23
CE00261 NaN 2.0 0.997895 ミヤジマがお知らせします。 週刊少年マガジン 2011-03-16
CE00298 NaN 12.0 0.431330 カウントラブル 週刊少年マガジン 2011-03-02
CE00416 NaN 2.0 0.997831 ミヤジマがお知らせします。 週刊少年マガジン 2011-02-02
CE00450 NaN 60.0 0.219713 極味ドラゴン 週刊少年マガジン 2011-01-22
Hide code cell content
# 欠損値を"タイトルなし"で埋める
df_na.fillna("各話名なし")
cename pages page_start_position ccname mcname date
ceid
CE00036 各話名なし 4.0 0.601145 ネギほ(幼)文 週刊少年マガジン 2011-05-18
CE00064 各話名なし 4.0 0.564378 竹植物語 週刊少年マガジン 2011-05-04
CE00154 各話名なし 2.0 0.997912 ミヤジマがお知らせします。 週刊少年マガジン 2011-04-13
CE00211 各話名なし 20.0 0.174009 さんかれあ 週刊少年マガジン 2011-03-23
CE00261 各話名なし 2.0 0.997895 ミヤジマがお知らせします。 週刊少年マガジン 2011-03-16
CE00298 各話名なし 12.0 0.431330 カウントラブル 週刊少年マガジン 2011-03-02
CE00416 各話名なし 2.0 0.997831 ミヤジマがお知らせします。 週刊少年マガジン 2011-02-02
CE00450 各話名なし 60.0 0.219713 極味ドラゴン 週刊少年マガジン 2011-01-22
Hide code cell content
# 欠損値を含む行を削除
df_na.dropna()
cename pages page_start_position ccname mcname date
ceid

カラム名の変更#

Hide code cell content
# columns引数に辞書を渡すことでカラム名を変更
df.rename(columns={"cename": "各話名", "mcname": "雑誌名", "ccname": "作品名"})
各話名 pages page_start_position 作品名 雑誌名 date
ceid
CE00000 第238話/この世代 22.0 0.021368 ダイヤのA 週刊少年マガジン 2011-05-25
CE00001 #134 話の続き 18.0 0.070513 君のいる町 週刊少年マガジン 2011-05-25
CE00002 第5話 チア・ザ・マシンガン! 18.0 0.108974 アゲイン!! 週刊少年マガジン 2011-05-25
CE00003 第233話 妖精の輝き 20.0 0.147436 FAIRY TAIL 週刊少年マガジン 2011-05-25
CE00004 -BOUT 71- From Dark Zone 20.0 0.190171 A-BOUT! 週刊少年マガジン 2011-05-25
... ... ... ... ... ... ...
CE00495 Trick:299 18.0 0.938492 エア・ギア 週刊少年マガジン 2011-01-15
CE00496 第65話 伝統シー・ロール 8.0 0.974206 だぶるじぇい 週刊少年マガジン 2011-01-15
CE00497 File.290 西本、「劇団四季」に入門!? 6.0 0.990079 もう、しませんから。 週刊少年マガジン 2011-01-15
CE00498 第310話 風待ち 21.0 0.021318 あひるの空 週刊少年マガジン 2011-01-08
CE00499 第92話 a man-made mountain:人の造り給いし山 20.0 0.063953 エデンの檻 週刊少年マガジン 2011-01-08

500 rows × 6 columns

データ型の変換#

Hide code cell content
# pages(各話の合計ページ数)列の型を確認
df["pages"].dtype
dtype('float64')
Hide code cell content
# pages(各話の合計ページ数)をint型に変換
df["pages"].astype(int)
ceid
CE00000    22
CE00001    18
CE00002    18
CE00003    20
CE00004    20
           ..
CE00495    18
CE00496     8
CE00497     6
CE00498    21
CE00499    20
Name: pages, Length: 500, dtype: int64
Hide code cell content
# date列の型を確認
df["date"].dtype
dtype('O')
Hide code cell content
# to_datetimeでdate列を変換
pd.to_datetime(df["date"])
ceid
CE00000   2011-05-25
CE00001   2011-05-25
CE00002   2011-05-25
CE00003   2011-05-25
CE00004   2011-05-25
             ...    
CE00495   2011-01-15
CE00496   2011-01-15
CE00497   2011-01-15
CE00498   2011-01-08
CE00499   2011-01-08
Name: date, Length: 500, dtype: datetime64[ns]
Hide code cell content
# dt.yearメソッドで年だけを抽出
pd.to_datetime(df["date"]).dt.year
ceid
CE00000    2011
CE00001    2011
CE00002    2011
CE00003    2011
CE00004    2011
           ... 
CE00495    2011
CE00496    2011
CE00497    2011
CE00498    2011
CE00499    2011
Name: date, Length: 500, dtype: int32
Hide code cell content
# dt.monthメソッドで月だけを抽出
pd.to_datetime(df["date"]).dt.month
ceid
CE00000    5
CE00001    5
CE00002    5
CE00003    5
CE00004    5
          ..
CE00495    1
CE00496    1
CE00497    1
CE00498    1
CE00499    1
Name: date, Length: 500, dtype: int32
Hide code cell content
# dt.dayメソッドで日だけを抽出
pd.to_datetime(df["date"]).dt.day
ceid
CE00000    25
CE00001    25
CE00002    25
CE00003    25
CE00004    25
           ..
CE00495    15
CE00496    15
CE00497    15
CE00498     8
CE00499     8
Name: date, Length: 500, dtype: int32
Hide code cell content
# dt.weekdayメソッドで曜日(0:月曜、1:火曜、…、6:日曜)を抽出
pd.to_datetime(df["date"]).dt.weekday
ceid
CE00000    2
CE00001    2
CE00002    2
CE00003    2
CE00004    2
          ..
CE00495    5
CE00496    5
CE00497    5
CE00498    5
CE00499    5
Name: date, Length: 500, dtype: int32
Hide code cell content
# ユニークなccname(マンガ作品名)を抽出し、リストに変換
ccnames = df["ccname"].unique()

# DataFrameのccname列をカテゴリ型に変換する
# ccnamesリストに含まれるユニークなマンガ作品名をカテゴリとして使用
# ordered=Trueにより、カテゴリに順序を持たせる(ただし、この例ではccnamesの順序に依存)
df["ccname"] = pd.Categorical(df["ccname"], categories=ccnames, ordered=True)
Hide code cell content
# ccname列の型を確認
df["ccname"].dtype
CategoricalDtype(categories=['ダイヤのA', '君のいる町', 'アゲイン!!', 'FAIRY TAIL', 'A-BOUT!',
                  '我間乱 ~GAMARAN~', 'AKB49 ~恋愛禁止条例~', 'Baby Steps ベイビーステップ',
                  'CODE:BREAKER コード:ブレイカー', '魔法先生 ネギま! MAGISTER NEGI MAGI',
                  'ファイ・ブレイン 最期のパズル', '波打際のむろみさん', 'はじめの一歩', 'さよなら絶望先生',
                  'あひるの空', 'ヤンキー君とメガネちゃん', 'ゴッドハンド輝', 'エリアの騎士', '金田一少年の事件簿',
                  'この彼女はフィクションです。', '生徒会役員共', '振り向くな君は', 'エデンの檻', 'かってに改蔵',
                  'エア・ギア', 'ネギほ(幼)文', 'GE ~グッドエンディング~', 'くろのロワイヤル', 'だぶるじぇい',
                  'もう、しませんから。', '竹植物語', 'BLOODY MONDAY', 'チョイとだけ劇場',
                  'ほんとにあった!霊媒先生', 'ぷあぷあ?', 'ゼウスの種', 'ミヤジマがお知らせします。', 'GTO',
                  'さんかれあ', 'カウントラブル', 'ラブプラス Rinko Days', 'BUN BUN BEE',
                  'マガジンシアター', '[プレゼント当選者発表]', '極味ドラゴン', '花形  新約「巨人の星」'],
, ordered=True, categories_dtype=object)

カラムの追加・削除#

Hide code cell content
# 発売曜日を示す列をweekdayとして追加
df["weekday"] = pd.to_datetime(df["date"]).dt.weekday
Hide code cell content
# 列を追加されたdfの冒頭5行を表示
df.head()
cename pages page_start_position ccname mcname date weekday
ceid
CE00000 第238話/この世代 22.0 0.021368 ダイヤのA 週刊少年マガジン 2011-05-25 2
CE00001 #134 話の続き 18.0 0.070513 君のいる町 週刊少年マガジン 2011-05-25 2
CE00002 第5話 チア・ザ・マシンガン! 18.0 0.108974 アゲイン!! 週刊少年マガジン 2011-05-25 2
CE00003 第233話 妖精の輝き 20.0 0.147436 FAIRY TAIL 週刊少年マガジン 2011-05-25 2
CE00004 -BOUT 71- From Dark Zone 20.0 0.190171 A-BOUT! 週刊少年マガジン 2011-05-25 2
Hide code cell content
# 先程作成したweekdayを削除
df = df.drop(columns=["weekday"])
Hide code cell content
# weekday列を削除したdfの冒頭5行を表示
df.head()
cename pages page_start_position ccname mcname date
ceid
CE00000 第238話/この世代 22.0 0.021368 ダイヤのA 週刊少年マガジン 2011-05-25
CE00001 #134 話の続き 18.0 0.070513 君のいる町 週刊少年マガジン 2011-05-25
CE00002 第5話 チア・ザ・マシンガン! 18.0 0.108974 アゲイン!! 週刊少年マガジン 2011-05-25
CE00003 第233話 妖精の輝き 20.0 0.147436 FAIRY TAIL 週刊少年マガジン 2011-05-25
CE00004 -BOUT 71- From Dark Zone 20.0 0.190171 A-BOUT! 週刊少年マガジン 2011-05-25
Hide code cell content
# indexがCE00000の行を削除して冒頭5行を表示
df.drop("CE00000").head()
cename pages page_start_position ccname mcname date
ceid
CE00001 #134 話の続き 18.0 0.070513 君のいる町 週刊少年マガジン 2011-05-25
CE00002 第5話 チア・ザ・マシンガン! 18.0 0.108974 アゲイン!! 週刊少年マガジン 2011-05-25
CE00003 第233話 妖精の輝き 20.0 0.147436 FAIRY TAIL 週刊少年マガジン 2011-05-25
CE00004 -BOUT 71- From Dark Zone 20.0 0.190171 A-BOUT! 週刊少年マガジン 2011-05-25
CE00005 第94話 22.0 0.232906 我間乱 ~GAMARAN~ 週刊少年マガジン 2011-05-25

重複の処理#

Hide code cell content
# DataFrameの作成
df_bobobo = pd.DataFrame(columns=["キャラクター"], data=["ボボボーボ・ボーボボ"] * 5)

# 1から始まる順位列をインデックスとして設定
df_bobobo.index = range(1, len(df_bobobo) + 1)

# インデックス名を"順位"に設定
df_bobobo.index.name = "順位"
Hide code cell content
# 人気投票結果を表示
df_bobobo
キャラクター
順位
1 ボボボーボ・ボーボボ
2 ボボボーボ・ボーボボ
3 ボボボーボ・ボーボボ
4 ボボボーボ・ボーボボ
5 ボボボーボ・ボーボボ
Hide code cell content
# duplicatedメソッドで重複行を特定
df_bobobo.duplicated()
順位
1    False
2     True
3     True
4     True
5     True
dtype: bool
Hide code cell content
# 重複していない行のみを表示
df_bobobo[~df_bobobo.duplicated()]
キャラクター
順位
1 ボボボーボ・ボーボボ
Hide code cell content
# drop_duplicatedメソッドで重複行を削除
df_bobobo.drop_duplicates()
キャラクター
順位
1 ボボボーボ・ボーボボ
Hide code cell content
# keep=Falseを指定することで全ての重複行を削除
df_bobobo.drop_duplicates(keep=False)
キャラクター
順位
Hide code cell content
# 得票数列に各キャラクターの得票数を格納
df_bobobo["得票数"] = [5071, 3072, 1802, 721, 514]
# コメント列に各キャラクターの受賞コメントを格納
df_bobobo["コメント"] = [
    "みんなありがとう",
    "フン",
    "神に感謝",
    "くっ ボーボボに負けた…",
    "順当な順位ですね",
]
Hide code cell content
# 更新されたDataFrameを表示
df_bobobo
キャラクター 得票数 コメント
順位
1 ボボボーボ・ボーボボ 5071 みんなありがとう
2 ボボボーボ・ボーボボ 3072 フン
3 ボボボーボ・ボーボボ 1802 神に感謝
4 ボボボーボ・ボーボボ 721 くっ ボーボボに負けた…
5 ボボボーボ・ボーボボ 514 順当な順位ですね
Hide code cell content
# drop_duplicatedメソッドで重複行を削除
df_bobobo.drop_duplicates()
キャラクター 得票数 コメント
順位
1 ボボボーボ・ボーボボ 5071 みんなありがとう
2 ボボボーボ・ボーボボ 3072 フン
3 ボボボーボ・ボーボボ 1802 神に感謝
4 ボボボーボ・ボーボボ 721 くっ ボーボボに負けた…
5 ボボボーボ・ボーボボ 514 順当な順位ですね
Hide code cell content
# drop_duplicatedメソッドで「キャラクター」列が重複している行を削除
df_bobobo.drop_duplicates(subset=["キャラクター"])
キャラクター 得票数 コメント
順位
1 ボボボーボ・ボーボボ 5071 みんなありがとう

各行へのカスタム処理#

Hide code cell content
# dateに基づき、曜日情報をweekday列として追加
df["weekday"] = pd.to_datetime(df["date"]).dt.weekday
# 変換後のDataFrameの一部を表示
df.head()
cename pages page_start_position ccname mcname date weekday
ceid
CE00000 第238話/この世代 22.0 0.021368 ダイヤのA 週刊少年マガジン 2011-05-25 2
CE00001 #134 話の続き 18.0 0.070513 君のいる町 週刊少年マガジン 2011-05-25 2
CE00002 第5話 チア・ザ・マシンガン! 18.0 0.108974 アゲイン!! 週刊少年マガジン 2011-05-25 2
CE00003 第233話 妖精の輝き 20.0 0.147436 FAIRY TAIL 週刊少年マガジン 2011-05-25 2
CE00004 -BOUT 71- From Dark Zone 20.0 0.190171 A-BOUT! 週刊少年マガジン 2011-05-25 2
Hide code cell content
# weekdayと曜日を対応付ける辞書
weekday2yobi = {0: "月", 1: "火", 2: "水", 3: "木", 4: "金", 5: "土", 6: "日"}
# weekdayを元に、weekday2yobiを用いてyobi列に曜日表現を格納
df["yobi"] = df["weekday"].map(weekday2yobi)

# 変換後のDataFrameの一部を表示
df.head()
cename pages page_start_position ccname mcname date weekday yobi
ceid
CE00000 第238話/この世代 22.0 0.021368 ダイヤのA 週刊少年マガジン 2011-05-25 2
CE00001 #134 話の続き 18.0 0.070513 君のいる町 週刊少年マガジン 2011-05-25 2
CE00002 第5話 チア・ザ・マシンガン! 18.0 0.108974 アゲイン!! 週刊少年マガジン 2011-05-25 2
CE00003 第233話 妖精の輝き 20.0 0.147436 FAIRY TAIL 週刊少年マガジン 2011-05-25 2
CE00004 -BOUT 71- From Dark Zone 20.0 0.190171 A-BOUT! 週刊少年マガジン 2011-05-25 2
Hide code cell content
# DataFrameの形状を再確認
df_bobobo
キャラクター 得票数 コメント
順位
1 ボボボーボ・ボーボボ 5071 みんなありがとう
2 ボボボーボ・ボーボボ 3072 フン
3 ボボボーボ・ボーボボ 1802 神に感謝
4 ボボボーボ・ボーボボ 721 くっ ボーボボに負けた…
5 ボボボーボ・ボーボボ 514 順当な順位ですね
Hide code cell content
# summarize_ranking関数の定義
# 行ごとにキャラクター名、得票数、コメントをまとめた文字列を作成
def summarize_ranking(row):
    # 各行の'キャラクター'、'得票数'、'コメント'列の値を使用して、フォーマットされた文字列を返す
    return f"{row['キャラクター']}({row['得票数']}票)「{row['コメント']}」"


# df_boboboデータフレームの各行に対してsummarize_ranking関数を適用し、'まとめ'列として結果を追加
# 各行ごとのデータに対して関数を適用するため axis=1 を指定
df_bobobo["まとめ"] = df_bobobo.apply(summarize_ranking, axis=1)

# 結果のデータフレームを表示
df_bobobo
キャラクター 得票数 コメント まとめ
順位
1 ボボボーボ・ボーボボ 5071 みんなありがとう ボボボーボ・ボーボボ(5071票)「みんなありがとう」
2 ボボボーボ・ボーボボ 3072 フン ボボボーボ・ボーボボ(3072票)「フン」
3 ボボボーボ・ボーボボ 1802 神に感謝 ボボボーボ・ボーボボ(1802票)「神に感謝」
4 ボボボーボ・ボーボボ 721 くっ ボーボボに負けた… ボボボーボ・ボーボボ(721票)「くっ ボーボボに負けた…」
5 ボボボーボ・ボーボボ 514 順当な順位ですね ボボボーボ・ボーボボ(514票)「順当な順位ですね」

データのソートと集計#

ソート#

Hide code cell content
# dateで昇順にソートして冒頭5行を表示
df.sort_values("date").head()
cename pages page_start_position ccname mcname date weekday yobi
ceid
CE00499 第92話 a man-made mountain:人の造り給いし山 20.0 0.063953 エデンの檻 週刊少年マガジン 2011-01-08 5
CE00498 第310話 風待ち 21.0 0.021318 あひるの空 週刊少年マガジン 2011-01-08 5
CE00496 第65話 伝統シー・ロール 8.0 0.974206 だぶるじぇい 週刊少年マガジン 2011-01-15 5
CE00471 第221話/Progress 22.0 0.021825 ダイヤのA 週刊少年マガジン 2011-01-15 5
CE00472 #117 ・・・・ね? 18.0 0.065476 君のいる町 週刊少年マガジン 2011-01-15 5
Hide code cell content
# dateで降順にソートして冒頭5行を表示
df.sort_values("date", ascending=False).head()
cename pages page_start_position ccname mcname date weekday yobi
ceid
CE00000 第238話/この世代 22.0 0.021368 ダイヤのA 週刊少年マガジン 2011-05-25 2
CE00012 Round 935 未見の強振 18.0 0.579060 はじめの一歩 週刊少年マガジン 2011-05-25 2
CE00001 #134 話の続き 18.0 0.070513 君のいる町 週刊少年マガジン 2011-05-25 2
CE00022 第109話 Pyramid:第三の塔 20.0 0.959402 エデンの檻 週刊少年マガジン 2011-05-25 2
CE00021 第22話 震える世界。 20.0 0.916667 振り向くな君は 週刊少年マガジン 2011-05-25 2
Hide code cell content
# date、pagesで昇順にソートして冒頭5行を表示
df.sort_values(["date", "pages"]).head()
cename pages page_start_position ccname mcname date weekday yobi
ceid
CE00499 第92話 a man-made mountain:人の造り給いし山 20.0 0.063953 エデンの檻 週刊少年マガジン 2011-01-08 5
CE00498 第310話 風待ち 21.0 0.021318 あひるの空 週刊少年マガジン 2011-01-08 5
CE00493 #116 / 朝一コール / キリッ / つぶやき / 気のせい / 雪と戯れ / 先生の日... 4.0 0.890873 生徒会役員共 週刊少年マガジン 2011-01-15 5
CE00482 373 歳末とむろみさん 6.0 0.501984 波打際のむろみさん 週刊少年マガジン 2011-01-15 5
CE00497 File.290 西本、「劇団四季」に入門!? 6.0 0.990079 もう、しませんから。 週刊少年マガジン 2011-01-15 5

基礎集計#

Hide code cell content
# dfの行数と列数を取得
df.shape
(500, 8)
Hide code cell content
# date列のユニークな値を登場順に列挙
df["date"].unique()
array(['2011-05-25', '2011-05-18', '2011-05-04', '2011-04-27',
       '2011-04-20', '2011-04-13', '2011-04-06', '2011-03-30',
       '2011-03-23', '2011-03-16', '2011-03-09', '2011-03-02',
       '2011-02-23', '2011-02-16', '2011-02-09', '2011-02-02',
       '2011-01-29', '2011-01-22', '2011-01-15', '2011-01-08'],
      dtype=object)
Hide code cell content
# date列のユニークな値の数を集計
df["date"].nunique()
20
Hide code cell content
# pages列の平均値を算出
df["pages"].mean()
17.138
Hide code cell content
# pagesとpage_start_positionの平均値をそれぞれ算出
df[["pages", "page_start_position"]].mean()
pages                  17.138000
page_start_position     0.540504
dtype: float64
Hide code cell content
# (算出可能な列に対して)基本的な統計量を一括算出
df.describe()
pages page_start_position weekday
count 500.000000 500.000000 500.00000
mean 17.138000 0.540504 2.49800
std 7.621491 0.291936 1.11736
min 1.000000 0.006263 2.00000
25% 16.000000 0.285873 2.00000
50% 20.000000 0.559800 2.00000
75% 20.000000 0.791845 2.00000
max 66.000000 1.000000 5.00000
Hide code cell content
# pagesとpage_start_positionの相関行列を算出
df[["pages", "page_start_position"]].corr()
pages page_start_position
pages 1.000000 -0.424604
page_start_position -0.424604 1.000000

データの結合とマージ#

結合#

Hide code cell content
# マンガ各話データを格納するcm_ceを読み出し
df_ce = pd.read_csv("../../../data/cm/input/cm_ce.csv")
Hide code cell content
# 簡略化のために列を選択
cols = ["mcname", "miname", "ccname", "ccid"]

# 週刊少年ジャンプおよび週刊少年サンデーの最初の5行だけ抽出してDataFrame化
df_jump = (
    df_ce[df_ce["mcname"] == "週刊少年ジャンプ"][cols].reset_index(drop=True).head()
)
df_sunday = (
    df_ce[df_ce["mcname"] == "週刊少年サンデー"][cols].reset_index(drop=True).head()
)
Hide code cell content
# 週刊少年ジャンプに関するDataFrameの中身を確認
df_jump
mcname miname ccname ccid
0 週刊少年ジャンプ 週刊少年ジャンプ 1983年 表示号数3 スキャンドール C88521
1 週刊少年ジャンプ 週刊少年ジャンプ 1983年 表示号数3 風魔の小次郎 C89489
2 週刊少年ジャンプ 週刊少年ジャンプ 1983年 表示号数3 キャッツ・アイ CATS・EYE C88386
3 週刊少年ジャンプ 週刊少年ジャンプ 1983年 表示号数3 やぶれかぶれ C89747
4 週刊少年ジャンプ 週刊少年ジャンプ 1983年 表示号数3 キン肉マン C88427
Hide code cell content
# 週刊少年ジャンプに関するDataFrameの中身を確認
df_sunday
mcname miname ccname ccid
0 週刊少年サンデー 週刊少年サンデー 1971年 表示号数3 怒りよさらば C92147
1 週刊少年サンデー 週刊少年サンデー 1971年 表示号数3 ケンカの聖書 C92340
2 週刊少年サンデー 週刊少年サンデー 1971年 表示号数3 烈火 C93935
3 週刊少年サンデー 週刊少年サンデー 1971年 表示号数3 男どアホウ甲子園 C92472
4 週刊少年サンデー 週刊少年サンデー 1971年 表示号数3 ダメおやじ C92856
Hide code cell content
# df_jumpとdf_sundayをconcatメソッドを用いて結合
# ignore_index=Trueとすることで、インデックスを新たに振り直す
pd.concat([df_jump, df_sunday], ignore_index=True)
mcname miname ccname ccid
0 週刊少年ジャンプ 週刊少年ジャンプ 1983年 表示号数3 スキャンドール C88521
1 週刊少年ジャンプ 週刊少年ジャンプ 1983年 表示号数3 風魔の小次郎 C89489
2 週刊少年ジャンプ 週刊少年ジャンプ 1983年 表示号数3 キャッツ・アイ CATS・EYE C88386
3 週刊少年ジャンプ 週刊少年ジャンプ 1983年 表示号数3 やぶれかぶれ C89747
4 週刊少年ジャンプ 週刊少年ジャンプ 1983年 表示号数3 キン肉マン C88427
5 週刊少年サンデー 週刊少年サンデー 1971年 表示号数3 怒りよさらば C92147
6 週刊少年サンデー 週刊少年サンデー 1971年 表示号数3 ケンカの聖書 C92340
7 週刊少年サンデー 週刊少年サンデー 1971年 表示号数3 烈火 C93935
8 週刊少年サンデー 週刊少年サンデー 1971年 表示号数3 男どアホウ甲子園 C92472
9 週刊少年サンデー 週刊少年サンデー 1971年 表示号数3 ダメおやじ C92856

マージ#

Hide code cell content
# SPY×FAMILYを例に、forger家を表現するDataFrameを作成
df_forger = pd.DataFrame(
    {
        "名前": ["ロイド", "ヨル", "アーニャ"],
        "役割": ["父", "母", "娘"],
        "秘密": ["スパイ", "殺し屋", "超能力者"],
    }
)

# 内容を表示
df_forger
名前 役割 秘密
0 ロイド スパイ
1 ヨル 殺し屋
2 アーニャ 超能力者
Hide code cell content
# アーニャが所属するイーデン校を表現するDataFrameを作成
df_eden = pd.DataFrame(
    {
        "名前": ["アーニャ", "ダミアン", "ベッキー", "ビル"],
        "クラス": ["1年3組", "1年3組", "1年3組", "1年4組"],
    }
)

# 内容を表示
df_eden
名前 クラス
0 アーニャ 1年3組
1 ダミアン 1年3組
2 ベッキー 1年3組
3 ビル 1年4組
Hide code cell content
# onで名前をキーとして指定し、how="inner"で内部結合を指定
pd.merge(df_forger, df_eden, on="名前", how="inner")
名前 役割 秘密 クラス
0 アーニャ 超能力者 1年3組
Hide code cell content
# onで名前をキーとして指定し、how="outer"で外部結合を指定
pd.merge(df_forger, df_eden, on="名前", how="outer")
名前 役割 秘密 クラス
0 ロイド スパイ NaN
1 ヨル 殺し屋 NaN
2 アーニャ 超能力者 1年3組
3 ダミアン NaN NaN 1年3組
4 ベッキー NaN NaN 1年3組
5 ビル NaN NaN 1年4組
Hide code cell content
# onで名前をキーとして指定し、how="left"で左外部結合を指定
pd.merge(df_forger, df_eden, on="名前", how="left")
名前 役割 秘密 クラス
0 ロイド スパイ NaN
1 ヨル 殺し屋 NaN
2 アーニャ 超能力者 1年3組
Hide code cell content
# onで名前をキーとして指定し、how="right"で右外部結合を指定
pd.merge(df_forger, df_eden, on="名前", how="right")
名前 役割 秘密 クラス
0 アーニャ 超能力者 1年3組
1 ダミアン NaN NaN 1年3組
2 ベッキー NaN NaN 1年3組
3 ビル NaN NaN 1年4組

データのグルーピングとピボット#

グルーピング#

Hide code cell content
# ccidごとにグループ化し、それぞれのceidのユニーク数を集約して冒頭5行を表示
df_ce.groupby("ccid")["ceid"].nunique().reset_index().head()
ccid ceid
0 C102235 1
1 C109295 10
2 C109296 19
3 C109297 1
4 C110879 1
Hide code cell content
# まず、dateでソートすることで、発売日順に並ぶように調整
df_ce = df_ce.sort_values(["ccid", "date"], ignore_index=True)

# その上で、マンガ作品(ccid)ごとに冒頭8話を抽出
# 代表的な列のみ選択肢、最初の10行を表示
df_ce.groupby("ccid").head(8)[["ccname", "date", "cename"]].head(10)
ccname date cename
0 さばげぶっ! 2014-08-06 出張編
1 マウンドの稲妻 1980-08-18 野性の鉄腕の巻
2 マウンドの稲妻 1980-08-25 ●サンダーボンバー誕生の巻
3 マウンドの稲妻 1980-09-01 ●エースのあかし!の巻●
4 マウンドの稲妻 1980-09-08 ●ボンバーズ登場!!の巻●
5 マウンドの稲妻 1980-09-15 ●戦りつのマフィアリーグの巻●
6 マウンドの稲妻 1980-09-22 ●マフィアリーグへの出発の巻●
7 マウンドの稲妻 1980-09-29 ●マフィアリーグ開戦の巻●
8 マウンドの稲妻 1980-10-06 黒い罠に勝て!の巻
11 SCRAP三太夫 1988-10-03 NaN

ピボット#

Hide code cell content
# df_ceに曜日情報を追加
df_ce["weekday"] = pd.to_datetime(df_ce["date"]).dt.weekday

# マンガ雑誌(mcname)別に曜日(weekday)別の発売巻号(miid)数を集計
# 行(index)としてmcname、列(columns)としてweekdayを指定
# valuesで指定した列(miid)をaggfuncで指定した集約関数(nunique)で集約
df_ce.pivot_table(index="mcname", columns="weekday", values="miid", aggfunc="nunique")
weekday 0 1 2 3 4 5 6
mcname
週刊少年サンデー 9 9 1706 22 16 15 530
週刊少年ジャンプ 2177 25 25 22 22 15 20
週刊少年チャンピオン 554 9 5 1298 444 5 6
週刊少年マガジン 11 13 1673 26 26 20 539