代码之家  ›  专栏  ›  技术社区  ›  James Wright user3667089

在函数内追加数据帧

  •  1
  • James Wright user3667089  · 技术社区  · 7 年前

    我有个功能 test 它接受一个数据帧并向其追加数据。我想改变函数中的全局变量。我有下面的剧本:

    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)
    

    敌我识别 将有 [1,2,3] 在柱子下面 'asfd' . 注意,我甚至不必将变量声明为 global

    为什么会这样?

    我真的很想知道,因为当我了解可变工作区的时候,我就被证明是错的,而且我已经厌倦了不断地遇到这些问题*

    我知道解决这个问题的办法是:

    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 回复  |  直到 7 年前
        1
  •  2
  •   u2berggeist    7 年前

    更新:

    我在Pycon2015上找到了一个很好的演讲,解释了我试图在下面解释的内容,但是图表让它变得非常清晰。我将留下下面的解释来解释最初的3个脚本是如何工作的,但我建议去看视频:

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


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

    规则很少:

    1. 变量是指向实际保存数据的底层对象的链接/指针的名称。例如,街道地址。街道地址不是房子,它只是指向房子。所以地址(101街)就是指针。在全球定位系统中,你可能会把它标记为“家”。“home”这个词本身就是变量。

    2. 函数作用于对象,而不是变量或指针。将变量传递给函数时,实际上传递的是对象,而不是变量或指针。继续房屋示例,如果要向房屋添加平台,则需要平台承包商在房屋上工作,而不是元物理地址。

    3. 这个 return 函数中的命令返回指向对象的指针。所以这应该是房子的地址,而不是房子或者你可以叫你房子的名字。

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

    在外面,我会用 ---> 意思是“指向”

    在我们开始剧本之前,先从我们想要的开始。我们想要这个东西 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 在那个物体上 敌我识别 指向,即 ObjdFF . 这就引出了函数本身。

    def test(df):

    在这里,我们有一个本质上 = 功能。传递给测试函数的对象 ObjdFF 由函数变量指向 df . 所以现在 df --->objdff dff---> objdff

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

    我们先从 df.append(...) . 这个 .append(...) 传递到 ObjdFF . 这使得这个物体 ObjdFF 运行名为“append”的函数。正如@jai指出的, 追加(…) 方法使用 返回 命令输出一个新的数据帧,该数据帧附加了数据。我们将调用新对象 objdff_apnd

    现在我们可以进入 df = ... 部分。我们现在拥有的基本上是 df = objdff_apnd . 这很简单。变量 东风 现在指向对象 ObjdFffAPND

    在这一行的末尾我们有 df ---> objdff_apnd DFF--->对象 . 这就是问题所在。我们想要的东西( ObjdFffAPND )不是被指向 敌我识别

    最后,变量 敌我识别 仍然指向 ObjdFF 而不是 ObjdFffAPND . 这就引出了脚本3(见下文)。

    脚本2:

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

    就像剧本1, DFF--->对象 . 期间 测试(DFF) ,函数变量 df ---> objdff . 这就是事情不同的地方。

    手术(?) df['asdf'] = [1,2,3] 再次发送到基础对象 ObjdFF . 上次,这导致了一个新对象。然而,这一次, ['asdf'] 操作直接编辑对象 ObjdFF . 所以这个物体 ObjdFF 其中有额外的“asdf”列。

    因此最后我们有 数据框--->objdff 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的末尾开始,我们把right作为函数 测试(DFF) 结束了,我们已经 DFF--->对象 数据框--->objdff_apnd .

    函数 测试 返回 命令,因此返回对象 ObjdFffAPND . 这改变了路线 DFF=测试(DFF) 进入之内 dff = objdff_apnd .

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

        2
  •  1
  •   Jai    7 年前
    • 我认为pandas数据帧、列表和字典所有这些数据类型都是通过引用函数传递的,因此,这种行为。
    • 在第一个脚本中,要附加到一个新对象 append 返回一个新对象,因此它没有填充原始数据帧。
    • 在第二个脚本中,您将特定的dataframe列分配给原始dataframe对象,因此它用列填充原始dataframe对象,因为您正在修改原始对象
    • 您可以查看以下答案: 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.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.
    • 从描述中可以看出 追加 返回新对象
    • 你使用的方式 global 关键字错误…我想即使你没有 全球的 在第一个剧本里,还是没什么区别…我不知道 全球的 关键字,所以我不会提任何关于它的…但我知道如何使用关键字,这绝对不是正确的使用方法