前回に引き続き、「楽天ブックス書籍検索API」を利用してダウンロードした書籍情報データを用いて、ECサイトのカタログデータを処理・分析するためのpythonの小技をまとめました。
まず前回と同様に必要なライブラリを読み込み、データを保存先からロードします。
# ライブラリのインポート import numpy as np import pandas as pd import re import matplotlib.pyplot as plt import seaborn as sns sns.set(font=['IPAexGothic']) # parquetファイルからロード df01 = pd.read_parquet('rakuten_books.parquet') # 列を絞り込む focus_cols=['title','subTitle','seriesName','contents','author','publisherName','size',\ 'itemCaption','salesDate','itemPrice','reviewCount','reviewAverage'] df1 = df01.loc[:,focus_cols]
定型テキストの出現頻度を求める
テキスト情報の列の中でも、出現する文字列のパターンが限定されている場合があります。いわゆる「カテゴリカルデータ」に相当するものです。その出現頻度を知りたいことはよくあります。これにはcollectionsライブラリのCounter()メソッドを用います。ここでは列'publisherName'(出版社)の頻度分布を求め、上位10社を出力します。
# 頻度分布を求める列名を指定する col_name = 'publisherName' import collections c_count = collections.Counter(df1[col_name]) # カウント上位のリストを得る p_names, p_counts = zip(*c_count.most_common(10)) print(p_names)
尚、出力結果は以下のようになりました。
('講談社', 'KADOKAWA', '集英社', '小学館', '宝島社', 'スクウェア・エニックス', '白泉社', '秋田書店', '幻冬舎', '朝日新聞出版')
正規表現による検索
決まった文字列ではなく、ある規則性を持った文字列を検索したい場合には「正規表現」による検索を用います。ここでは、コミックセットのように複数の書籍が一括して販売されているケースを検索し、「○冊セット」の○にあたる数字を取り出すことを考えます。ここではpythonライブラリ're'(regular expressionを略したもの)のsearchメソッド(と内容を取り出すためのgroupメソッド)を一件につき2回用いています。1回目の適用で'○冊セット'の文字列をとりだし、2回目の適用でその中の○にあたる数字の部分を取り出して、int()で数値化しています。
def func_bulk(s): """タイトル文字列sの中の冊数を表すパターンを検索して冊数の数値を返す""" nitem = 0 blkstr1 = re.search('[0-9]+巻セット',s) if not blkstr1 is None: nitem = int(re.search('[0-9]+',blkstr1.group()).group()) return nitem blkstr2 = re.search('[0-9]+冊セット',s) if not blkstr2 is None: nitem = int(re.search('[0-9]+',blkstr2.group()).group()) return nitem blkstr3 = re.search('全[0-9]+巻',s) if not blkstr3 is None: nitem = int(re.search('[0-9]+',blkstr3.group()).group()) return nitem blkstr4 = re.search('全[0-9]+冊',s) if not blkstr4 is None: nitem = int(re.search('[0-9]+',blkstr4.group()).group()) return nitem return nitem # セット書籍の冊数を取り出す df1 = df1.assign(n_bulk = df1['title'].apply(func_bulk)) df81 = df1[df1['n_bulk'] > 0] dfi.export(df81,'kensaku_bulk.png')
結果は以下のようになりました。
データフレーム内の複数の列の演算により新たな列を作成する
これまでにもデータフレーム内のある一つの列から、ある演算によって新しい列を作り出す例が出てきました。演算が簡単なものならばその列を作り出す文の中に式を埋め込めばいいのですが、式が複雑な場合は別途関数を定義して、元の列に関してapplyメソッドを使う、という形でした。それでは、データフレーム内の複数の列を使って新しい列を作り出す場合はどうするのでしょうか。その場合は、データフレームそのものについてappyメソッドを適用します。ここでは列'reviewCount'と列'reviewAverage'を用いて、新しい列'review_pi'を作成しています。
# 新しい列を作成するための関数 def func_review_pi(df): return np.log(df.loc['reviewCount']+1) + df.loc['reviewAverage'] # データフレーム内の複数の列の演算により新たな列を作成する df51 = df1.assign(review_pi = df1.apply(func_review_pi, axis=1))
新しい列を作成するための関数に他の引数がある場合
これまでの例では、データフレーム内の新たな列を作るための関数には「元の列」や「元のデータフレーム」以外の引数はありませんでした。今度は、その関数が別途他の引数を必要とする場合の記述を見てみます。 ここでの例は、書籍のタイトルにある指定したキーワードが含まれていたら、あるジャンルの書籍であると判定するための関数の作成です。一つのジャンルについてキーワードは複数あるものとし、キーワードは2次元のリストで与えられるとします。
# ジャンル別のキーワードのリストの定義 # 0:経済, 1:歴史, 2:科学, 3:医学, 4:旅行, 5:辞典, 6:人生, 7:食事, 8:情報, 9:入試, 10:漫画 kws = [['経済','財務','お金','家計','会計','金融'], ['史','古代'], ['科学','サイエンス','宇宙'], ['医','癌','内科','外科','歯科','手術','疾患'], ['旅','紀行'], ['辞典','広辞苑'], ['人生','生き方','生きかた','ライフ'], ['料理','食事','グルメ','レシピ'], ['Excel','Word','Python','iPhone','iPad','プログラミング','アプリ','HTML','ソフトウェア','情報技術','Adobe'], ['入試','中学受験','高校受験','大学受験'], ['鬼滅の刃','リベンジャーズ','るろうに剣心','スライムだった件','青の祓魔師','呪術廻戦','進撃の巨人']] # キーワード判定関数の定義 def func_genre(s, ww, k): """文字列sに2次元リストwwの第kジャンルのキーワードが 含まれていれば1, 含まれていなければ0を返す""" q = 0 for j in range(len(ww[k])): if ww[k][j] in s: q = 1 return q
演算の元になる列以外の引数がある場合、その引数はapply()メソッドの中で引数名=値の形で指定します。
# タイトルに経済分野のキーワードを含むかどうかのダミー変数を生成する df1= df1.assign(G経済=df1['title'].apply(func_genre, ww=kws, k=0))