pandas の apply と transform の違いを知る

はじめに

Pandas を用いたグループに対する特徴量生成では専ら apply を使っていました。
transform なるメソッドを知ったので、注意点とともに整理します。

問題設定

ある2つのグループに対して、数値が与えられている。
この2つのグループそれぞれに対して、何らかの演算結果(今回は平均)を得たい。

df = pd.DataFrame([[1, 2], [1, 3], [1, 4], [1, 5], [2, 6], [2, 7], [2, 8], [2, 9]], columns=['group', 'value'])

apply

やり方はいくつかありますが、まずは apply から。

d = df.groupby(by=['group']).mean()['value'].to_dict()
df['mean'] = df.apply(lambda x: d[x['group']], axis=1)
print(df)

# ===============================
   group  value  mean
0      1      2   3.5
1      1      3   3.5
2      1      4   3.5
3      1      5   3.5
4      2      6   7.5
5      2      7   7.5
6      2      8   7.5
7      2      9   7.5

map でもできる。 単純な平均を得たいならばこちらでやる気がする。

d = dict()
d['mean'] = df.groupby(by=['group'])['value'].mean()
df['mean'] = df['group'].map(d['mean'].to_dict())
print(df)

上記2つの変換ではどちらも、辞書を使いました。
groupby でまとめた DataFrame に対して演算を行うとグループごとにまとめられた結果が得られ、もとの DataFrame と形が違うためです。

print(df.groupby(by=['group'])['value'].mean())

# ==================================================
group
1    3.5
2    7.5

この方法は、平均以外の複雑な計算にも対応できます。
しかし、もっと賢い方法がありそう…
(より良い方法が見つかったら追記する。)

transform とは

transform を用いた計算では、もとの DataFrame と同一の形状を得ることができる。

df2 = df.groupby(by=['group'])['value'].transform(lambda x: x.mean())
print(df2)

# =====================================================
0    3.5
1    3.5
2    3.5
3    3.5
4    7.5
5    7.5
6    7.5
7    7.5

従って、今回得たい DataFrame は下記のように得られる。

df['mean'] = df.groupby(by=['group'])['value'].transform(lambda x: x.mean())

簡単!! 綺麗!!

transform の注意点

上のプログラムを apply と同じ思想で、書き換えると動かない。

df['mean'] = df.groupby(by=['group']).transform(lambda x: x['value'].mean(), axis=1)  # これは動かない

# ===========================
TypeError: Transform function invalid for data types

TypeError: Transform function invalid for data types となってしまう。

これは、transform の中で演算可能なものが Series であるかららしい。
つまり、DataFrame 中の2つ以上の列を演算することで、新しい値を得たいならば apply を使わなければならないということ。
ただし、 Series に対して演算可能で、単一の数値を返すような sum(), len() などは演算可能である。

おわりに

transform という綺麗な方法を知り喜んで使っていたら見事に error に当たったのでまとめました。
groupby を経由する演算は途中経過を print できないので挙動を掴みにくいですが、参考先の web site が非常に役に立ちました。

参考

コメント

タイトルとURLをコピーしました