7

我正在从通过 Sierra Chart 从 Interactive Brokers 5 秒 OHLCVT 柱接收数据的文件中获取数据。

按照之前帖子中的建议,我没有将每个新行附加到数据框中,而是使用历史文件构建了一个数据框,并将 5000 条带有正确时间戳的“空白”记录附加到其中。然后我将每个新行写在一个空白行上,如果缺少时间戳并更新指针,则填充任何行。

这很好用。这是当前的类和函数。我的初始版本创建了 5000 行 NaN (OHLCVxyz)。我认为从最终数据类型开始会更整洁,因此将“空白”记录转换为零,OHLC 为浮点数,Vxyz 为整数,使用:

dg.iloc[0:5000] = 0.0
dg[[v, x, y, z]] = dg[[v, x, y, z]].astype('int')

每增加 5000 行只会发生一次(恒指每天一次)。令我惊讶的是对读/写循环的影响。它们从每行 0.8 毫秒变为 3.4 毫秒。唯一的变化是从 NaN 到零。

这张图片显示了一个带有零填充帧的初始运行(参见 timestats 0.0038),然后是一个带有 NaN 填充帧的运行(timestats 0.0008)。

谁能提供有关为什么写入 [0.0, 0.0, 0.0, 0.0, 0, 0, 0, 0] 而不是 [NaN, NaN, NaN, NaN, NaN, NaN, NaN 的字段可能会增加这么多时间的见解, 南] ?

也欢迎任何关于代码改进的想法。:)

谢谢

编辑+17 小时

根据@BrenBarn 的问题,我构建了一个更简单的模型,任何人都可以在没有数据的情况下运行。在这样做的过程中,我消除了 NaN 是否会影响它的问题。在这个版本中,我能够将 0.0s 写入两个版本,并且区别是相同的:

  • 具有 8 列浮点数的数组的添加速度比具有 4 列浮点数和 4 个 int64 的数组快 10 倍。
  • 在每种情况下,添加的行都是 [1.0, 2.0, 3.0, 4.0, 5, 6, 7, 8]
  • 使用 self.df.iloc[self.end] = datarow 和增量结束添加 10000 次。

因此,除非我弄错了(总是可能的),否则添加到具有 4 列浮点数和 4 个整数的数据帧似乎需要 10 倍的时间。这是熊猫的问题还是人们应该期待的问题?

这是测试代码这是输出图片

我认为在添加之前拥有 350,000 行 8 列的数组会产生显着差异。我最初添加到 10 行的测试显示没有影响 - 我必须回去重新测试它们。

编辑+10 分钟

不,我返回并创建了只有 10 行的初始数组,并且对添加循环的影响没有改变,因此它不是原始数组/数据帧的大小。很可能在我之前的测试中我认为我已经将列转换为整数,但我没有 - 检查这证明我认为会执行此操作的命令没有。

da = SierraFrame(range(10), np.zeros((10,8)))
da.extend_frame1()

编辑和可能的答案+35 分钟

这个问题不应该更详细地回答。

在这一点上,我的假设是,如果 df 包含所有一种类型,而不是包含浮点数和整数列。我刚刚使用所有 int64 对其进行了测试,所有浮点数的平均添加时间为 0.41 毫秒,而混合数据帧的平均添加时间为 2.8 毫秒。Int8s 耗时 0.39 毫秒。我猜这种混合会影响 pandas 优化其动作的能力,所以如果效率非常重要,那么所有列都是相同类型(可能是 float64)的数据框是最好的选择。

使用 Python 3.3.1 在 Linux x64 上进行的测试

4

1 回答 1

5

正如pandas 的主要作者在这篇博文中所述,pandas DataFrame 内部由“块”组成。块是一组具有相同数据类型的列。每个块都存储为其块类型的 numpy 数组。因此,如果您有五个 int 列,然后是五个 float 列,则将有一个 int 块和一个 float 块。

追加到多类型数组需要追加到每个底层 numpy 数组。追加到 numpy 数组很慢,因为它需要创建一个全新的 numpy 数组。因此,附加到多类型 DataFrame 的速度很慢是有道理的:如果所有列都是一种类型,则只需创建一个新的 numpy 数组,但如果它们是不同的类型,则必须创建多个新的 numpy 数组。

确实,保持数据类型相同会加快速度。但是,我想说的主要结论不是“如果效率很重要,请保持所有列的类型相同”。结论是如果效率很重要,请不要尝试附加到您的数组/数据帧

这就是 numpy 的工作原理。使用 numpy 数组最慢的部分是首先创建它们。它们具有固定的大小,当您“附加”到一个时,您实际上只是在创建一个具有新大小的全新大小,这很慢。如果您绝对必须附加它们,您可以尝试诸如弄乱类型之类的东西来减轻痛苦。但最终你只需要接受,每当你尝试追加到 DataFrame(或一般的 numpy 数组)时,你可能会遭受重大的性能打击。

于 2013-06-18T18:37:32.913 回答