前処理#

madbから必要なデータを抽出し,縦持ちのcsvに変換します.

環境構築#

import warnings
warnings.filterwarnings('ignore')
!pip install ijson
Requirement already satisfied: ijson in /opt/conda/lib/python3.9/site-packages (3.1.4)
import glob
import ijson
import json
import numpy as np
import os
import pandas as pd
from pprint import pprint
from tqdm import tqdm_notebook as tqdm
import zipfile
DIR_IN = '../../madb/data/json-ld'
DIR_TMP = '../../data/preprocess/tmp'
DIR_OUT = '../../data/preprocess/out'
FNS_CM = [
    'cm102',
    'cm105',
    'cm106',
]
# 分析対象とする雑誌名
MCNAMES = [
    '週刊少年ジャンプ',
    '週刊少年マガジン', 
    '週刊少年サンデー',
    '週刊少年チャンピオン',
]
COLS_CM105 = [
    'identifier',
    'label',
    'name',
]
# cm102, genre=='雑誌巻号'
COLS_MIS = {
    'identifier': 'miid',
    'label': 'miname',
    'datePublished': 'datePublished',
    'isPartOf': 'mcid',
    'issueNumber': 'issueNumber',
    'numberOfPages': 'numberOfPages',
    'publisher': 'publisher',
    'volumeNumber': 'volumeNumber',
    'price': 'price',
    'editor': 'editor',
}
# cm102, genre=='マンガ作品'
COLS_EPS = {
    'relatedCollection': 'cid',
    'creator': 'creator',
    'note': 'note',
    'alternativeHeadline': 'epname',
    'pageStart': 'pageStart',
    'pageEnd': 'pageEnd',
    'isPartOf': 'miid',
}
# cm106
COLS_CS = {
    'identifier': 'cid', 
    'name': 'cname'
}
# 最終的に出力するカラム
COLS_OUT = [
    'mcname', 'miid', 'miname', 'cid', 'cname', 'epname',
    'creator', 'pageStart', 'pageEnd', 'numberOfPages',
    'datePublished', 'price', 'publisher', 'editor',
]
# 許容するpageEnd,pageStartの最大値
MAX_PAGES = 1000

関数#

def read_json(path):
    """
    jsonファイルを辞書として読み込む関数.

    Params:
        path (str): 読込対象ファイルパス
    Returns:
        dict: 辞書
    """
    with open(path, 'r') as f:
        dct = json.load(f)

    return dct
def save_json(path, dct):
    """
    辞書をjson形式で保存する関数.

    Params:
        path (str): jsonファイルの保存先
        dct (dict): 保存対象辞書
    """
    with open(path, 'w') as f:
        json.dump(dct, f, ensure_ascii=False, indent=4)
def read_json_w_filters(path, items, filters):
    """itemsのうち,filtersの条件を満たすもののみを抽出
    path: jsonファイルのパス
    items: jsonファイル中でitemsを取得するキー
    filters: dict形式.item[key] in valueで条件づけする想定
    """
    out = []
    with open(path, 'r') as f:
        parse = ijson.items(f, items)
        for item in parse:
            # filtersの条件をすべて満足するもの以外はbreak
            for k, v in filters.items():
                if k not in item.keys():
                    break
                if item[k] not in v:
                    break
            else:
                # breakしなかった場合はoutに追加
                out.append(item)
    return out
def try_mkdirs(path) -> None:
    """mkdirsにtry"""
    try:
        os.makedirs(path)
    except FileExistsError as e:
        pass

出力フォルダの生成#

try_mkdirs(DIR_TMP)
try_mkdirs(DIR_OUT)

解凍#

マンガ系のデータ(*cm*)のみDIR_TMPに解凍する.

ps_cm = glob.glob(f'{DIR_IN}/*_cm*')
for p_from in tqdm(ps_cm):
    p_to = p_from.replace(DIR_IN, DIR_TMP).replace('.zip', '')
    
    with zipfile.ZipFile(p_from) as z:
        z.extractall(p_to)

