ハヤカワ・ポケット・ミステリを分析する ( 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|||
次回は、ミステリファンの視点でデータを見ていきたいと思います。