親データフレームからサブデータフレームを選択するとき、.copy()
メソッドを使ってデータフレームのコピーを作成するプログラマーがいることに気づきました。
なぜ彼らはデータフレームのコピーを作っているのですか?コピーしないとどうなりますか?
これはパウロの答えを拡大したものです。 Pandasでは、DataFrameのインデックスを作成すると、最初のDataFrameへの参照が返されます。したがって、サブセットを変更すると、最初のDataFrameも変更されます。したがって、最初のDataFrameが変更されないようにするには、コピーを使用します。次のコードを見てください。
df = DataFrame({'x': [1,2]})
df_sub = df[0:1]
df_sub.x = -1
print(df)
あなたは得るでしょう:
x
0 -1
1 2
対照的に、以下はdfを変更しません。
df_sub_copy = df[0:1].copy()
df_sub_copy.x = -1
なぜなら、あなたがコピーをしないのであれば、dataFrameを別の名前に割り当てたとしても、インデックスは他の場所で操作することができます。
例えば:
df2 = df
func1(df2)
func2(df)
func1は、df2を変更することによってdfを変更できます。
df2 = df.copy()
func1(df2)
func2(df)
コピーまたはビューを返すかどうかは、インデックスの種類によって異なることに注意する必要があります。
パンダのドキュメンテーションは言います:
コピーに対してビューを返す
データに対するビューがいつ返されるかに関する規則は、NumPyに完全に依存しています。ラベルの配列またはブールベクトルがインデックス付け操作に関係しているときはいつでも、結果はコピーになります。単一ラベル/スカラーのインデックス作成とスライシングでは、 df.ix [3:6]またはdf.ix [:, 'A']を指定すると、ビューが返されます。
主な目的は、連鎖インデックスを使用せずにSettingWithCopyWarning
を削除することです。
ここで連鎖インデックスはdfc['A'][0] = 111
のようなものです。
この文書では、連鎖索引付けは ビューとコピーの対比 で避けるべきだと述べています。これはその文書から少し修正された例です:
In [1]: import pandas as pd
In [2]: dfc = pd.DataFrame({'A':['aaa','bbb','ccc'],'B':[1,2,3]})
In [3]: dfc
Out[3]:
A B
0 aaa 1
1 bbb 2
2 ccc 3
In [4]: aColumn = dfc['A']
In [5]: aColumn[0] = 111
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
In [6]: dfc
Out[6]:
A B
0 111 1
1 bbb 2
2 ccc 3
ここでaColumn
はビューであり、元のDataFrameからのコピーではないため、aColumn
を変更すると元のdfc
も変更されます。次に、行に最初にインデックスを付けるとします。
In [7]: zero_row = dfc.loc[0]
In [8]: zero_row['A'] = 222
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
In [9]: dfc
Out[9]:
A B
0 111 1
1 bbb 2
2 ccc 3
今回はzero_row
はコピーなので、元のdfc
は変更されません。
上記の2つの例から、元のDataFrameを変更するかどうかはあいまいです。あなたが以下のような何かを書くならば、これは特に危険です:
In [10]: dfc.loc[0]['A'] = 333
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
In [11]: dfc
Out[11]:
A B
0 111 1
1 bbb 2
2 ccc 3
今回はまったく機能しませんでした。ここではdfc
を変更したいと思いましたが、実際にはコピーである中間値dfc.loc[0]
を変更してすぐに破棄されます。 dfc.loc[0]
やdfc['A']
のような中間値がビューなのかコピーなのかを予測するのは非常に難しいので、元のDataFrameが更新されるかどうかは保証されません。そのため、連鎖インデックスは避けるべきであり、パンダはこのような連鎖インデックスの更新のためにSettingWithCopyWarning
を生成します。
今は.copy()
の使い方です。警告を排除するには、あなたの意図を明示的に表すためにコピーを作成してください。
In [12]: zero_row_copy = dfc.loc[0].copy()
In [13]: zero_row_copy['A'] = 444 # This time no warning
あなたがコピーを修正しているので、あなたはオリジナルのdfc
が決して変わらないことを知っています、そしてあなたはそれが変わることを期待していません。あなたの期待は振る舞いと一致し、そしてSettingWithCopyWarning
は消えます。
元のDataFrameを変更したい場合は、loc
を使用することをお勧めします。
In [14]: dfc.loc[0,'A'] = 555
In [15]: dfc
Out[15]:
A B
0 555 1
1 bbb 2
2 ccc 3
一般的に、元のデータフレームよりもコピーの方が作業が安全です。ただし、元のデータフレームは不要になり、操作バージョンを続行したい場合は除きます。通常は、元のデータフレームを操作したバージョンと比較するなどの目的で使用する必要があります。したがって、ほとんどの人はコピーを作成して最後にマージします。