ハヤカワ・ポケット・ミステリを分析する ( Python pandasを使ってみよう )


pandasは、データの加工、解析に非常に役立つ Python のライブラリです。も何冊か出ていますが、そのなかでは、pandasの作者自らが書いた「Pythonによるデータ分析入門」が代表的なものでしょう。
ただ、pandasを理解するには書籍を読むより、興味がある分野のデータを入手し、実際に手を動かし使ってみることが一番です。

今回は、ミステリファンなら誰でも知っている「ハヤカワ・ポケット・ミステリ」を例に、簡単なデータ分析をやってみましょう。
「分析手法に興味はないから、結果だけ見たい」という方は、次の記事に進んでください。


ハヤカワ・ポケット・ミステリとは

ウィキペディア(Wikipedia)によれば、

ハヤカワ・ポケット・ミステリ(正式名称:ハヤカワ・ミステリ、HAYAKAWA POCKET MYSTERY BOOK、通称:ポケミス、略称:HPB)は、早川書房が刊行する翻訳ミステリ専門の叢書。新書判。キャッチフレーズは「世界最高最大のミステリ・シリーズ」。

ということです。1953(昭和28)年の刊行から、60年以上経った現在(2020(令和2)年)まで続いているのですから、上のキャッチフレーズも頷けます。

データのダウンロード

横丁の名探偵というサイトで、「ハヤカワ・ポケット・ミステリ」の作品リストが公開されています。ダウンロードができるようなので、自由に使用してよいということでしょう。ありがたく使わせていただきます。

データは下記のようにCSV形式となっています。「大いなる殺人」のように同一ナンバーでも内容に差異があるようなものや、改訳されたものは複数エントリされているようです。

101,大いなる殺人,ミッキー・スピレイン,清水俊二,1953.09.05,江戸川亂歩,×  
101,大いなる殺人,ミッキー・スピレイン,清水俊二,,編集部S,☆  
102,赤い収穫,ダシェル・ハメット,砧一郎,1953.09.30,江戸川亂歩,×  
103,黒衣の花嫁,コーネル・ウールリッチ,黒沼健,1953.09.10,H,×  
104,ワイルダー一家の失踪,ハーバート・ブリーン,西田政治,1953.11.05,江戸川亂歩,×  
105,裁くのは俺だ,ミッキー・スピレイン,中田耕治,1953.11.05,江戸川亂歩,×  

ダウンロードしたデータを、“hpb.csv” という名称で保存します。また、文字コードが、“SJIS” のようなので、“UTF-8” に変換しておきましょう。いろいろやり方はありますが、ここでは、“nkf” を使います。

$ nkf -w --overwrite hpb.csv  

これでデータの準備は出来ました。


Python pandas による分析

Pythonインタプリタを起動します。

$ python  
Python 3.7.3 (default, Oct 30 2019, 14:24:57)  
[GCC 7.4.0] on linux  
Type "help", "copyright", "credits" or "license" for more information.  
>>>  

(1) pandasのimport

Pythonのモジュールとして、pandasをimportします。

>>> from pandas import Series, DataFrame  
>>> import pandas as pd  
>>>  

(2) CSVファイルの読み込み

次に、先程ダウンロードしたCSVファイルを読み込みます。
pandasは、標準でCSVファイルを読むメソッドを持っているので、非常に便利です。フィールド名は、namesパラメータで指定していますが、1行目がフィールド名になっているCSVも使えるようです。

>>> df = pd.read_csv("hpb.csv", names=['vol','title','author','translator','p_date','comment','is_stock'])  

pythonのlen関数を使い、件数を確認しておきます。

>>> print(len(df))  
1864  

データの内容も確認しておきましょう。head(件数)で最初から、tail(件数)で後ろからの件数分を表示させることができます。件数を指定しないと5件ですね。

>>> print(df.head())  
   vol       title       author translator      p_date comment is_stock  
0  101      大いなる殺人   ミッキー・スピレイン       清水俊二  1953.09.05   江戸川亂歩        ×  
1  101      大いなる殺人   ミッキー・スピレイン       清水俊二         NaN    編集部S        ☆  
2  102        赤い収穫    ダシェル・ハメット        砧一郎  1953.09.30   江戸川亂歩        ×  
3  103       黒衣の花嫁  コーネル・ウールリッチ        黒沼健  1953.09.10       H        ×  
4  104  ワイルダー一家の失踪   ハーバート・ブリーン       西田政治  1953.11.05   江戸川亂歩        ×  
  
>> print(df.tail())  
       vol             title  ...          comment is_stock  
1859  1946            名探偵の密室  ...  クリス・マクジョージ;不二淑子      NaN  
1860  1947          サイコセラピスト  ...              NaN      NaN  
1861  1948  雪が白いとき、かつそのときに限り  ...             稲村文吾      NaN  
1862  1949               熊の皮  ...              NaN      NaN  
1863  1950        流れは、いつか海へと  ...              NaN      NaN  

