为什么我应该在 Pandas 中复制一个数据框

2025-01-03 08:41:00
admin
原创
87
摘要:问题描述:当从父数据框中选择子数据框时,我注意到一些程序员使用该方法复制数据框.copy()。例如,X = my_dataframe[features_list].copy() ...而不仅仅是X = my_dataframe[features_list] 他们为什么要复制数据框?如果我不复制会发生什么?解决...

问题描述:

当从父数据框中选择子数据框时,我注意到一些程序员使用该方法复制数据框.copy()。例如,

X = my_dataframe[features_list].copy()

...而不仅仅是

X = my_dataframe[features_list]

他们为什么要复制数据框?如果我不复制会发生什么?


解决方案 1:

此答案已在较新版本的 pandas 中弃用。请参阅文档


这扩展了 Paul 的回答。在 Pandas 中,索引 DataFrame 会返回对初始 DataFrame 的引用。因此,更改子集将更改初始 DataFrame。因此,如果您想确保初始 DataFrame 不会更改,则需要使用副本。请考虑以下代码:

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

您将获得:

   x
0 -1
1  2

相反,下面的代码保持 df 不变:

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

解决方案 2:

因为如果您不复制,那么即使您将 dataFrame 分配给不同的名称,索引仍然可以在其他地方被操作。

例如:

df2 = df
func1(df2)
func2(df)

func1 可以通过修改 df2 来修改 df,因此为了避免这种情况:

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

解决方案 3:

需要提到的是,返回的副本或视图取决于索引的类型。

熊猫文档说:

返回视图与副本

关于何时返回数据视图的规则完全取决于 NumPy。每当标签数组或布尔向量参与索引操作时,结果将是副本。使用单标签/标量索引和切片,例如 df.ix[3:6] 或 df.ix[:, 'A'],将返回视图。

解决方案 4:

主要目的是避免链式索引并消除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']是视图还是副本,因此无法保证原始 DataFrame 是否会被更新。这就是为什么应该避免链式索引,而 pandasSettingWithCopyWarning为这种链式索引更新生成了。

现在使用.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

解决方案 5:

假设您有如下数据框

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,现在df1df2被视为不同的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

解决方案 6:

一般来说,处理副本比处理原始数据框更安全,除非你知道不再需要原始数据框,而想要继续处理处理后的版本。通常,你仍然会用到原始数据框来与处理后的版本进行比较等。因此,大多数人处理副本并在最后合并。

解决方案 7:

Pandas 深度复制保持初始 DataFrame 不变。

当你想要规范化 DataFrame 并希望保持初始 df 不变时,此功能特别有用。例如:

df = pd.DataFrame(np.arange(20).reshape(2,10))

然后你规范化数据:

# Using Sklearn MinMaxSacaler method
scaler = preprocessing.MinMaxScaler()

并且您根据第一个 df 创建新的 df 并希望第一个 df 保持不变,则必须使用 .copy() 方法

new_df = pd.DataFrame(df).copy() # Deep Copy
for i in range(10):
    pd_features[i] = scaler.fit_transform(unnormal_pd_features[i].values.reshape(-1,1))

否则你原来的 df 也会改变。

解决方案 8:

我在使用 copy() 时非常粗心,直到我使用下面那行代码而不使用 copy(),df_genel3 中的更改影响了 df_genel

df_genel3 = df_genel
df_genel3.loc[(df_genel3['Hareket']=='İmha') , 'Hareket_Tutar'] = tutar 

copy() 解决了这个问题

df_genel3 = df_genel.copy()
df_genel3.loc[(df_genel3['Hareket']=='İmha') , 'Hareket_Tutar'] = tutar
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用