スライスに割り当てるときの pandas の動作は本質的に予測不可能であることはよく知られています(そして理解できます)。しかし、私は警告によってそれについて警告されることに慣れていSettingWithCopyます。
次の 2 つのコード スニペットのいずれでも警告が生成されないのはなぜですか?また、そのようなコードを意図せずに作成する可能性を減らすには、どのような手法を使用すればよいでしょうか?
# pandas 0.18.1, python 3.5.1
import pandas as pd
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
new_data = data[['a', 'b']]
data = data['a']
new_data.loc[0, 'a'] = 100 # no warning, doesn't propagate to data
data[0] == 1
True
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
new_data = data['a']
data = data['a']
new_data.loc[0] = 100 # no warning, propagates to data
data[0] == 100
True
説明は、現在のコンテキストから親 DataFrame にまだ到達できる場合にのみ、パンダが警告を生成するというものだと思いました。(前の例が示すように、これは検出アルゴリズムの弱点です。)
次のスニペットでは、元の 2 列の DataFrame に到達できなくなっていることがわかりますが、pandas の警告メカニズムは (幸いなことに) トリガーされます。
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
new_data = data['a']
data = data[['a']]
new_data.loc[0] = 100 # warning, so we're safe
編集:
これを調査しているときに、警告が欠落している別のケースを見つけました。
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
data = data.groupby('a')
new_data = data.filter(lambda g: len(g)==1)
new_data.loc[0, 'a'] = 100 # no warning, does not propagate to data
assert data.filter(lambda g: True).loc[0, 'a'] == 1
ほぼ同じ例でも警告がトリガーされます。
data = pd.DataFrame({'a': [1, 2, 2], 'b': ['a', 'b', 'c']})
data = data.groupby('a')
new_data = data.filter(lambda g: len(g)==1)
new_data.loc[0, 'a'] = 100 # warning, does not propagate to data
assert data.filter(lambda g: True).loc[0, 'a'] == 1
更新: コメントに入れるのが難しいため、ここで @firelynx の回答に返信します。
回答で、@firelynx は、データフレーム全体を取得しているため、最初のコード スニペットでは警告が発生しないと述べています。しかし、参加したとしても、警告は表示されません。
# pandas 0.18.1, python 3.5.1
import pandas as pd
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c'], c: range(3)})
new_data = data[['a', 'b']]
data = data['a']
new_data.loc[0, 'a'] = 100 # no warning, doesn't propagate to data
data[0] == 1
True