これで個別分析できる状態となりました。

以下の説明ですが、今回は技術面からの解説にとどめ、ミステリファン的な視点でのコメントは、次の記事に譲りたいと考えます。

(3) 作家別集計

ここでは、ポケミスで出版された作家について分析してみましょう。

まず、作家別の出版点数でサマリーします。

>>> authors = df["author"].value_counts()  

全作家数は、下記のコマンドでわかります。のべ542人の作家が紹介されたということですね。

>>> print(len(authors))  
542  

出版点数、上位5人を出してみましょう。

>>> print(authors.head())  
E・S・ガードナー     100  
アガサ・クリスティー     79  
エド・マクベイン       66  
カーター・ブラウン      64  
エラリイ・クイーン      41  
Name: author, dtype: int64  
>>>  

(4) 訳者別集計

(3)と同様に、翻訳者について分析しておきます。

>>> translators = df["translator"].value_counts()  
>>> print(len(translators))  
397  
>>> print(translators.head())  
田中小実昌    62  
井上一夫     59  
宇野利泰     50  
小倉多加志    35  
村崎敏郎     35  
Name: translator, dtype: int64  
>>>  

(5) 年代別分析

次に、年代別にどのような作家が多く紹介されたかを調べましょう。
とりあえず、1960年代のデータを抜き出してみます。

>>> df_year = df[(df.p_date.str[:3] == "196")]  

(3)同様にデータを表示させます。

>>> authors_year = df_year["author"].value_counts()  
>>> print(len(authors_year))  
163  
>>> print(authors_year.head())  
カーター・ブラウン    60  
E・S・ガードナー    36  
エド・マクベイン     21  
A・A・フェア      19  
ブレット・ハリデイ    16  
Name: author, dtype: int64  
>>>  

これを各年代毎にまとめると、トレンドがわかりそうですね。


ブログ用にデータを加工する

ここまでは、pythonインタプリタでデータを加工しましたが、これをスクリプトにまとめておきます。30ステップ程度で書けてしまいました。pandasの優秀さがわかるのではないでしょうか。
ここでは、次の記事で使えるように、markdownのテーブル形式データで出力するようにしています。

from pandas import Series, DataFrame  
import pandas as pd  
  
df = pd.read_csv("hpb.csv", names=['vol','title','author','translator','p_date','comment','is_stock'])  
print("|作家|作品数|訳者|翻訳数|")  
print("|:-----|-----:|:-----|-------:|")  
authors = df["author"].value_counts()  
translators = df["translator"].value_counts()  
for i in range(10):  
    print("|"+authors.index[i]+'|'+str(authors[i])+"|"+translators.index[i]+'|'+str(translators[i])+"|")  
print("|全作家数 |"+str(len(authors))+"|全訳者数 |"+str(len(translators))+"|")  
print("|HPB全作品数|"+str(len(df))+"|||")  
print()  
years = ["195", "196", "197", "198", "199", "200", "201"]  
for year in years:  
    print("|年代|作家|作品数|訳者|翻訳数|")  
    print("|:-----|:-----|-----:|:-----|-------:|")  
    df_year = df[(df.p_date.str[:3] == year)]  
    authors_year = df_year["author"].value_counts()  
    translators_year = df_year["translator"].value_counts()  
    age = year+"0年〜"  
    for i in range(10):  
        print("|"+age+"|"+authors_year.index[i]+'|'+str(authors_year[i])+"|"+translators_year.index[i]+'|'+str(translators_year[i])+"|")  
        age = ""  
    print("||全作者数 |"+str(len(authors_year))+"|全訳者数 |"+str(len(translators_year))+"|")  
    print("||全作品数 |"+str(len(df_year))+"|||")  
    print()  

こんな形で出力されるので、これを記事に貼り付けるという作戦です。

|作家|作品数|訳者|翻訳数|
|:-----|-----:|:-----|-------:|
|E・S・ガードナー|100|田中小実昌|62|
|アガサ・クリスティー|79|井上一夫|59|
|エド・マクベイン|66|宇野利泰|50|
|カーター・ブラウン|64|尾坂力|35|
|エラリイ・クイーン|41|村崎敏郎|35|
|ジョン・ディクスン・カー|31|小倉多加志|35|
|A・A・フェア|29|高橋豊|32|
|レジナルド・ヒル|25|菊池光|30|
|ミッキー・スピレイン|24|青木久惠|27|
|P・D・ジェイムズ|20|山本俊子|24|
|全作家数 |542|全訳者数 |397|
|HPB全作品数|1864|||

次回は、ミステリファンの視点でデータを見ていきたいと思います。