DataFrame の集約処理 (数値データ)
Posted on 2020/02/02 in 機械学習 , Updated on: 2020/02/02
はじめに¶
pandas の groupby
メソッドを用いたデータの aggregation (集約)
方法の説明。さらに集約したデータを他の table へ結合し、新たな特徴量を含めたデータで目的変数との相関係数を調べる。本記事では、数値データのみの集約処理を説明する。カテゴリデータに関しては別記事を参照。
テーブルコンペにおいて、一意のサンプルID が付与されている training データとは別に、サンプルIDに対して 1対多 で紐づけられている table データを処理する際に良く用いられる。kaggle の Home Credit Default Risk コンペのデータを用いる。
コンペ概要
Home Credit社は、信用の積み重ねが足りずに融資を受けることができない顧客にも融資を行う会社で、今回のコンペは債務不履行(デフォルト, default)になる顧客を予測する。
参考: Introduction to Manual Feature Engineering
データの準備¶
application_train
データと、1対多で紐づくデータを含む bureau
データを呼び出す。
application_train
: サンプルID としてSK_ID_CURR
列がある。これは一意に決定されるユーザIDで、重複はない。つまり、データの行数とSK_ID_CURR
の一意の数は等しい。bureau
: 上記SK_ID_CURR
で決定される顧客が、過去に行った融資情報をSK_ID_BUREAU
として含む。各ユーザはいくつかのSK_ID_BUREAU
を持つ。また、過去融資情報が無い顧客も存在しているため、bureau
内のSK_ID_CURR
の一意の数は、application_train
内のそれよりも少ない。
データを確認する。
import numpy as np
import pandas as pd
train = pd.read_csv('data/application_train.csv')
print('Training data shape:', train.shape)
print('Unique number of SK_ID_CURR in training data:', train.SK_ID_CURR.nunique())
train.head()
bureau = pd.read_csv('data/bureau.csv')
print('Bureau data shape:', bureau.shape)
print('Unique number of SK_ID_CURR in bureau data:', bureau.SK_ID_CURR.nunique())
print('Unique number of SK_ID_BUREAU in bureau data:', bureau.SK_ID_BUREAU.nunique())
bureau.head()
Aggregation (手作業)¶
bureau
データに対して集約処理を実行する。groupby
メソッドで、顧客IDでグループ化し、agg
関数を用いて集計する。ここでは、「頻度」,「平均」,「合計」を適用するが、任意の関数を渡すこともできる。また、pandas の agg
関数は数値データのみに適用される。
# SK_ID_BUREAU も数値データとして扱われるので、除外する
bureau_agg = bureau.drop(columns=['SK_ID_BUREAU'])
bureau_agg = bureau_agg.groupby('SK_ID_CURR', as_index=False).agg(['count', 'mean', 'sum']).reset_index()
bureau_agg.head()
これにより、各数値特徴量の「頻度」,「平均」,「合計」特徴量が作成された。ただ、カラム名が二段(level 2)になっているため、下記の操作でカラムの level を下げる必要がある。
# column 名のリストを準備
columns = ['SK_ID_CURR']
# カラム名を一つ一つ読み出す
for col in bureau_agg.columns.levels[0]:
# SK_ID_CURR は飛ばす
if col != 'SK_ID_CURR':
for stat in bureau_agg.columns.levels[1][:-1]:
# 変数と統計量の新しい名前を生成し、リストへ追加
columns.append('bureau_%s_%s' % (col, stat))
# 作成したカラム名を dataframe へ適用
bureau_agg.columns = columns
print('bureau_agg shape:', bureau_agg.shape)
bureau_agg.head()
上記作業で、例えば DAYS_CREDIT
内の count
特徴量が、新たに bureau_DAYS_CREDIT_count
という名称になり、一段の名前になっていることがわかる。これで application_train
と SK_ID_CURR
で紐づけて結合することができる。
ここで、burea_agg
に含まれていない SK_ID_CURR
の集約特徴量部は、NaN になる。(exp. SK_ID_CURR=100006)
print('Traning data shape before merged:', train.shape)
train = train.merge(bureau_agg, on='SK_ID_CURR', how='left')
print('Training data shape after merged:', train.shape)
train.head()
新たに作成された特徴量36個が、dataframe の右側に追加されている。
相関を見る¶
ここから、新たに作成した特徴量と TARGET (目的変数) との相関を見ることで、機械学習モデルに有用な特徴量が作成されたかどうかを調べることができる。
corrs = []
# TARGET と各特徴量の相関係数を計算
for col in columns:
corr = train['TARGET'].corr(train[col])
corrs.append((col, corr))
# 相関係数の絶対値の降順で上位 10 個を表示
corrs = sorted(corrs, key=lambda x: abs(x[1]), reverse=True)
corrs[:10]
Aggregation (関数使って)¶
同様の作業を実行する関数を定義する。これにより他の dataframe にも同じ操作を実施したい時に再利用が可能になる。
# df : 処理する dataframe
# group_var : 集約する起点となる特徴量名 (ID名)
# df_name : dataframe名 (string型)
# agg_list : 処理する統計量のリスト
# remove_cols : 処理しない特徴量リスト
def agg_numeric(df, group_var, df_name, agg_list, remove_cols):
# ID と不要な特徴量を削除する前に、ID列を抜き出し
group_ids = df[group_var]
df = df.drop(columns=remove_cols)
df = df.drop(columns=group_var)
numeric_df = df.select_dtypes('number')
numeric_df.loc[:, group_var] = group_ids
# aggregation 処理
agg = numeric_df.groupby(group_var).agg(agg_list).reset_index()
# カラム名を修正
columns = [group_var]
for col in agg.columns.levels[0]:
if col != group_var:
for stat in agg.columns.levels[1][:-1]:
columns.append('%s_%s_%s' % (df_name, col, stat))
agg.columns = columns
return agg
処理する統計リストを定義して、手作業時と同様の集約処理を実行する。同じ集約済みデータが生成されていることがわかる。
agg_list = ['count', 'mean', 'sum']
bureau_agg_by_func = agg_numeric(bureau, group_var='SK_ID_CURR', df_name='bureau',
agg_list=agg_list, remove_cols=['SK_ID_BUREAU'])
print('bureau_agg_by_func shape:', bureau_agg.shape)
bureau_agg_by_func.head()