Python 编辑数据帧';就地';在函数中,还是返回已编辑的数据帧?

Python 编辑数据帧';就地';在函数中,还是返回已编辑的数据帧?,python,pandas,Python,Pandas,我目前正在开发一个更新数据帧的函数 我有两种方法可以做到这一点 示例1:就地编辑 创建数据帧 mydf = pd.DataFrame({'name':['jim','john','mary','michael'], 'age':[12,46,44,32]}) name age 0 jim 12 1 john 46 2 mary 44 3 michael 32 我们将进行以下编辑: 如果名称以j开

我目前正在开发一个更新数据帧的函数

我有两种方法可以做到这一点

示例1:就地编辑

创建数据帧

mydf = pd.DataFrame({'name':['jim','john','mary','michael'],
                    'age':[12,46,44,32]})

      name  age
0      jim   12
1     john   46
2     mary   44
3  michael   32
我们将进行以下编辑:

  • 如果名称以
    j
    开头,请在名称中添加
    'smith'

  • 如果年龄大于40岁,则将其乘以2

  • 很好。我没有返回函数中的任何内容,数据帧已编辑:

    modify(mydf)
    
    print(mydf)
    
             name  age
    0   jim smith   12
    1  john smith   92
    2        mary   88
    3     michael   32
    
    示例2我也可以通过返回数据帧来实现,如下所示。我的问题是:有什么区别?一种方法比另一种更可取吗

    def modify(df):
    
        for i in range(len(df)):
    
            if df.loc[i,'age'] > 40:
    
                df.loc[i,'age'] = df.loc[i,'age']*2
    
            name = df.loc[i,'name']
    
            if name[0]=='j':
    
                name = name+' '+'smith'
    
            df.loc[i,'name'] = name
    
        return df
    
    运行该函数:

    mydf = modify(mydf)
    
    print(mydf)
    
             name  age
    0   jim smith   12
    1  john smith   92
    2        mary   88
    3     michael   32
    
    两者都很好。是就地编辑还是返回数据帧更好


    注意:我无法进行矢量化,因为我正在处理的实际函数中使用api。这只是一个玩具的例子

    我们通常做
    np.where
    ,这将加快整个过程

    df['name']=np.where(df.name.str[0]=='j',df.name+'smith',df.name)
    df['age']=np.where(df.age>40,df.age*2,df.age)
    df
    Out[90]: 
            name  age
    0   jimsmith   12
    1  johnsmith   92
    2       mary   88
    3    michael   32
    

    我总是选择返回数据帧。如果您计划将输出分配给另一个变量(
    df1=my_func(df)
    ),请使用
    df.copy()
    调用该函数,或者确保将
    .copy()
    放在函数顶部,以避免意外修改输入

    DataFrames
    是可变的,因此与列表一样,可以在函数中修改它们而不返回它们。但是,当您使用返回新对象的
    pandas
    函数而不是修改原始对象时,这可能会导致很多混乱

    mydf = pd.DataFrame({'name': ['jim', 'jim'],
                         'age': [12, 46]})
    
    def modify(df):
        df.loc[df.name.eq('jim'), 'age'] = 1000
    
    print(mydf)
    #  name  age
    #0  jim   12
    #1  jim   46
    
    modify(mydf)
    print(mydf)
    #  name   age
    #0  jim  1000
    #1  jim  1000
    

    好吧,太好了,情况变了。但如果我们继续:

    def modify2(df):
        df.drop_duplicates(inplace=True)
        df['age'] = df['age'] + 1
    
        df = pd.concat([df]*4)
        df['age'] = df['age'] + 17
    
    modify2(mydf)
    print(mydf)
    #  name   age
    #0  jim  1001
    

    所以这不太好。基本上,函数只成功地修改了
    df
    ,直到函数的某些部分返回了一个新对象,而不是对原始对象的引用。这是一个非常有问题的问题,需要每个操作都在原地运行,否则就会失败

    谢谢,但我正在处理的函数要复杂得多,根据条件等,会有对api的调用<代码>np。其中对于api来说太快。我只是想知道上面哪种方法更有效preferred@SCool我将推荐第二个,另外,您可以将.loc改为.at以加快它的速度谢谢@WeNYoBen我不知道
    .at
    。很好的解释,谢谢。如果我确实想修改原始数据帧而不是
    .copy()
    它该怎么办?例如,在我的函数(不是这里的函数)中,有一个api调用来验证电子邮件地址。如果这是一封有效的电子邮件,我将添加一个额外的列
    df['email\u verification']='valid'
    。因此,我将包含客户数据和电子邮件的数据框发送到函数中,并附加新数据。我是否仍应使用
    .copy()
    ?如果数据帧有一百万行呢?我将创建一个庞大的额外数据副本。如果结果是修改原始数据(
    df=my_func(df)
    ),那么就不需要添加
    .copy()
    ,因为其目的是修改原始数据,所以在返回之前是否意外修改它并不重要。尽管您偶尔会收到一些带有copy的
    设置警告。但是是的,我会在函数末尾添加一个
    返回df
    ,然后
    df=my_func(df)
    def modify2(df):
        df.drop_duplicates(inplace=True)
        df['age'] = df['age'] + 1
    
        df = pd.concat([df]*4)
        df['age'] = df['age'] + 17
    
    modify2(mydf)
    print(mydf)
    #  name   age
    #0  jim  1001