既然它已被弃用,那么空数据帧的 .concat() 的替代方案是什么?

回答 4 浏览 3864 2023-10-08

我有两个都可以为空的数据帧,我想将它们连接起来。

以前我只能做:

output_df= pd.concat([df1, df2])

但现在我遇到了

FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.

一个简单的解决方法是:

if not df1.empty and not df2.empty:
    result_df = pd.concat([df1, df2], axis=0)
elif not df1.empty:
    result_df = df1.copy()
elif not df2.empty:
    result_df = df2.copy()
else:
    result_df = pd.DataFrame()

但这看起来很丑陋。有人有更好的解决方案吗?

仅供参考:这是在 pandas 发布后出现的 v2.1.0

Timothee W 提问于2023-10-08
如果您对新行为感到满意,您仍然可以使用pd.concat。唯一的区别是数据帧的类型会改变,但它仍然会连接数据帧。这对你来说会是个问题吗?Frank Vel 2023-10-08
@FrankVel 新类型会是什么?另外,用 warnings.simplefilter(action='ignore', category=FutureWarning) 删除 Future 警告是否不好?Timothee W 2023-10-08
不知道新类型会怎么样。您一般不应该隐藏警告,因为它们不会影响您的代码。但是,如果您担心输出噪音,您可以暂时 抑制警告,这样您就可以忽略该特定函数(而不是所有其他警告)。Frank Vel 2023-10-09
如果有一个有效的索引但有一个空列,它会给我这条消息,所以它不仅仅是空数据帧。空列类型的旧行为是什么,新行为是什么。有人关心吗?如果这条消息消失我会非常高兴。Tunneller 2023-11-03
因此,为了减少闲聊,似乎应该:过滤警告,然后将 pandas 升级到非警告状态,然后删除警告过滤器? :(jtlz2 2023-11-15
4 个回答
#1楼 已采纳
得票数 5

准确地说, concat 并没有被弃用(今后也不会被弃用),但在 2.1.1 中,我可以通过以下示例触发 这个 FutureWarning ,而 df2 是一个空 DataFrame,其 dtypesdf1 不同:

df1 = pd.DataFrame({"A": [.1, .2, .3]})
df2 = pd.DataFrame(columns=["A"], dtype="object")

out = pd.concat([df1, df2]) ; print(out)

     A
0  0.1
1  0.2
2  0.3

作为您的情况的解决方案,您可以尝试像您所做的那样:

out = (df1.copy() if df2.empty else df2.copy() if df1.empty
       else pd.concat([df1, df2]) # if both DataFrames non empty
      )

或者甚至是这个? :

out = pd.concat([df1.astype(df2.dtypes), df2.astype(df1.dtypes)])
Timeless 提问于2023-10-08
Timeless 修改于2023-10-08
如果这是两个代码选项,我会将其设为两个代码块。目前它读起来就像一个代码片段。 (另外,如果它们有两个具有不同签名的非空数据帧,它们将如何表现?)MatBailie 2023-10-08
我更新了答案以解决您评论的第一部分。关于您的问题,如果两个数据帧具有不同的签名(dtypes,shapes,...),这是一个经典的串联,因此将由两个解决方案处理。Timeless 2023-10-08
感谢您提供如此准确的答案@Timeless :)Timothee W 2023-10-09
#2楼
得票数 1

这个更通用的解决方案怎么样?:

list_of_dfs = [df1, df2, dfx]
# now remove all columns from the dataframes which are empty or have all-NA 
cleaned_list_of_dfs = [df.dropna(axis=1, how='all') for df in list_of_dfs]
output_df = pd.concat(cleaned_list_of_dfs)

或者用你的一行示例:

output_df= pd.concat(df.dropna(axis=1, how='all') for df in [df1, df2])

也就是说,您可能希望在更明确的清理步骤中清理这些列,而不一定是在串联过程中。用户可能不希望某些列在串联过程中消失,这就是为什么他们从未来的 panda 中删除了这种行为。

Si Mon 提问于2023-11-01
#3楼
得票数 1

我发现这个基于 @Timeless 答案的解决方案对我来说最“不丑陋”。

In [1]: import pandas as pd

In [2]: df = pd.DataFrame([], columns=['A', 'B'])

In [3]: df = pd.concat([
   ...:     df if not df.empty else None,
   ...:     pd.DataFrame([{'A': 1.1, 'B': 2.2}])
   ...: ])

In [4]: df
Out[4]: 
     A    B
0  1.1  2.2
valentinmk 提问于2023-11-02
#4楼
得票数 1

如果您知道 df_list 中可能有空数据框,请尝试此操作

df_list = [df1, df2, ...]

df = pd.concat([df for df in df_list if not df.empty])
Victor23d 提问于2023-11-12