View and Copy of pandas.DataFrame
ビッグデータ分析では全てのデータ処理の結果を逐一確認することは不可能に近い。
そのため、結果に明らかな不備が出ないような誤った操作を行ってしまった場合、それに気付くことができずに誤った結果を導いてしまう。
そのような事態を避けるため、pandas でデータ処理をする際はその操作が元データに対して行われているのか、それともそのコピーに対して行われているのかを常に意識しておくべきである。
ここでは、以下のページを参考に[1] pandas の DataFrame
への参照・代入がどのように行われているかをまとめておく。
Data Manipulation in Pandas
データ操作には一般に以下の 2 つの種類がある。
- Access : データを参照 (get) する際の処理で
__getitem()__
が呼ばれる - Assignment : データを代入 (set) する際の処理で
__setitem()__
が呼ばれる
一方、pandas でのデータ処理は []
, .loc
, iloc
などの indexing と呼ばれる操作とそれの連結 (chaining : [][]
など) によって行われる。
Pandas ではどの indexing の操作に対してもその使用される状況に応じて get, set method が自動的に使い分けられる。
Problems
問題が起きるのは、__getitem()___
で呼び出されたオブジェクトに対して __setitem()__
が呼び出されたときである。
Pandas では __getitem()__
が元の DataFrame
の参照を返すのか、それともコピーを返すのかが定まっていない。
従って、そのような状況になった場合、元のデータが変更されるのかそれともコピーされたデータが変更されるのかが一意に定まらず、バグの元になるのである。
Simple Chaning
典型的な例の一つが以下のような chaining 処理である。
df[df['col1']=='example']]['col2'] = 10
この場合、始めの indexing [df['col1']=='example']
で __getitem()__
が呼び出された後、次の indexing ['col2'] = 10
によって __setitem()__
が呼び出される。
先に述べたように __getitem()__
による戻り値は参照かコピーかが保証されていないため、 SettingWithCopyWarning
が出ることになる。
元データを変更したい場合、chaining 処理を行わずに .loc
を用いて元データに対して indexng 処理を行えば良い。
df.loc[df['col1']=='example', 'col2'] = 10
この場合、元データへの indexing .loc[...] =
に応じて __setitem()__
が呼び出されるため、無事元データを変更することができる。
気を付けなければならないのが、代入の際はとりあえず .loc
を使えばよいというわけではないことである。
先に述べたように、pandas の indexing 処理は状況に応じて自動的に決まる。
従って、.loc
は必ずしも set を意味せず、例えば下のように呼び出された場合は先と同様 get と set と chaining になり動作が保証されないことを注意しておく必要がある。
df.loc[df['col1'] == 'example', ('col1', 'col2')]['col2'] = 5.0
Hidden Chaining
実用上よく起こりうるのが、意図せず chaining と同様の操作を行ってしまう場合である。
df_view = df[df['col1`]=='exapmle]
# some sort of manipulations
# ...
df_view['col2'] = 10
この場合も __getitem()__
で作成された変数に対して __setitem()__
が呼び出されるため、再び SettingWithCopyWarning
が出ることになる。
新しく作成したデータ df_view
のみを変更したい場合、.copy()
method を用いて明確にコピーを作っておく必要がある。
df_view = df[df['col1`]=='exapmle].copy()
# ...
後にその値を変更することになるとは思わず copy()
を呼び出さずにコードを書いてしまうことが往々にしてあるため、不要なバグをさけるためにも、例えばメモリを気にしなくてよい場合は常にコピーを作るようにしておくなどのルールを決めておくことが大事である。
Discussion