在Function中附加DataFrame

时间:2018-06-15 01:55:18

标签: python pandas function dataframe

我有一个函数test,它接受​​一个DataFrame并向其追加数据。我希望更改放入函数的全局变量。我有以下脚本:

import pandas as pd
global dff

def test(df):
    df = df.append({'asdf':1, 'sdf':2}, ignore_index=True)
    return(df)

dff = pd.DataFrame()
test(dff)

在此之后,dff仍为空;它没有被编辑。但是,如果你这样做:

import pandas as pd

def test(df):
    df['asdf'] = [1,2,3]
    return(df)

dff = pd.DataFrame()
test(dff)

dff会在[1,2,3]列下有'asfd'。请注意,我甚至不必将变量声明为global

为什么会这样?

我实际上想知道,因为第二个我认为我理解变量工作空间,我被证明是错误的,而且我厌倦了不断遇到这个BS *

我知道问题的解决方案是:

import pandas as pd

def test(df):
    df = df.append({'asdf':1, 'sdf':2}, ignore_index=True)
    return(df)

dff = pd.DataFrame()
dff = test(dff)

但我真的只想弄清楚为什么初始方法不起作用,特别是考虑到我已经展示的第二个脚本。

*显然它不是完整的BS,但经过3年的休闲编程后我无法理解它

2 个答案:

答案 0 :(得分:2)

更新

我在PyCon 2015上发现了一个非常好的演讲,解释了我试图在下面解释的内容,但是使用的图表使其更加清晰。我将在下面留下解释来解释原始的3个脚本是如何工作的,但我建议你去观看视频:

Ned Batchelder - Facts and Myths about Python names and values - PyCon 2015

所以,我想我已经弄清楚上面两个脚本中发生了什么。我会尝试分解它。如果需要,请随时纠正我。

几条规则:

  1. 变量是指向实际保存数据的基础对象的链接/指针的名称。例如,街道地址。街道地址不是房子;它只是指向一所房子。所以地址(101 Streetway Rd。)是指针。在GPS中,您可能将其标记为“主页”。 “Home”这个词本身就是变量。

  2. 函数适用于对象,而不是变量或指针。将变量传递给函数时,实际上是传递对象,而不是变量或指针。继续这个房子的例子,如果你想在房子里添加一个套牌,你希望装饰承包商在房子上工作,而不是元物理地址。

  3. 函数中的return命令返回指向对象的指针。所以这就是房子的地址,而不是房子或你称之为房子的名字。

  4. =是一个函数,意思是“指向此对象”。 =前面的变量是输出,右边的变量是输入。这将是命名房屋的行为。因此Home = 101 Streetway Rd.使变量Home指向101 Streetway Rd上的房子。假设你搬进了邻居家,这是102 Streetway Rd。这可以通过Home = Neighbor's House来完成。现在,Home现在是指针102 Streetway Rd。

  5. 的名称

    这里我将使用--->来表示“指向”

    在我们开始编写脚本之前,让我们从我们想要的开始。我们希望变量指向的对象objdff

    脚本1:

    (没有global dff因为没有做任何相关的事情)

      
    import pandas as pd
    
    def test(df):
        df = df.append({'asdf':1, 'sdf':2}, ignore_index=True)
        return(df)
    
    dff = pd.DataFrame()
    test(dff)
    

    让我们来看看这个功能。在我们到达之前没有任何有趣的事情发生:

    dff = pd.DataFrame()

    在这里,我们将变量dff分配给由pd.DataFrame创建的对象,这是一个空数据帧。我们将此对象称为objdff。所以在这一行的最后,我们有dff ---> objdff

    下一行:test(dff)

    函数处理对象,因此我们说我们将在test指向的对象dff上运行函数objdff。这将我们带到了函数本身。

    def test(df):

    在这里,我们实际上是一个=函数。传递给测试函数objdff的对象由函数变量df指向。现在df --->objdff dff---> objdff

    转到下一行:df = df.append(...)

    让我们从df.append(...)开始吧。 .append(...)会传递到objdff。这使对象objdff运行一个名为'append'的函数。正如@Jai所指出的,.append(...)方法使用return命令输出一个全新的DataFrame,该DataFrame附加了数据。我们将调用新对象objdff_apnd

    现在我们可以转到df = ...部分了。我们现在拥有的基本上是df = objdff_apnd。这很简单。变量df现在指向对象objdff_apnd

    在这一行的最后,我们有df ---> objdff_apnddff ---> objdff。这就是问题所在。我们想要的对象(objdff_apnd)没有被dff指向。

    最后,变量dff仍然指向objdff,而不是objdff_apnd。这将我们带到脚本3(见下文)。

    脚本2:

    import pandas as pd
    
    def test(df):
        df['asdf'] = [1,2,3]
        return(df)
    
    dff = pd.DataFrame()
    test(dff)
    

    就像脚本1 dff ---> objdff一样。在test(dff)期间,函数变量df ---> objdff。这是事情不同的地方。

    再次将操作(?)df['asdf'] = [1,2,3]发送到基础对象objdff。上一次,这导致了一个新对象。但是,这次['asdf']操作会直接编辑对象objdff。因此,对象objdff中包含额外的“asdf”列。

    因此,最后我们有df ---> objdffdff ---> objdff。因此,它们指向同一个对象,这意味着变量dff指向已编辑的对象。

    一旦我们突破该函数,变量dff仍然指向objdff,其中包含新数据。这给了我们想要的结果。

    脚本3:

    import pandas as pd
    
    def test(df):
        df = df.append({'asdf':1, 'sdf':2}, ignore_index=True)
        return(df)
    
    dff = pd.DataFrame()
    dff = test(dff)
    

    此脚本与脚本1完全相同,但dff = test(dff)除外。我们将在一秒钟内完成。

    从脚本1的结尾开始,我们在函数test(dff)结束时向右移动,我们有dff ---> objdffdf ---> objdff_apnd

    函数test具有return命令,因此返回对象objdff_apnd。这会将行dff = test(dff)转换为dff = objdff_apnd

    因此,最后,我们有dff ---> objdff_apnd,这正是我们想要的结果。

答案 1 :(得分:1)

  • 我认为pandas数据框,列表和字典所有这些数据类型都是通过引用函数传递的,因此,这种行为。
  • 在第一个附加脚本的脚本中,append会返回一个新对象,因此它不会填充原始数据帧。
  • 在第二个脚本中,您将特定的数据框列分配给原始数据框对象,因此它会使用列填充原始数据框对象,因为您正在修改原始对象
  • 你可以查看这个答案:python pandas dataframe, is it pass-by-value or pass-by-reference
  • 检查此列表示例:

    def test1(a):
        a.append(1)
    
    def test2(a):
        a = [1, 2, 3]
    
    def test3(a):
        a[0] = 10
    
    aa = list()
    test1(aa)
    print(aa)
    
    aa = list()
    test2(aa)
    print(aa)
    
    aa = list([1])
    test3(aa)
    print(aa)
    
  • 输出:

    [1]
    []
    [10]
    
  • 将上面的列表示例与pandas dataframe示例
  • 相关联
  • 如果您检查Dataframe的append功能:
    DataFrame.append(other, ignore_index=False, verify_integrity=False, sort=None)[source] Append rows of other to the end of this frame, returning a new object. Columns not in this frame are added as new columns.
  • 正如您在说明中所见append返回新对象
  • 您使用global关键字的方式是错误的...我认为即使您在第一个脚本中没有global,它仍然没有任何区别......我没有关于global关键字的详细信息,所以我不会提及它的任何内容..但我知道如何使用关键字,这绝对不是正确的使用方式