Pandas函数修改DataFrame后外部无法访问修改结果
此前曾在Stack Overflow发布过关于扁平化JSON数据的问题及对应代码,事后回看发现当时的问题描述过于晦涩复杂,因此简化问题场景后重新提问。
编写的处理函数将Pandas DataFrame作为输入参数传入并在函数内对其做修改,但函数执行完成后,无法在外部访问到修改后的DataFrame,获取到的始终是原始版本的数据。
- 导入numpy和pandas库,创建测试用DataFrame:
import numpy as np import pandas as pd df = pd.DataFrame(np.arange(12).reshape(3, 4), columns=['A', 'B', 'C', 'D'])
- 编写用于修改DataFrame的删除列函数:
def drop_col(df): print(f"original shape: {df.shape}") df = df.drop(['B'], axis=1) print(f"final shape: {df.shape}") return df
函数内的打印输出显示,DataFrame原始形状为(3,4),执行删除列操作后形状为(3,3),说明列B已按预期被成功删除。但函数运行结束后,在外部通过df.head()等方式访问DataFrame时,看到的仍然是3行4列的原始DataFrame,修改未生效。
Pandas中绝大多数DataFrame操作默认不会原地修改原始对象,而是返回一个执行完对应操作的新对象。
在函数内部写df = df.drop(['B'], axis=1)时,只是将函数作用域内的局部变量df重新指向了删完列的新DataFrame,外部全局作用域里的df仍然指向最开始创建的原始DataFrame,自然看不到修改效果。
方法1:接收函数返回值重新赋值(推荐)
这是最符合Pandas设计逻辑的写法,能避免原地操作带来的隐式副作用、SettingWithCopyWarning等问题,调用函数时把返回值重新赋值给外部变量即可:
# 调用函数时用原变量接收返回值 df = drop_col(df) # 此时查看df,就是已经删除B列、形状为(3,3)的正确结果 print(df.shape)
方法2:开启原地修改参数(不推荐)
如果不想做返回值赋值,可以在调用操作时传入inplace=True参数,让操作直接修改原始传入的DataFrame,这种写法不需要额外做变量赋值:
def drop_col(df): print(f"original shape: {df.shape}") # 加上inplace=True参数,直接修改原始对象 df.drop(['B'], axis=1, inplace=True) print(f"final shape: {df.shape}") # 直接调用函数即可,不需要赋值 drop_col(df) # 此时外部的df已经被修改 print(df.shape)
注意:Pandas官方并不推荐频繁使用
inplace=True,这类写法在链式调用场景下很容易出现难以排查的问题,且部分操作的inplace参数已经在后续版本的废弃计划中,日常使用优先选择返回值赋值的方案。
内容的提问来源于stack exchange,提问作者DavidH

