为什么要在pandas中复制数据框

llmtgqce  于 11个月前  发布在  其他
关注(0)|答案(8)|浏览(99)

当从父帧中选择子帧时,我注意到有些程序员使用.copy()方法复制 Dataframe 。例如,

X = my_dataframe[features_list].copy()

字符串
而不是

X = my_dataframe[features_list]


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

0s0u357o

0s0u357o1#

这个答案在较新版本的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

mnemlml8

mnemlml82#

因为如果你不做一个拷贝,那么索引仍然可以在其他地方被操纵,即使你把dataFrame分配给一个不同的名字。
举例来说:

df2 = df
func1(df2)
func2(df)

字符串
func1可以通过修改df2来修改df,这样可以避免:

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

0ejtzxu1

0ejtzxu13#

有必要提到的是,返回副本或视图取决于索引的类型。
Pandas文档说:
返回视图与副本
关于何时返回数据视图的规则完全取决于NumPy。每当索引操作中涉及标签数组或布尔向量时,结果将是副本。使用单个标签/标量索引和切片,例如df.ix[3:6]或df.ix[:,'A'],将返回视图。

vfh0ocws

vfh0ocws4#

主要目的是避免链式索引并消除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是否会被更新。这就是为什么应该避免链式索引,pandas为这种链式索引更新生成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

emeijp43

emeijp435#

假设您有如下数据框

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,添加副本也是安全的。

jm81lzqq

jm81lzqq6#

一般来说,使用副本比使用原始数据框更安全,除非您知道不再需要原始数据框,并希望继续使用操作版本。通常,您仍然可以使用原始数据框来与操作版本进行比较等。因此,大多数人都在最后使用副本和合并。

hpxqektj

hpxqektj7#

Pandas Deep copy保持初始DataFrame不变。
当你想规范化一个DataFrame并想保持初始的df不变时,这个特性特别有用。例如:

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

字符串
然后将数据标准化:

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


如果你想在第一个基础上创建一个新的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也会改变。

3wabscal

3wabscal8#

我在使用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

相关问题