パンダでデータフレームのコピーを作成する理由


188

親データフレームからサブデータフレームを選択すると、一部のプログラマーがこの.copy()メソッドを使用してデータフレームのコピーを作成することに気付きました。例えば、

X = my_dataframe[features_list].copy()

...の代わりに

X = my_dataframe[features_list]

データフレームのコピーを作成するのはなぜですか?コピーを作成しないとどうなりますか?


6
私の推測では、ソースデータフレームを変更しないように特別な注意を払っています。おそらく不要ですが、インタラクティブに何かを一緒に投げている場合は、残念より安全です。
Paul H

8
私はこれを否定的な質問をすることに対する愚かな質問ではないと思います。
エリザベススーザンジョセフ

回答:


207

これは、ポールの答えを拡張します。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

6
これは深いコピーですか?
bikashg

6
はい。デフォルトのモードは「ディープ」コピーです。pandas.pydata.org/pandas-docs/stable/reference/api/...
アンベアイーッシュ

44

コピーを作成しない場合、dataFrameを別の名前に割り当てても、インデックスは他の場所で操作できます。

例えば:

df2 = df
func1(df2)
func2(df)

func1はdf2を変更することでdfを変更できるため、それを回避できます。

df2 = df.copy()
func1(df2)
func2(df)

待って待って待って、なぜこれが起こるのか説明できますか?意味がありません。
NoName

2
最初の例では、 `df2 = df , both variables reference the same DataFrame instance. So any changes made to df`またはdf2同じオブジェクトインスタンスに対して作成されるためです。一方でdf2 = df.copy()第二オブジェクト・インスタンスが作成され、最初のもののコピーが、今dfdf2異なるオブジェクト・インスタンスと変更への参照は、それぞれのデータフレームのインスタンスについて説明します。
ペドロ

17

返されるコピーまたはビューは、インデックスの種類に依存することを言及する必要があります。

パンダのドキュメントは言う:

ビューとコピーを返す

データのビューが返されるタイミングに関するルールは、NumPyに完全に依存しています。ラベルの配列またはブールベクトルがインデックス付け操作に関与する場合は常に、結果はコピーになります。単一ラベル/スカラーのインデックス作成とスライス(例:df.ix [3:6]またはdf.ix [:, 'A'])では、ビューが返されます。



12

主な目的は、連鎖索引付けを回避し、 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

2

一般に、元のデータフレームではなくコピーで作業する方が安全です。ただし、元のデータフレームが不要になることがわかっていて、操作されたバージョンを続行する場合を除きます。通常、元のデータフレームを操作されたバージョンなどと比較するためにまだいくつかの用途があります。したがって、ほとんどの人は最後にコピーに取り組み、マージします。


0

以下のようなデータフレームがあると仮定します

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と同じで別のものを作成したい場合はdf1copy

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、現在df1df2別のと見なされている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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.