mengapa saya harus membuat salinan bingkai data di panda

188

Ketika memilih sub dataframe dari dataframe induk, saya perhatikan bahwa beberapa programmer membuat salinan bingkai data menggunakan .copy()metode ini. Sebagai contoh,

X = my_dataframe[features_list].copy()

... bukannya adil

X = my_dataframe[features_list]

Mengapa mereka membuat salinan bingkai data? Apa yang akan terjadi jika saya tidak membuat salinan?

Elizabeth Susan Joseph
sumber
6
Dugaan saya adalah mereka mengambil tindakan pencegahan ekstra untuk tidak mengubah bingkai data sumber. Mungkin tidak perlu, tetapi ketika Anda melemparkan sesuatu secara interaktif, lebih baik aman daripada menyesal.
Paul H
8
Saya menganggap ini bukan pertanyaan bodoh untuk memberikan yang negatif.
Elizabeth Susan Joseph

Jawaban:

207

Ini memperluas jawaban Paulus. Di Pandas, pengindeksan DataFrame mengembalikan referensi ke DataFrame awal. Dengan demikian, mengubah subset akan mengubah DataFrame awal. Dengan demikian, Anda ingin menggunakan salinan jika Anda ingin memastikan bahwa DataFrame awal tidak boleh berubah. Pertimbangkan kode berikut:

df = DataFrame({'x': [1,2]})
df_sub = df[0:1]
df_sub.x = -1
print(df)

Anda akan mendapatkan:

x
0 -1
1  2

Sebaliknya, berikut ini tidak berubah:

df_sub_copy = df[0:1].copy()
df_sub_copy.x = -1
cgold
sumber
6
apakah ini salinan yang dalam?
bikashg
6
Iya. Mode standar adalah salin "dalam"! pandas.pydata.org/pandas-docs/stable/reference/api/…
Ambareesh
44

Karena jika Anda tidak membuat salinan maka indeks masih dapat dimanipulasi di tempat lain bahkan jika Anda menetapkan dataFrame ke nama yang berbeda.

Sebagai contoh:

df2 = df
func1(df2)
func2(df)

func1 dapat memodifikasi df dengan memodifikasi df2, jadi untuk menghindari itu:

df2 = df.copy()
func1(df2)
func2(df)
burung gereja
sumber
Tunggu tunggu tunggu, bisakah Anda menjelaskan MENGAPA ini terjadi? Tidak masuk akal.
NoName
2
itu karena pada contoh pertama, ` , both variables reference the same DataFrame instance. So any changes made to df2 = df df` atau df2akan dibuat ke instance objek yang sama. Sedangkan dalam df2 = df.copy()instance objek kedua dibuat, salinan yang pertama, tapi sekarang dfdan df2referensi ke instance objek yang berbeda dan perubahan apa pun akan dilakukan pada instance DataFrame masing-masing.
Pedro
17

Perlu disebutkan bahwa pengembalian salinan atau tampilan tergantung pada jenis pengindeksan.

Dokumentasi panda mengatakan:

Mengembalikan tampilan versus salinan

Aturan tentang kapan tampilan data dikembalikan sepenuhnya bergantung pada NumPy. Setiap kali array label atau vektor boolean terlibat dalam operasi pengindeksan, hasilnya akan menjadi salinan. Dengan label tunggal / pengindeksan skalar dan pengiris, mis. Df.ix [3: 6] atau df.ix [:, 'A'], sebuah tampilan akan dikembalikan.

Gusev Slava
sumber
12

Tujuan utama adalah untuk menghindari pengindeksan berantai dan menghilangkan SettingWithCopyWarning.

Di sini pengindeksan berantai adalah sesuatu seperti dfc['A'][0] = 111

Dokumen itu mengatakan pengindeksan berantai harus dihindari dalam Mengembalikan tampilan versus salinan . Berikut adalah contoh yang sedikit dimodifikasi dari dokumen itu:

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

Di sini aColumnadalah tampilan dan bukan salinan dari DataFrame asli, jadi memodifikasi aColumnakan menyebabkan yang asli dfcjuga dimodifikasi. Selanjutnya, jika kita mengindeks baris pertama:

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

Kali ini zero_rowadalah salinan, jadi yang asli dfctidak diubah.

Dari dua contoh di atas, kami melihat ambigu apakah Anda ingin mengubah DataFrame asli atau tidak. Ini sangat berbahaya jika Anda menulis sesuatu seperti berikut:

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

Kali ini tidak berhasil sama sekali. Di sini kami ingin mengubah dfc, tetapi kami benar-benar mengubah nilai menengah dfc.loc[0]yang merupakan salinan dan segera dibuang. Sangat sulit untuk memprediksi apakah nilai antara suka dfc.loc[0]atau tidak dfc['A']adalah tampilan atau salinan, jadi tidak dijamin apakah DataFrame asli akan diperbarui atau tidak. Itu sebabnya pengindeksan berantai harus dihindari, dan panda menghasilkan SettingWithCopyWarningpembaruan pengindeksan berantai seperti ini.

Sekarang adalah penggunaan .copy(). Untuk menghilangkan peringatan, buat salinan untuk mengekspresikan niat Anda secara eksplisit:

In [12]: zero_row_copy = dfc.loc[0].copy()

In [13]: zero_row_copy['A'] = 444 # This time no warning

Karena Anda memodifikasi salinan, Anda tahu yang asli dfctidak akan pernah berubah dan Anda tidak mengharapkannya untuk berubah. Harapan Anda cocok dengan perilaku, lalu SettingWithCopyWarningmenghilang.

Catatan, Jika Anda ingin memodifikasi DataFrame asli, dokumen menyarankan Anda menggunakan loc:

In [14]: dfc.loc[0,'A'] = 555

In [15]: dfc
Out[15]:
    A   B
0   555 1
1   bbb 2
2   ccc 3
Cosyn
sumber
2

Secara umum itu lebih aman untuk bekerja pada salinan daripada pada frame data asli, kecuali ketika Anda tahu bahwa Anda tidak akan membutuhkan yang asli lagi dan ingin melanjutkan dengan versi yang dimanipulasi. Biasanya, Anda masih memiliki beberapa penggunaan untuk bingkai data asli untuk dibandingkan dengan versi yang dimanipulasi, dll. Oleh karena itu, kebanyakan orang bekerja pada salinan dan bergabung pada akhirnya.

bojax
sumber
0

Diasumsikan Anda memiliki kerangka data seperti di bawah ini

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

Ketika Anda ingin membuat yang lain df2identik dengan df1, tanpacopy

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

Dan ingin memodifikasi nilai df2 hanya seperti di bawah ini

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

Pada saat yang sama df1 diubah juga

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

Karena dua df sama object, kita dapat memeriksanya dengan menggunakanid

id(df1)
140367679979600
id(df2)
140367679979600

Jadi mereka sebagai objek yang sama dan satu perubahan yang lain akan melewati nilai yang sama juga.


Jika kita menambahkan copy, dan sekarang df1dan df2dianggap berbeda object, jika kita melakukan perubahan yang sama ke salah satunya, yang lain tidak akan berubah.

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

Baik untuk disebutkan, ketika Anda mengatur ulang kerangka data asli, aman untuk menambahkan salinan juga untuk menghindari SettingWithCopyWarning

YOBEN_S
sumber