Python *args returns 元组而不是 pandas 数据帧

Python *args returns tuple rather than pandas dataframes

具有return一系列数据帧的功能。

def frames():
  bla bla
  return df1, df2, df3, df4

我想编写一个函数,将这些帧附加在一起而不必列出计数,这样我以后可以有更多或更少的帧

def appender(*args):
   condition goes here
       append things that are true

我希望能够这样称呼它

appender(frames())

将return一整帧的帧通过条件。

现在 frames() 函数 return 是一个包含四个帧的元组。是否有任何简单的解决方法来解压元组?

感谢您的帮助!

克莱姆

更新这是一个例子

def frames():

    df1 = pd.DataFrame()

    df2 = pd.DataFrame()

    df3 = pd.DataFrame(['not', 'empty'])

    df4 = pd.DataFrame(['not', 'empty'])

    return df1, df2, df3, df4

def appender(*args):
    main_frame = pd.DataFrame()
    for arg in args:
        if arg.empty != True:
            assignment_frame = assignment_frame.append(arg)

    return assignment_frame


appender(frames())

给予


AttributeError Traceback(最近调用最后) 在 () ----> 1 个附加程序(帧())

在 appender(*args) 2 main_frame = pd.DataFrame() 3 对于 args 中的 arg: ----> 4 如果 arg.empty != True: 5 assignment_frame = assignment_frame.append(arg) 6

AttributeError: 'tuple' 对象没有属性 'empty'

如果您通过 appender(*frames()) 调用它,您的原始代码可以正常工作,但您仍然会收到错误消息,因为 assignment_frame 应该是 main_frame

不过,还有更简单的方法。只需传递一组数据框,然后根据您的条件使用列表理解来过滤它们。

请注意,您不想通过附加来构建数据框!这称为二次复制,因为每次调用 append 时都会返回原始数据帧的副本以及新附加的数据帧。这将非常慢。请参阅下面的时间安排。

def appender(dataframes):
    return pd.concat([df for df in dataframes if not df.empty])  # Optional: .reset_index()


>>> appender(frames())
       0
0    not
1  empty
0    not
1  empty

计时(连接与追加)

df = pd.DataFrame(np.random.randn(10, 10))

%timeit df2 = pd.concat([df] * 1000)
# 10 loops, best of 3: 54.7 ms per loop

%%timeit
df3 = pd.DataFrame()
for _ in range(1000):
    df3 = df3.append(df)
# 1 loop, best of 3: 1.28 s per loop

>>> df3.equals(df2)
True

有几个错误:

  1. 记得在你的初始函数参数中解压。
  2. 您在 appender 中数据框的变量名称发生变化,请保持一致。

这是一个工作示例:

def appender(*args):
    df = pd.DataFrame()
    for arg in args:
        if arg.empty != True:
            df = df.append(arg)
    return df

appender(*frames())

但是 pd.DataFrame.append in a loop is inefficient due to unnecessary data copying; it's not recommended. A more efficient way of writing this is possible via pd.concat 和列表理解:

def appender(*dfs):
    return pd.concat([df for df in dfs if not df.empty], ignore_index=True)

使用 ignore_index=True 确保您的输出数据帧具有默认的 pd.RangeIndex 索引。