合并多个 Pandas Dataframe 对象

问题描述

我有一个 Pandas DataFrame 对象列表 df_list,我从 csv 和 parquet 文件中加载了这些对象,并将 TimeStamp 对象作为索引。我想将它们全部合并为一个 DataFrame 对象,如下所示:

  • 每个 DataFrame 对象的索引都是唯一的。合并后的 DataFrame 的索引也应该是唯一的,并且应该按索引列排序。
  • 如果一个索引存在于两个或多个原始 DataFrame 对象中,则该索引的列值对于所有对象都必须相同。否则脚本应显示错误消息(例如,引发异常)。某些列具有浮点值,其中一些值最初保存为 csv 时可能会丢失精度,因为这样做需要将值转换为涉及四舍五入的文本。如果是这种情况,值比较需要考虑到这一点。
  • 任何原始 DataFrame 对象都被认为涵盖了第一行索引和最后一行索引之间的时间段。我想知道合并的数据帧对象涵盖哪些时间段。这是原始 DataFrame 对象的时间段的并集,可能包含间隙。

如何使用 Pandas 命令有效地执行此操作?

我尝试了以下方法:

intervals = pd.DataFrame(columns=column_name_list).set_index(index_name)
for current_df in df_list:
    for index in current_df.index:
        if index in intervals.index:
            if current_df.loc[index] != intervals.loc[index]:
                raise RuntimeError("Entries for {} do not match: {} and {},respectively".format(repr(index),repr(current_df.loc[index]),repr(intervals.loc[index])))
        intervals.loc[index] = current_df.loc[index]

但这非常慢,我收到以下错误:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-a3867a7c8aa1> in <module>
     78             for index in current_df.index:
     79                 if index in intervals.index:
---> 80                     if current_df.loc[index] != intervals.loc[index]:
     81                         raise RuntimeError("Entries for {} do not match: {} and {},repr(intervals.loc[index])))
     82                 intervals.loc[index] = current_df.loc[index]

D:\ProgramData\Miniconda3\envs\stocks\lib\site-packages\pandas\core\generic.py in __nonzero__(self)
   1327 
   1328     def __nonzero__(self):
-> 1329         raise ValueError(
   1330             f"The truth value of a {type(self).__name__} is ambiguous. "
   1331             "Use a.empty,a.bool(),a.item(),a.any() or a.all()."

ValueError: The truth value of a Series is ambiguous. Use a.empty,a.any() or a.all().

所以我似乎无法使用 != 运算符比较两行。 (此外,我的代码目前没有考虑可能的舍入误差,也没有确定涵盖的时间段。)

解决方法

我尝试了以下方法:

这将遍历现有数据帧的每个元素以及新数据帧的每个元素。这是 O(n^2),这很慢。如果您可以一次对数据进行排序和处理,速度会快得多。

如何使用 Pandas 命令有效地执行此操作?

您可以使用 concat 执行此操作,然后进行排序,然后使用 Index.duplicated()keep=False 来获取数据帧上的布尔索引。

然后,将该索引与 .loc[] 结合使用以获取具有重复索引值的数据帧子集。称其为欺骗数据帧。然后,使用 drop_duplicates() 删除完全相同的行。如果此时复制数据帧的行数非零,则引发异常,因为您有具有不同列值的重复索引值。欺骗数据帧包含违规数据。

这个解释有点含糊,抱歉。您没有包含示例数据集,因此我没有任何可测试的内容。

某些列具有浮点值,其中一些值最初保存为 csv 时可能会丢失精度,因为这样做需要将值转换为涉及四舍五入的文本。

这里有一个更简单的方法:您应该以与写出的方式相同的方式读取 CSV。看看 this page 上的 round_trip

如果这行不通,请参阅Dropping duplicates with less precision

但这非常慢,我收到以下错误:

如果您调用 df.loc[foo],它将在索引中查找 foo。这为您提供了与行值对应的系列。如果将两个系列与 == 进行比较,则会得到另一个具有 True/False 值的系列。为了将此系列视为单个布尔值,您需要决定是否对任何 True 值感兴趣,或者是否希望它仅在所有值都为 True 时为 True。

例如

if (current_df.loc[index] != intervals.loc[index]).any():

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...