前処理#

対象#

ps_cm = {cm: glob.glob(f'{DIR_TMP}/*{cm}*/*') for cm in FNS_CM}
pprint(ps_cm)
{'cm102': ['../../data/preprocess/tmp/metadata_cm-item_cm102_json/metadata_cm-item_cm102_json\\metadata_cm-item_cm102_00001.json',
           '../../data/preprocess/tmp/metadata_cm-item_cm102_json/metadata_cm-item_cm102_json\\metadata_cm-item_cm102_00002.json'],
 'cm105': ['../../data/preprocess/tmp/metadata_cm-col_cm105_json/metadata_cm-col_cm105_json\\metadata_cm-col_cm105_00001.json'],
 'cm106': ['../../data/preprocess/tmp/metadata_cm-col_cm106_json/metadata_cm-col_cm106_json\\metadata_cm-col_cm106_00001.json']}

cm105#

漫画雑誌に関するデータを整形し,分析対象のIDを特定.

def format_magazine_name(name):
    """nameからpublished_nameを取得"""
    for x in name:
        if type(x) is str:
            return x
    raise Exception(f'No magazine name in {name}!')
cm105 = read_json(ps_cm['cm105'][0])
df_cm105 = pd.DataFrame(cm105['@graph'])[COLS_CM105]
# 雑誌名を取得
df_cm105['mcname'] = df_cm105['name'].apply(
    lambda x: format_magazine_name(x))
