मुझे पंडों में डेटा फ्रेम की एक प्रति क्यों बनानी चाहिए


189

पैरेंट डेटाफ़्रेम से उप डेटाफ़्रेम का चयन करते समय, मैंने देखा कि कुछ प्रोग्रामर .copy()विधि का उपयोग करके डेटा फ़्रेम की प्रतिलिपि बनाते हैं । उदाहरण के लिए,

X = my_dataframe[features_list].copy()

... बस के बजाय

X = my_dataframe[features_list]

वे डेटा फ़्रेम की प्रतिलिपि क्यों बना रहे हैं? यदि मैं प्रतिलिपि नहीं बनाता तो क्या होगा?


6
मेरा अनुमान है कि वे स्रोत डेटा फ्रेम को संशोधित नहीं करने के लिए अतिरिक्त सावधानी बरत रहे हैं। संभवतः अनावश्यक है, लेकिन जब आप अंतःक्रियात्मक रूप से कुछ फेंक रहे हैं, तो क्षमा से बेहतर सुरक्षित है।
पॉल एच

8
मैं इसे एक नकारात्मक प्रश्न देने के लिए एक मूर्खतापूर्ण प्रश्न नहीं मानता हूं।
एलिजाबेथ सुसान जोसेफ

जवाबों:


207

यह पॉल के जवाब पर फैलता है। पंडों में, एक DataFrame को अनुक्रमित करना प्रारंभिक DataFrame का संदर्भ देता है। इस प्रकार, सबसेट बदलने से प्रारंभिक डेटाफ़्रेम बदल जाएगा। इस प्रकार, यदि आप यह सुनिश्चित करना चाहते हैं कि प्रारंभिक डेटाफ़्रेम को नहीं बदलना चाहिए तो आप कॉपी का उपयोग करना चाहते हैं। निम्नलिखित कोड पर विचार करें:

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

आपको मिलेगा:

x
0 -1
1  2

इसके विपरीत, निम्नलिखित पत्ते अपरिवर्तित हैं:

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

6
क्या यह एक गहरी नकल है?
bikashg

6
हाँ। डिफ़ॉल्ट मोड "गहरी" प्रतिलिपि है! pandas.pydata.org/pandas-docs/stable/reference/api/…
अंबरीश

44

क्योंकि यदि आप प्रतिलिपि नहीं बनाते हैं, तब भी सूचक कहीं और हेरफेर कर सकते हैं, भले ही आप डेटाफ़्रेम को किसी अन्य नाम पर असाइन करें।

उदाहरण के लिए:

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()एक दूसरी वस्तु उदाहरण में बनाई जाती है, पहले एक की एक प्रति, लेकिन अब dfऔर df2विभिन्न वस्तु उदाहरणों के संदर्भ में और उनके संबंधित डेटाफ्रेम उदाहरण में कोई भी परिवर्तन किया जाएगा।
पेड्रो

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को संशोधित नहीं किया गया है।

उपरोक्त इन दो उदाहरणों से, हम देखते हैं कि यह अस्पष्ट है कि आप मूल 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']कोई व्यू है या कॉपी है, इसलिए इसकी गारंटी नहीं है कि ओरिजिनल डेटाफ़्रेम को अपडेट किया जाएगा या नहीं। इसलिए जंजीर अनुक्रमण से बचा जाना चाहिए, और 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जो 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

चूंकि दो df समान हैं object, इसलिए हम इसका उपयोग करके जाँच कर सकते हैंid

id(df1)
140367679979600
id(df2)
140367679979600

तो वे एक ही वस्तु के रूप में और एक दूसरे को बदलने के साथ ही एक ही मूल्य पारित करेंगे।


यदि हम दूसरे को जोड़ते हैं copy, और अब df1और df2अलग माने जाते हैं object, यदि हम उनमें से एक में भी ऐसा ही बदलाव करेंगे तो दूसरा नहीं बदलेगा।

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.