【问题标题】:How is Pandas DataFrame handled across multiple custom functions when passed as argument?作为参数传递时,如何跨多个自定义函数处理 Pandas DataFrame?
【发布时间】:2020-10-13 18:05:08
【问题描述】:

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

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

修改 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 显示在末尾时:新的 Column 会出现吗?调用 mod_col 时对“现有列”所做的更改如何? 调用 add_Col 函数是创建了 df 的副本还是仅创建了一个指针?

将数据帧传递给函数时的最佳做法是什么,因为如果它们足够大,我确信创建副本会对性能和内存都有影响吗?

【问题讨论】:

    标签: python pandas function dataframe memory-management


    【解决方案1】:

    这取决于。 DataFrames are mutable objects,就像列表一样,它们可以在函数内修改,无需返回对象。

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

    如果你有一个函数结合了这两种类型的变化,你可以修改你的 DataFrame 直到你返回一个新对象。


    改变原来的

    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
    

    你应该怎么做?

    如果函数的目的是修改 DataFrame,例如在管道中,那么您应该创建一个函数,该函数接受 DataFrame 并返回 DataFrame。

    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,非常有见地的回答!如果我们谈论数百万条记录,创建副本可能会显着增加内存利用率,所以我猜最后你指出这完全取决于每个函数将如何处理 Dataframe,记录自定义函数将变得至关重要,因此下一个开发人员可以知道是否必须传递、替换或复制“df”,同时了解数据大小和要在整个项目架构上实现的逻辑。干杯伙伴!
    【解决方案2】:

    是的,该函数确实会更改数据框本身而不创建它的副本。您应该小心它,因为您最终可能会在不注意的情况下更改列。

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

    例如,如果您正在创建一个以某些数据帧作为输入的管道,您不想更改输入数据帧本身。而如果您只是在处理一个数据帧并且您正在将处理拆分为不同的函数,您可以编写您如何执行的函数

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-07
      • 2020-11-14
      • 2023-04-10
      • 1970-01-01
      • 2014-08-18
      • 2013-08-30
      相关资源
      最近更新 更多