親データフレームからサブデータフレームを選択すると、一部のプログラマーがこの.copy()
メソッドを使用してデータフレームのコピーを作成することに気付きました。例えば、
X = my_dataframe[features_list].copy()
...の代わりに
X = my_dataframe[features_list]
データフレームのコピーを作成するのはなぜですか?コピーを作成しないとどうなりますか?
親データフレームからサブデータフレームを選択すると、一部のプログラマーがこの.copy()
メソッドを使用してデータフレームのコピーを作成することに気付きました。例えば、
X = my_dataframe[features_list].copy()
...の代わりに
X = my_dataframe[features_list]
データフレームのコピーを作成するのはなぜですか?コピーを作成しないとどうなりますか?
回答:
これは、ポールの答えを拡張します。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)
, both variables reference the same DataFrame instance. So any changes made to
df`またはdf2
同じオブジェクトインスタンスに対して作成されるためです。一方でdf2 = df.copy()
第二オブジェクト・インスタンスが作成され、最初のもののコピーが、今df
とdf2
異なるオブジェクト・インスタンスと変更への参照は、それぞれのデータフレームのインスタンスについて説明します。
返されるコピーまたはビューは、インデックスの種類に依存することを言及する必要があります。
パンダのドキュメントは言う:
ビューとコピーを返す
データのビューが返されるタイミングに関するルールは、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
以下のようなデータフレームがあると仮定します
df1
A B C D
4 -1.0 -1.0 -1.0 -1.0
5 -1.0 -1.0 -1.0 -1.0
6 -1.0 -1.0 -1.0 -1.0
6 -1.0 -1.0 -1.0 -1.0
df2
と同じで別のものを作成したい場合はdf1
、copy
df2=df1
df2
A B C D
4 -1.0 -1.0 -1.0 -1.0
5 -1.0 -1.0 -1.0 -1.0
6 -1.0 -1.0 -1.0 -1.0
6 -1.0 -1.0 -1.0 -1.0
そして、以下のようにのみdf2値を変更したいと思います
df2.iloc[0,0]='changed'
df2
A B C D
4 changed -1.0 -1.0 -1.0
5 -1 -1.0 -1.0 -1.0
6 -1 -1.0 -1.0 -1.0
6 -1 -1.0 -1.0 -1.0
同時に、df1も変更されます
df1
A B C D
4 changed -1.0 -1.0 -1.0
5 -1 -1.0 -1.0 -1.0
6 -1 -1.0 -1.0 -1.0
6 -1 -1.0 -1.0 -1.0
2つのdfは同じなのでobject
、次のコマンドを使用して確認できます。id
id(df1)
140367679979600
id(df2)
140367679979600
したがって、それらは同じオブジェクトであり、1つが別のオブジェクトを変更すると、同じ値を渡します。
を追加しcopy
、現在df1
、df2
別のと見なされているobject
場合、それらの1つに同じ変更を行っても、他の変更は行われません。
df2=df1.copy()
id(df1)
140367679979600
id(df2)
140367674641232
df1.iloc[0,0]='changedback'
df2
A B C D
4 changed -1.0 -1.0 -1.0
5 -1 -1.0 -1.0 -1.0
6 -1 -1.0 -1.0 -1.0
6 -1 -1.0 -1.0 -1.0
元のデータフレームをサブセット化するときは、コピーを追加しても安全です。 SettingWithCopyWarning