Python 当作为参数传递时,如何跨多个自定义函数处理数据帧?

Python 当作为参数传递时,如何跨多个自定义函数处理数据帧?,python,pandas,function,dataframe,memory-management,Python,Pandas,Function,Dataframe,Memory Management,我们有一个项目,其中有多个*.py脚本,其中的函数接收并返回数据帧变量作为参数 但这让我想知道:当dataframe变量作为参数传递或作为这些函数返回的变量传递时,它们在内存中的行为是什么 修改df变量是否也会改变父/主/全局变量 考虑以下示例: import pandas as pd def add_Col(df): df["New Column"] = 10 * 3 def mod_Col(df): df["Existing Column&qu

我们有一个项目,其中有多个*.py脚本,其中的函数接收并返回数据帧变量作为参数

但这让我想知道:当dataframe变量作为参数传递或作为这些函数返回的变量传递时,它们在内存中的行为是什么

修改df变量是否也会改变父/主/全局变量

考虑以下示例:

import pandas as pd

def add_Col(df): 
   df["New Column"] = 10 * 3

def mod_Col(df):
   df["Existing Column"] = df["Existing Column"] ** 2

data = [0,1,2,3]
df = pd.DataFrame(data,columns=["Existing Column"])

add_Col(df)
mod_col(df)

df

当df在末尾显示时:是否会显示新列?调用mod_col时对“Existing Column”所做的更改如何? 调用add_Col函数是创建了df的副本还是只创建了指针


将数据帧传递到函数中的最佳实践是什么?因为如果数据帧足够大,我确信创建副本将同时影响性能和内存,对吗?

是的,函数确实会更改数据帧本身,而不创建数据帧的副本。您应该小心,因为您可能会在不知不觉中更改列

在我看来,最佳实践取决于用例,使用.copy()确实会对您的内存产生影响

例如,如果您正在创建以某个数据帧作为输入的管道,则不希望更改输入数据帧本身。如果您只是在处理一个数据帧,并且在不同的函数中分割处理,那么您可以编写函数,具体操作方式取决于具体情况,因此,与列表一样,可以在函数中修改它们,而无需返回对象

另一方面,绝大多数pandas操作将返回一个新对象,因此修改不会改变底层数据帧。例如,下面您可以看到,使用
.loc
更改值将修改原始值,但如果要将整个数据帧(返回新对象)相乘,原始值将保持不变

如果有一个函数同时具有这两种类型的更改,则可以修改数据帧,直到返回新对象为止


更改原始文件

df = pd.DataFrame([1,2,4])

def mutate_data(df):
    df.loc[1,0] = 7

mutate_data(df)
print(df)
#   0
#0  1
#1  7
#2  4
df = pd.DataFrame([1,2,4])

def mutate_data(df):
    df = df*2

mutate_data(df)
print(df)
#   0
#0  1
#1  2
#2  4

不会更改原始版本

df = pd.DataFrame([1,2,4])

def mutate_data(df):
    df.loc[1,0] = 7

mutate_data(df)
print(df)
#   0
#0  1
#1  7
#2  4
df = pd.DataFrame([1,2,4])

def mutate_data(df):
    df = df*2

mutate_data(df)
print(df)
#   0
#0  1
#1  2
#2  4

你该怎么办?

如果函数的目的是修改数据帧(如在管道中),则应创建一个函数,该函数接受数据帧并返回数据帧

def add_column(df):
    df['new_column'] = 7
    return df


df = add_column(df)
#┃              ┃
#┗ on lhs & rhs ┛
在这种情况下,函数是否更改或创建新对象并不重要,因为我们打算修改原始对象

但是,如果计划写入新对象,则可能会产生意外后果

df1 = add_column(df)
# |              |
# New Obj        Function still modifies this though!
一种不需要了解底层源代码的安全替代方法是强制您的函数在顶部进行复制。因此,在该范围内,对
df
的更改不会影响功能之外的原始
df

def add_column_maintain_original(df):
    df = df.copy()

    df['new_column'] = 7
    return df
另一种可能是将
copy
传递给函数:

df1 = add_column(df.copy())

谢谢@ALollz,非常有洞察力的回答!如果我们谈论数以百万计的记录,那么创建一个副本可以显著提高内存利用率,因此我想在最后,正如您所指出的,这一切都取决于每个函数将如何处理数据帧,记录自定义函数将变得至关重要,这样下一个开发人员就可以知道是否必须传递“df”,在意识到要在整个项目架构上实现的数据大小和逻辑的同时进行替换或复制。干杯,伙计!