【问题标题】:python Pandas DataFrame copy(deep=False) vs copy(deep=True) vs '='python Pandas DataFrame copy(deep=False) vs copy(deep=True) vs '='
【发布时间】:2018-03-01 20:03:47
【问题描述】:

谁能给我解释一下

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]

请问我错过了什么?

【问题讨论】:

    标签: python pandas dataframe deep-copy


    【解决方案1】:

    如果您看到您创建的各种 DataFrame 的对象 ID,您可以清楚地看到发生了什么。

    当您编写df2 = df1 时,您正在创建一个名为df2 的变量,并将它与一个ID 为4541269200 的对象绑定。当您编写df1 = pd.DataFrame([9,9,9]) 时,您正在创建一个ID 为4541271120new 对象并将其绑定到变量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's id not impacted.
    

    编辑:于 2018 年 7 月 30 日添加

    深度复制doesn't work in pandas 和开发人员考虑将可变对象放入 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,如果它是一个真正的深层副本,它应该为其中包含的列表具有新的 id。因此,当您修改 df2 中的列表时,它也会影响 df1 中的列表,因为它们是相同的对象。

    【讨论】:

    • 嗨!但是 df1.copy() 和 df1.copy(deep=False) 有什么区别?您能否改进示例以显示这种差异?
    • 这很有帮助,因为我现在看到df2 = df1df2 = df1.copy(deep=False) 之间的区别;一个人创建一个具有新 id 的新对象。但我还是不明白为什么这很重要?它们仍然只是对df1 的引用,对吧?他们仍然会以同样的方式收集垃圾,对吧?或者,除了所有元素实际上都指向同一个引用之外,浅拷贝是否真的创建了一个新的容器对象?如果是这样,那似乎是最糟糕的:消耗了大部分内存(数百万个重复的指针),但仍然没有真正的副本。
    • @karolszk:我添加了一个示例来说明深拷贝在 Pandas 中的工作方式并不如您所愿。
    • 如果有人在寻找一个很好的例子,我在这里做了一个尝试stackoverflow.com/questions/61578453/…
    【解决方案2】:

    深拷贝会为其包含的每个对象创建新的 id,而普通拷贝仅从父级复制元素并为要复制到的变量创建新的 id。

    df2df3df4 都没有显示[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'.
    

    【讨论】:

      【解决方案3】:

      您需要单独修改 df 的元素。试试下面的

      df1 = pd.DataFrame([1,2,3,4,5])
      df2 = df1
      df3 = df1.copy()
      df4 = df1.copy(deep=False)
      
      df1.iloc[0,0] = 6
      df2.iloc[1,0] = 7
      df4.iloc[2,0] = 8
      
      print(df1)
      print(df2)
      print(df3)
      print(df4)
      
      df1:        df2:        df3:        df4:
         0           0           0           0
      0  6        0  6        0  1        0  6
      1  7        1  7        1  2        1  7
      2  8        2  8        2  3        2  8
      3  4        3  4        3  4        3  4
      4  5        4  5        4  5        4  5
      

      【讨论】:

      • 已编辑以显示结果,这确实是查看正在发生的事情的最佳方式。在最初的问题中,df1 的重新分配并不能真正说明复制的真正问题,这个例子确实如此。 df3,使用 .copy() 是这 3 个选项的唯一深层副本。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-17
      • 2018-12-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多