# mcnameで抽出
df_cm105[df_cm105['mcname'].isin(MCNAMES)].T
148 1449 1828 2569
identifier C117607 C119033 C119459 C120282
label 週刊少年サンデー 週刊少年マガジン 週刊少年ジャンプ 週刊少年チャンピオン
name [{'@language': 'ja-hrkt', '@value': 'シュウカンショウネ... [週刊少年マガジン, {'@language': 'ja-hrkt', '@value': ... [週刊少年ジャンプ, {'@language': 'ja-hrkt', '@value': ... [{'@language': 'ja-hrkt', '@value': 'シュウカンショウネ...
mcname 週刊少年サンデー 週刊少年マガジン 週刊少年ジャンプ 週刊少年チャンピオン
# 雑誌ID:雑誌名
mcid2mcname = \
    df_cm105[df_cm105['mcname'].isin(MCNAMES)].\
    groupby('identifier')['mcname'].first().to_dict()
# 保存
save_json(os.path.join(DIR_TMP, 'mcid2mcname.json'), mcid2mcname)

cm102#

雑誌巻号およびマンガ作品に関するデータを整形し,一次保存.

def format_cols(df, cols_rename):
    """cols_renameのcolのみを抽出し,renmae"""
    df_new = df.copy()
    df_new = df_new[cols_rename.keys()]
    df_new = df_new.rename(columns=cols_rename)
    return df_new
def get_items_by_genre(graph, genre):
    """graphから所定のgenreのアイテム群を取得"""
    items = [
        x for x in graph 
        if 'genre' in x.keys() and x['genre'] == genre]
    return items
def get_id_from_url(url):
    """url表記から末尾のidを取得"""
    if url is np.nan:
        return None
    else:
        return url.split('/')[-1]
def format_nop(numberOfPages):
    """numberOfPagesからpやPを除外"""
    nop = numberOfPages
    if nop is np.nan:
        return None
    elif nop == '1冊' or nop == '1サツ':
        # M577294, 週刊少年サンデー 2010年 表示号数17
        # nop = '1冊'
        return None
    else:
        return int(nop.replace('p', '').replace('P', ''))
def format_price(price):
    """priceを整形"""
    if price is np.nan:
        return None
    elif price == 'JUMPガラガラウなかも':
        # M544740, 週刊少年ジャンプ 1971年 表示号数47
        # price = 'JUMPガラガラウなかも'
        return None
    elif price == '238p':
        # M542801, 週刊少年ジャンプ 2010年 表示号数42
        # price = '238p'
        return 238
    else:
        price_new = price.replace('円', '').replace('+税', '')
        return int(price_new)
def format_creator(creator):
    """creatorから著者名を取得"""
    if creator is np.nan:
        return None
    for x in creator:
        if type(x) is str:
            return x
    raise Exception('No creator name!')
def create_df_mis(path, mcids):
    """pathとmcidsからdf_misを構築"""    
    filters = {
        'genre': ['雑誌巻号'],
        'isPartOf': [
            f'https://mediaarts-db.bunka.go.jp/id/{mcid}' for mcid in mcids],
    }
    mis = read_json_w_filters(path, '@graph.item', filters)
    df_mis = pd.DataFrame(mis)
    
    # 列を整理
    df_mis = format_cols(df_mis, COLS_MIS)
    # mcidを取得
    df_mis['mcid'] = df_mis['mcid'].apply(
        lambda x: get_id_from_url(x))
    # datePublishedでソート
    df_mis['datePublished'] = pd.to_datetime(df_mis['datePublished'])
    df_mis  = df_mis.sort_values('datePublished', ignore_index=True)
    # numberOfPagesを整形
    df_mis['numberOfPages'] = df_mis['numberOfPages'].apply(
        lambda x: format_nop(x))
    # priceを整形
    df_mis['price'] = df_mis['price'].apply(
        lambda x: format_price(x))
    return df_mis
def create_df_eps(path, miids):
    """pathとmiidsからdf_epsを構築"""
    filters = {
        'genre': ['マンガ作品'],
        'isPartOf': [
            f'https://mediaarts-db.bunka.go.jp/id/{miid}' for miid in miids],
    }
    eps = read_json_w_filters(path, '@graph.item', filters)
    df_eps = pd.DataFrame(eps)
    
    # 列を整形
    df_eps = format_cols(df_eps, COLS_EPS)
    # url表記から各idを取得
    df_eps['cid'] = df_eps['cid'].apply(lambda x: get_id_from_url(x))
    df_eps['miid'] = df_eps['miid'].apply(lambda x: get_id_from_url(x))
    # 著者名を取得
    df_eps['creator'] = df_eps['creator'].apply(
        lambda x: format_creator(x))
    return df_eps
for i, p in tqdm(enumerate(ps_cm['cm102'])):
    mcids = list(mcid2mcname.keys())
    df_mis = create_df_mis(p, mcids)
    # 雑誌巻号のmiidを取得し,epsの抽出に利用
    miids = set(df_mis['miid'].unique())
    df_eps = create_df_eps(p, miids)
    
    # 保存
    fn_mis = os.path.join(DIR_TMP, f'mis_{i+1:05}.csv')
    fn_eps = os.path.join(DIR_TMP, f'eps_{i+1:05}.csv')
    df_mis.to_csv(fn_mis, index=False)
    df_eps.to_csv(fn_eps, index=False)

cm106#

掲載作品に関するデータを整形し,一次保存.

def format_cname(cname):
    """cnameから著者名を取得"""
    if cname is np.nan:
        return None
    for x in cname:
        if type(x) is str:
            return x
    raise Exception('No comic name!')
cm106 = read_json(ps_cm['cm106'][0])
# 雑誌掲載ジャンルのアイテムを抽出
cs = get_items_by_genre(cm106['@graph'], '雑誌掲載')
# DataFrame化
df_cs = pd.DataFrame(cs)
# カラムを整理
df_cs = format_cols(df_cs, COLS_CS)
# cnameを整形
df_cs['cname'] = df_cs['cname'].apply(
    lambda x: format_cname(x))
# 保存
df_cs.to_csv(os.path.join(DIR_TMP, 'cs.csv'), index=False)

加工#

結合#

def read_and_concat_csvs(pathes):
    """pathesのcsvを順番に呼び出し,concat"""
    df_all = pd.DataFrame()
    for p in pathes:
        df = pd.read_csv(p)
        df_all = pd.concat([df_all, df], ignore_index=True)
    return df_all
def sort_date(df, col_date):
    """dfをcol_dateでソート"""
    df_new = df.copy()
    df_new[col_date] = pd.to_datetime(df_new[col_date])
    df_new = df_new.sort_values(col_date, ignore_index=True)
    return df_new
# 各ファイルのパスを抽出
ps_mis = glob.glob(f'{DIR_TMP}/mis*.csv')
ps_eps = glob.glob(f'{DIR_TMP}/eps*.csv')
ps_cs = glob.glob(f'{DIR_TMP}/cs*.csv')
# データの読み出し
df_mis = read_and_concat_csvs(ps_mis)
df_eps = read_and_concat_csvs(ps_eps)
df_cs = read_and_concat_csvs(ps_cs)
mcid2mcname = read_json(os.path.join(DIR_TMP, 'mcid2mcname.json'))
# 結合
df_all = pd.merge(df_eps, df_cs, on='cid', how='left')
df_all = pd.merge(df_all, df_mis, on='miid', how='left')
df_all['mcname'] = df_all['mcid'].apply(
    lambda x: mcid2mcname[x])
# 必要な列のみ抽出
df_all = df_all[COLS_OUT]
# ソート
df_all['datePublished'] = pd.to_datetime(df_all['datePublished'])
df_all = df_all.sort_values(['datePublished', 'pageStart'], ignore_index=True)

各雑誌のdatePublishedを統一#

df_all.groupby('mcname')['datePublished'].min()
mcname
週刊少年サンデー     1959-04-05
週刊少年ジャンプ     1969-11-03
週刊少年チャンピオン   1970-07-27
週刊少年マガジン     1959-03-26
Name: datePublished, dtype: datetime64[ns]
df_all.groupby('mcname')['datePublished'].max()
mcname
週刊少年サンデー     2017-07-12
週刊少年ジャンプ     2017-07-31
週刊少年チャンピオン   2017-07-13
週刊少年マガジン     2017-07-26
Name: datePublished, dtype: datetime64[ns]
# 全雑誌のうちDBに存在する期間が最も短いものに合わせる
date_min = df_all.groupby('mcname')['datePublished'].min().max()
date_max = df_all.groupby('mcname')['datePublished'].max().min()
df_all = df_all[
    (df_all['datePublished']>=date_min)&\
    (df_all['datePublished']<=date_max)].reset_index(drop=True)
df_all.groupby('mcname')['datePublished'].min()
mcname
週刊少年サンデー     1970-08-02
週刊少年ジャンプ     1970-07-27
週刊少年チャンピオン   1970-07-27
週刊少年マガジン     1970-08-02
Name: datePublished, dtype: datetime64[ns]
df_all.groupby('mcname')['datePublished'].max()
mcname
週刊少年サンデー     2017-07-12
週刊少年ジャンプ     2017-07-10
週刊少年チャンピオン   2017-07-06
週刊少年マガジン     2017-07-12
Name: datePublished, dtype: datetime64[ns]
df_all.value_counts('mcname')
mcname
週刊少年サンデー      46179
週刊少年チャンピオン    45426
週刊少年マガジン      45318
週刊少年ジャンプ      43045
dtype: int64

適切なpageStart/pageEndを持つ行のみ抽出#

# pageStartがpageEndより小さい値であること
asst_ps_pe = df_all['pageStart'] <= df_all['pageEnd']
# pageEndがMAX_PAGES内であること
asst_pe = df_all['pageEnd'] <= MAX_PAGES
# 抽出後のデータ
df_new = df_all[
    (asst_ps_pe&asst_pe)].reset_index(drop=True)
# 除外したデータ
df_drop = df_all[
    ~(asst_ps_pe&asst_pe)].reset_index(drop=True)
# 検証
assert df_all.shape[0] == df_new.shape[0] + df_drop.shape[0]

除外したデータの一覧.

df_drop
mcname miid miname cid cname epname creator pageStart pageEnd numberOfPages datePublished price publisher editor
0 週刊少年ジャンプ M544705 週刊少年ジャンプ 1972年 表示号数30 C88437 くそ坊主ガン鉄 母よどこにの巻 手無功 220.0 219.0 308.0 1972-07-17 100.0 集英社 ∥ シュウエイシャ 長野規
1 週刊少年ジャンプ M544697 週刊少年ジャンプ 1972年 表示号数39 C88021 あらし!三匹 水上スキーの巻 池沢さとし 290.0 289.0 316.0 1972-09-11 100.0 集英社 長野規
2 週刊少年ジャンプ M544696 週刊少年ジャンプ 1972年 表示号数40 C89703 燃えて走れ! NaN 村上もとか 107.0 106.0 316.0 1972-09-18 100.0 集英社 ∥ シュウエイシャ 長野規
3 週刊少年サンデー M579126 週刊少年サンデー 1973年 表示号数44 C92856 ダメおやじ NaN 古谷三敏 189.0 150.0 334.0 1973-10-21 120.0 小学館 ∥ ショウガクカン 井上敬三
4 週刊少年ジャンプ M544561 週刊少年ジャンプ 1975年 表示号数20 C88276 学ちゃんとメリー NaN 大画としゆき 52.0 1.0 268.0 1975-05-19 130.0 集英社 ∥ シュウエイシャ 中野祐介
5 週刊少年サンデー M578825 週刊少年サンデー 1979年 表示号数37 C92118 あばれ大海 にわかライダーの巻 六田登 265.0 232.0 380.0 1979-09-09 170.0 小学館 田中一喜
6 週刊少年ジャンプ M544336 週刊少年ジャンプ 1979年 表示号数44 C89510 ふたりのダービー NaN 田中つかさ 5.0 0.0 344.0 1979-10-29 150.0 集英社 ∥ シュウエイシャ 西村繁男
7 週刊少年ジャンプ M544335 週刊少年ジャンプ 1979年 表示号数45 C89510 ふたりのダービー NaN 田中つかさ 67.0 NaN 336.0 1979-11-05 150.0 集英社 ∥ シュウエイシャ 西村繁男
8 週刊少年ジャンプ M544334 週刊少年ジャンプ 1979年 表示号数46 C89510 ふたりのダービー NaN 田中つかさ 165.0 NaN 336.0 1979-11-12 150.0 集英社 ∥ シュウエイシャ 西村繁男
9 週刊少年ジャンプ M544331 週刊少年ジャンプ 1979年 表示号数48 C89510 ふたりのダービー NaN 田中つかさ 235.0 0.0 382.0 1979-11-26 170.0 集英社 ∥ シュウエイシャ 西村繁男
10 週刊少年ジャンプ M544330 週刊少年ジャンプ 1979年 表示号数49 C89510 ふたりのダービー NaN 田中つかさ 143.0 NaN 336.0 1979-12-03 150.0 集英社 ∥ シュウエイシャ 西村繁男
11 週刊少年ジャンプ M544328 週刊少年ジャンプ 1979年 表示号数51 C89510 ふたりのダービー NaN 田中つかさ 223.0 NaN 336.0 1979-12-17 150.0 集英社 ∥ シュウエイシャ 西村繁男
12 週刊少年ジャンプ M544327 週刊少年ジャンプ 1979年 表示号数52 C89510 ふたりのダービー NaN 田中つかさ 187.0 NaN 384.0 1979-12-24 170.0 集英社 ∥ シュウエイシャ 西村繁男
13 週刊少年ジャンプ M544324 週刊少年ジャンプ 1980年 表示号数3 C88057 いずみちゃんグラフィティー NaN 金井たつお 60.0 0.0 416.0 1980-01-21 170.0 集英社 ∥ シュウエイシャ 西村繁男
14 週刊少年ジャンプ M544324 週刊少年ジャンプ 1980年 表示号数3 C89510 ふたりのダービー NaN 田中つかさ 319.0 0.0 416.0 1980-01-21 170.0 集英社 ∥ シュウエイシャ 西村繁男
15 週刊少年サンデー M578803 週刊少年サンデー 1980年 表示号数9 C93296 ドロファイター NaN 村上もとか 247.0 246.0 380.0 1980-02-24 170.0 小学館 ∥ ショウガクカン 田中一喜
16 週刊少年サンデー M578597 週刊少年サンデー 1984年 表示号数5 C93515 ラブZ D 愛せない ⑭ やまさき拓味 221.0 0.0 388.0 1984-01-18 190.0 小学館 ∥ ショウガクカン 田中一喜
17 週刊少年マガジン M536783 週刊少年マガジン 1984年 表示号数11 C90685 コンポラ先生 オンボロバスが大変身!?の巻 もとはしまさひで 139.0 1578.0 348.0 1984-02-29 180.0 講談社 ∥ コウダンシャ 三樹創作
18 週刊少年チャンピオン M557460 週刊少年チャンピオン 1986年 表示号数22 C94728 たつみ!センセーション NaN ゆめおい 319.0 38.0 348.0 1986-05-09 180.0 秋田書店 ∥ アキタショテン 壁村耐三
19 週刊少年チャンピオン M557411 週刊少年チャンピオン 1987年 表示号数21 C94102 4P田中くん 第41話 実力発揮、春日高校 川三番地 49.0 48.0 364.0 1987-05-01 180.0 秋田書店 ∥ アキタショテン 壁村耐三
20 週刊少年マガジン M536541 週刊少年マガジン 1988年 表示号数46 C90588 激烈バカ 第36話 前夜祭!!! / ガンバレ日本!!! / 強引!なんちゃって野郎!! / 鎌倉野郎... 斉藤富士夫 359.0 261.0 396.0 1988-10-26 180.0 講談社 ∥ コウダンシャ 五十嵐隆夫
21 週刊少年チャンピオン M557113 週刊少年チャンピオン 1993年 表示号数16 C94561 グラップラー刃牙 第73話 長老 板垣恵介 9999.0 30.0 412.0 1993-04-01 200.0 秋田書店 ∥ アキタショテン 岡本三司
22 週刊少年チャンピオン M557112 週刊少年チャンピオン 1993年 表示号数17 C93997 俺たち鶴高ラグビー部 タックル〔□14〕キャプテンシー!! 山本幸四郎 359.0 358.0 412.0 1993-04-08 200.0 秋田書店 ∥ アキタショテン 岡本三司
23 週刊少年チャンピオン M557103 週刊少年チャンピオン 1993年 表示号数27 C95825 女郎 〔○52〕時間目 タタリじゃあ~ 笠原倫 63.0 0.0 412.0 1993-06-17 200.0 秋田書店 ∥ アキタショテン 岡本三司
24 週刊少年サンデー M578069 週刊少年サンデー 1994年 表示号数24 C92071 FCレッドカード GOAL39 / 美しさは罪 / 心うらはら / プライド / だまされた! / 謎の指サイ... しろうず秀明 248.0 247.0 420.0 1994-06-01 200.0 小学館 ∥ ショウガクカン 平山隆
25 週刊少年サンデー M578067 週刊少年サンデー 1994年 表示号数26 C92627 川添孝一のJリーグカルチョクラブ Kick off23 前期優勝チームは、はたして… NaN 156.0 155.0 408.0 1994-06-15 200.0 小学館 ∥ ショウガクカン 平山隆
26 週刊少年ジャンプ M543567 週刊少年ジャンプ 1995年 表示号数1 C88491 ジョジョの奇妙な冒険 思い出したぞ! 荒木飛呂彦 2275.0 293.0 470.0 1995-01-01 200.0 集英社 ∥ シュウエイシャ 堀江信彦
27 週刊少年マガジン M536070 週刊少年マガジン 1998年 表示号数16 C91434 はじめの一歩 Round386 弱点 森川ジョージ 171.0 NaN 468.0 1998-04-01 220.0 講談社 ∥ コウダンシャ 野内雅宏
28 週刊少年ジャンプ M543400 週刊少年ジャンプ 1998年 表示号数25 C89166 封神演義 第90回 趙公明攻略Ⅵ-蝉玉・ストーカー被害- 藤崎竜 359.0 349.0 456.0 1998-06-01 220.0 集英社 ∥ シュウエイシャ 鳥嶋和彦
29 週刊少年マガジン M536060 週刊少年マガジン 1998年 表示号数27 C89971 Dreams 第81話 特訓の成果 川三番地 233.0 232.0 470.0 1998-06-17 230.0 講談社 ∥ コウダンシャ 野内雅宏
30 週刊少年ジャンプ M543372 週刊少年ジャンプ 1999年 表示号数2 C89162 ホイッスル! 俺の居場所!の巻 樋口大輔 343.0 341.0 452.0 1999-01-08 230.0 集英社 ∥ シュウエイシャ 鳥島和彦
31 週刊少年ジャンプ M543371 週刊少年ジャンプ 1999年 表示号数4 C87726 I''s ウラ目ウラ目 桂正和 281.0 207.0 512.0 1999-01-15 230.0 集英社 ∥ シュウエイシャ 鳥島和彦
32 週刊少年チャンピオン M556789 週刊少年チャンピオン 1999年 表示号数48 C94192 O-HA-YO にらめっこ / 秋の高座 / 卵を割る娘 / メロンの恋人たち / 恋愛小説 / 石庭 / ... 川島よしお 198.0 101.0 444.0 1999-11-04 220.0 秋田書店 ∥ アキタショテン 大塚公平
33 週刊少年ジャンプ M543308 週刊少年ジャンプ 2000年 表示号数20 C88492 ジョジョの奇妙な冒険 Part6 ストーンオーシャン 捕獲計画 荒木飛呂彦 289.0 208.0 450.0 2000-05-01 220.0 集英社 ∥ シュウエイシャ 鳥嶋和彦
34 週刊少年マガジン M535433 週刊少年マガジン 2011年 表示号数18 C89995 GTO SHONAN 14DAYS LESSON.60 この手につかんだ未来地図 藤沢とおる 345.0 264.0 479.0 2011-04-13 248.0 講談社 ∥ コウダンシャ 森田浩章
35 週刊少年マガジン M675760 週刊少年マガジン 2015年 表示号数16 C110993 リアルアカウント account 13 Real & Virtual 渡辺静 374.0 298.0 236.0 2015-04-01 260.0 NaN 菅原喜一郎
36 週刊少年サンデー M675826 週刊少年サンデー 2015年 表示号数35 C110901 戦争劇場 第48戦:手を出したら最後… 土星フジコ 601.0 308.0 506.0 2015-07-29 270.0 NaN 市原武法

episodeのページ数pagesをカラムに追加#

df_new['pages'] = df_new['pageEnd'] - df_new['pageStart'] + 1

各雑誌巻号の最終ページpageEndMaxをカラムに追加#

# 各雑誌巻号の最終ページ
miname2page = df_new.groupby('miname')['pageEnd'].max().to_dict()

df_new['pageEndMax'] = df_new['miname'].apply(
    lambda x: miname2page[x])

各episodeの掲載位置pageStartPositionをカラムに追加#

df_new['pageStartPosition'] = \
    df_new['pageStart'] / df_new['pageEndMax']
df_new['pageStartPosition'].describe()
count    179931.000000
mean          0.514837
std           0.283146
min           0.002045
25%           0.274840
50%           0.520588
75%           0.759626
max           1.000000
Name: pageStartPosition, dtype: float64

保存#

# 全データ
df_new.to_csv(
    os.path.join(DIR_OUT, 'episodes.csv'), index=False,
    encoding='utf_8_sig')
# 除外したデータ
df_new.to_csv(os.path.join(DIR_OUT, 'droped_episodes.csv'), index=False)