既然它已被弃用,那么空数据帧的 .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
如果您对新行为感到满意,您仍然可以使用
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,其 dtypes
比 df1
不同:
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)])
如果这是两个代码选项,我会将其设为两个代码块。目前它读起来就像一个代码片段。 (另外,如果它们有两个具有不同签名的非空数据帧,它们将如何表现?)
- 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 中删除了这种行为。
#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
#4楼
得票数 1
如果您知道 df_list 中可能有空数据框,请尝试此操作
df_list = [df1, df2, ...]
df = pd.concat([df for df in df_list if not df.empty])