pandas的dataFrame传入函数后发生了变化以及拷贝问题

在Python中,当pandas DataFrame被传入函数并进行修改时,全局变量可能会受到影响。文章讨论了如何避免意外修改原DataFrame,推荐在需要时使用.copy()创建副本。特别地,对双重切片赋值会导致警告。实验表明,只进行切片操作不会改变原DataFrame,而数值修改、添加新列等会改变原数据。使用inplace参数进行删除操作能有效防止意外更改。

今天发现,全局定义的pandas的DataFrame被传入到函数中的时候,如果函数改变了slice,比如df.loc[…,…] = x,全局变量df也会跟着变。险些造成错误计算,幸好发现及时。这里探讨一下这个问题的规避方法。

tl;dr:
使用的dataframe很大的情况下,复制列,在复制的列上进行想要的操作,如果很小,使用df.copy()。
更新,复制列有时会有bug,会弹出view vs copy警告,原因未知,建议使用df.copy()
更新,原因已查明。
当在函数中对df进行切片,即使使用了loc:

new_df = df.loc[cond]
new_df.loc[0,'col_name'] = 1

也会弹出警告,原因是new_df本质上还是df的切片,
包括像是(df.drop_duplicates这些方法都是切片)
new_df.loc[0,‘col_name’] = 1相当于 df.loc[cond].loc[0,‘col_name’] = 1
一旦出现给双重切片赋值,就会弹出警告,规避方法:

new_df = df.loc[cond].copy()
new_df.loc[0,'col_name'] = 1

takeaway:避免给双重切片赋值

首先是实验环节:定义dataframe

import pandas as pd

df = pd.DataFrame({'a':['z','x','c'],'b':[4,5,6]})
  1. 改变整个df,不改变原df:
def change_df(df):
    df = df * 2
print('change_df')
change_df(df)
print(df)

输出:
change_df
   a  b
0  z  4
1  x  5
2  c  6
  1. 改变一列,原df发生变化:
def change_b(df):
    df.loc[:,'b'] = df.b*2

print('change_b')
change_b(df)
print(df)
输出:
change_b
   a   b
0  z   8
1  x  10
2  c  12
  1. 在func里面复制一个新的col,对新col赋值,不改变被复制的col,但是df会出现新加入的col:
def change_nCol(df):
    df.loc[:,'c'] = df.b
    df.loc[:,'c'] = df.c*2

print('\nchange_nCol')
change_nCol(df)
print(df)

输出:
change_nCol
   a   b   c
0  z   8  16
1  x  10  20
2  c  12  24
  1. 使用copy功能,原df不变:
def change_copy(df):
    df_copy = df.copy(deep = True) #默认为True
    df_copy.loc[:,'a'] = df_copy.a*2

print('\nchange_copy')
change_copy(df)
print(df)

输出:
change_copy
   a   b   c
0  z   8  16
1  x  10  20
2  c  12  24
  1. 但也有例外情况,如官网上讲的:
    note that when copying an object containing Python objects, a deep copy will copy the data, but will not do so recursively. Updating a nested data object will be reflected in the deep copy.
>>> s = pd.Series([[1, 2], [3, 4]])
>>> deep = s.copy()
>>> s[0][0] = 10
>>> s
0    [10, 2]
1     [3, 4]
dtype: object
>>> deep
0    [10, 2]
1     [3, 4]
dtype: object
  1. 讲一下我的看法
    传入函数之后,如果是对dataframe只是进行切片操作,那么原来的dataframe是不会变的。
    如果涉及到改变数值,包括添加新列新行,以及改变原数值,那么原df会跟着变。有时会需要新加一列方便计算,结尾删除该列一定要inplace,不然普通的drop也其实只是切片操作,不会删除新加列。之前一直不知道inplace的用处,这里就能看出inplace的作用了。
def test(data):
    data['test'] = 0
    data = data.drop(columns=['test'])
    print('test done df里面多一个test列,并且没有被删掉')
    
def test2(data):
    data['test'] = 0
    data.drop(columns=['test'], inplace=True)
    print('test done df里面多出来的test列被删掉了')

如果你在切片上改变数值,则会弹出set value on a copy of view警告,也是终于看懂这句话的意思,new是data的一个切片的copy。具体原始df会不会改,读者可以自行实验。

def test_change(data):
	new = data.iloc[:,0:2]
	new['test'] = 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值