python Pandas DataFrame copy (deep = False) vs copy (deep = True) vs '='

Может ли кто-нибудь объяснить мне разницу между

df2 = df1

df2 = df1.copy()

df3 = df1.copy(deep=False)

Я пробовал все варианты и делал следующее:

df1 = pd.DataFrame([1,2,3,4,5])
df2 = df1
df3 = df1.copy()
df4 = df1.copy(deep=False)
df1 = pd.DataFrame([9,9,9])

и возвращается следующим образом:

df1: [9,9,9]
df2: [1,2,3,4,5]
df3: [1,2,3,4,5]
df4: [1,2,3,4,5]

Таким образом, я не вижу различий в выходе между .copy() и .copy(deep=False). Зачем?

Я бы ожидал, что один из вариантов "=", copy(), copy (deep = False) вернется [9,9,9]

Что я пропущу, пожалуйста?

Ответ 1

Если вы видите идентификаторы объектов различных DataFrames, которые вы создаете, вы можете четко видеть, что происходит.

Когда вы пишете df2 = df1, вы создаете переменную с именем df2 и привязываете ее к объекту с идентификатором 4541269200. Когда вы пишете df1 = pd.DataFrame([9,9,9]), вы создаете новый объект с идентификатором 4541271120 и привязываете его к переменной df1, но объект с id 4541269200 который ранее был привязан к df1 продолжает жить. Если бы не было никаких переменных, связанных с этим объектом, он получит мусор, собранный Python.

In[33]: import pandas as pd
In[34]: df1 = pd.DataFrame([1,2,3,4,5])
In[35]: id(df1)
Out[35]: 4541269200

In[36]: df2 = df1
In[37]: id(df2)
Out[37]: 4541269200  # Same id as df1

In[38]: df3 = df1.copy()
In[39]: id(df3)
Out[39]: 4541269584  # New object, new id.

In[40]: df4 = df1.copy(deep=False)
In[41]: id(df4)
Out[41]: 4541269072  # New object, new id.

In[42]: df1 = pd.DataFrame([9, 9, 9])
In[43]: id(df1)
Out[43]: 4541271120  # New object created and bound to name 'df1'.

In[44]: id(df2)
Out[44]: 4541269200  # Old object id not impacted.

Редактировать: Добавлено 30.07.2018

Глубокое копирование не работает в пандах, и разработчики считают, что переносить изменяемые объекты внутри DataFrame в качестве антипатерна. Рассмотрим следующее:

In[10]: arr1 = [1, 2, 3]
In[11]: arr2 = [1, 2, 3, 4]
In[12]: df1 = pd.DataFrame([[arr1], [arr2]], columns=['A'])
In[13]: df1.applymap(id)
Out[13]: 
            A
0  4515714832
1  4515734952

In[14]: df2 = df1.copy(deep=True)
In[15]: df2.applymap(id)
Out[15]: 
            A
0  4515714832
1  4515734952

In[16]: df2.loc[0, 'A'].append(55)
In[17]: df2
Out[17]: 
               A
0  [1, 2, 3, 55]
1   [1, 2, 3, 4]
In[18]: df1
Out[18]: 
               A
0  [1, 2, 3, 55]
1   [1, 2, 3, 4]

df2, если это была истинная глубокая копия, должны были иметь новые идентификаторы для списков, содержащихся в ней. В результате, когда вы изменяете список внутри df2, он также влияет на список внутри df1, потому что это те же объекты.

Ответ 2

Глубокая копия создает новый идентификатор каждого объекта, который он содержит, в то время как обычная копия только копирует элементы из родителя и создает новый идентификатор для переменной, к которой он скопирован.

Причина, по которой ни один из df2, df3 и df4 отображающий [9,9,9] является:

In[33]: import pandas as pd
In[34]: df1 = pd.DataFrame([1,2,3,4,5])
In[35]: id(df1)
Out[35]: 4541269200

In[36]: df2 = df1
In[37]: id(df2)
Out[37]: 4541269200  # Same id as df1

In[38]: df3 = df1.copy()
In[39]: id(df3)
Out[39]: 4541269584  # New object, new id.

In[40]: df4 = df1.copy(deep=False)
In[41]: id(df4)
Out[41]: 4541269072  # New object, new id.

In[42]: df1 = pd.DataFrame([9, 9, 9])
In[43]: id(df1)
Out[43]: 4541271120  # New object created and bound to name 'df1'.