neden pandalarda veri çerçevesinin bir kopyasını yapmalıyım


189

Bir üst veri çerçevesinden bir alt veri çerçevesi seçerken, bazı programcıların .copy()yöntemi kullanarak veri çerçevesinin bir kopyasını aldığını fark ettim . Örneğin,

X = my_dataframe[features_list].copy()

... sadece yerine

X = my_dataframe[features_list]

Neden veri çerçevesinin bir kopyasını yapıyorlar? Bir kopya çıkarmazsam ne olur?


6
Sanırım kaynak veri çerçevesini değiştirmemek için ekstra önlemler alıyorlar. Muhtemelen gereksizdir, ancak etkileşimli bir şey bir araya getirdiğinizde, üzülmekten daha güvenli.
Paul H

8
Bunun olumsuz bir soru vermek için aptalca bir soru olmadığını varsayıyorum.
Elizabeth Susan Joseph

Yanıtlar:


207

Bu Paul'un cevabını genişletiyor. Pandalar'da, bir DataFrame'in indekslenmesi ilk DataFrame'e bir referans döndürür. Böylece, alt kümenin değiştirilmesi ilk DataFrame'i değiştirecektir. Bu nedenle, ilk DataFrame'in değişmemesini sağlamak istiyorsanız, kopyayı kullanmak istersiniz. Aşağıdaki kodu göz önünde bulundurun:

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

Alacaksınız:

x
0 -1
1  2

Buna karşılık, aşağıdaki df değişmez:

df_sub_copy = df[0:1].copy()
df_sub_copy.x = -1

6
bu derin bir kopya mı?
bikashg

6
Evet. Varsayılan mod "derin" kopyadır! pandas.pydata.org/pandas-docs/stable/reference/api/…
Ambareesh

44

Çünkü bir kopya oluşturmazsanız, dataFrame'i farklı bir ada atasanız bile indeksler başka bir yerde işlenebilir.

Örneğin:

df2 = df
func1(df2)
func2(df)

func1, bundan kaçınmak için df2'yi değiştirerek df'yi değiştirebilir:

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

Bekle bekle bekle, neden böyle olduğunu açıklayabilir misin? Mantıklı değil.
NoName

2
çünkü ilk örnekte, 'df2 = df , both variables reference the same DataFrame instance. So any changes made to df` ya df2da aynı nesne örneğine yapılacaktır. Oysa df2 = df.copy()bir ikinci amacı örneği oluşturulur, birinci bir kopyası, ama şimdi dfve df2farklı nesne örneklerine ve herhangi bir değişiklik için bir referans, kendi DataFrame örneğine yapılacaktır.
Pedro

17

Kopya veya görünümün geri gönderilmesinin tür endekslemeye bağlı olduğunu belirtmek gerekir.

Panda belgeleri şöyle diyor:

Bir görünümün kopyaya karşı döndürülmesi

Verilerdeki bir görünümün ne zaman döndürüleceğine ilişkin kurallar tamamen NumPy'ye bağlıdır. İndeksleme işlemine bir etiket dizisi veya bir boole vektörü dahil olduğunda, sonuç bir kopya olacaktır. Tek etiket / skaler indeksleme ve dilimleme ile, örneğin df.ix [3: 6] veya df.ix [:, 'A'], bir görünüm döndürülür.



12

Birincil amaç zincirleme indekslemeden kaçınmak ve SettingWithCopyWarning.

Burada zincirleme endeksleme dfc['A'][0] = 111

Bir kopyaya karşı görünüm döndürülmesinde belirtilen zincirleme indekslemeden kaçınılmalıdır . İşte bu belgeden biraz değiştirilmiş bir örnek:

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

Burada, aColumnorijinal DataFrame'in bir kopyası değil, bir görünümdür, bu nedenle değiştirilmesi aColumnorijinalin dfcde değiştirilmesine neden olur . Ardından, önce satırı dizine eklersek:

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

Bu sefer zero_rowbir kopya, yani orijinaldfc değiştirilmez.

Yukarıdaki bu iki örnekten, orijinal DataFrame'i değiştirmek isteyip istemediğinizi belirsiz görüyoruz. Aşağıdaki gibi bir şey yazarsanız bu özellikle tehlikelidir:

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

Bu sefer hiç işe yaramadı. Burada değiştirmek istedik dfc, ancak aslında dfc.loc[0]bir kopya olan ve hemen atılan bir ara değeri değiştirdik . Sanki ara değer olup olmadığını tahmin etmek çok zordur dfc.loc[0]ya dfc['A']da orijinal DataFrame güncellenecektir olsun veya olmasın garanti değil bu yüzden, bir görünüm veya bir kopyasıdır. Bu yüzden zincirleme indekslemeden kaçınılmalı ve pandalarSettingWithCopyWarning bu tür zincirleme indeksleme güncellemesi için oluşturur.

Şimdi kullanımı .copy(). Uyarıyı ortadan kaldırmak için niyetinizi açıkça ifade etmek üzere bir kopyasını alın:

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

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

Bir kopyayı değiştirdiğiniz için, orijinalin dfcasla değişmeyeceğini ve değiştirilmesini beklemediğinizi biliyorsunuz. Beklentiniz davranışla eşleşir, ardındanSettingWithCopyWarning kaybolur.

Not: Orijinal DataFrame'i değiştirmek istiyorsanız, belge şunları kullanmanızı önerir 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

Genel olarak, artık orijinal belgeye ihtiyacınız olmayacağını bildiğiniz ve değiştirilen sürüme devam etmek istemeniz dışında, kopyalar üzerinde orijinal veri çerçevelerinden daha güvenli bir şekilde çalışmak daha güvenlidir. Normalde, orijinal veri çerçevesi için manipüle edilmiş sürümle vb. Karşılaştırmak için yine de biraz kullanmanız gerekir. Bu nedenle, çoğu kişi kopyalar üzerinde çalışır ve sonunda birleşir.


0

Aşağıdaki gibi veri çerçeveniz olduğu varsayılmıştır

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

Aynı df2olan başka bir tane oluşturmak istediğinizde 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

Ve sadece aşağıdaki gibi df2 değerini değiştirmek istiyorum

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

Aynı zamanda df1 de değişir

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

İki df aynı olduğundan object, bunu kullanarak kontrol edebiliriz.id

id(df1)
140367679979600
id(df2)
140367679979600

Yani aynı nesne olarak ve bir diğeri değiştikçe aynı değeri de geçecekler.


Eğer eklersek copyve şimdi df1ve df2farklı olarak kabul objectedilirsek, bunlardan birinde aynı değişikliği yaparsak diğeri değişmez.

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

Orijinal veri karesini alt kümeye yerleştirdiğinizde, kopyalamayı önlemek için kopyayı da eklemek güvenlidir. SettingWithCopyWarning

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.