我从一个文件中获取数据,该文件通过Sierra Chart从Interactive Brokers的5秒OHLCVT条接收数据。
根据早期帖子中的建议,不是将每个新行附加到数据帧,而是使用历史文件构造数据框,并使用正确的时间戳向其附加5000个“空白”记录。然后我将每个新行写在空行上,如果缺少时间戳并填充指针,则填充任何行。
这很有效。这是当前的classes and functions。我的初始版本创建了5000行NaN(OHLCVxyz)。我认为从最终数据类型开始会更加整洁,因此将“空白”记录转换为零,OHLC为浮点数,Vxyz使用以下内容进行整数:
dg.iloc[0:5000] = 0.0
dg[[v, x, y, z]] = dg[[v, x, y, z]].astype('int')
这仅在每5000行(HSI每天一次)时发生一次。让我感到惊讶的是对读/写循环的影响。它们每行从0.8ms到3.4ms。唯一的变化是从NaNs到零。
This picture显示初始运行时填充零(参见时间戳0.0038),然后运行NaN填充帧(时间戳0.0008)。
任何人都可以提供有关为什么它可能会增加这么多时间来写入[0.0,0.0,0.0,0.0,0,0,0,0]而不是[NaN,NaN,NaN,NaN,NaN, NaN,NaN,NaN]?
欢迎任何关于代码改进的想法。 :)
由于
编辑 +17小时
根据@BrenBarn提出的问题,我构建了一个更简单的模型,可以由没有数据的任何人运行。在这样做的过程中,我消除了NaN是否会影响它的问题。在这个版本中,我能够为两个版本写0.0s,差异是相同的:
所以,除非我错了(总是可能的),似乎添加到4列浮点数和4个整数的数据帧需要10倍的时间。对于大熊猫来说这是一个问题还是人们应该期待的问题?
Here's the test code 和here is the output picture
我认为在添加之前拥有包含8列的350,000行数组会产生显着差异。我的初始测试增加到10行显示没有影响 - 我必须返回并重新测试它们。
编辑 +10分钟
不,我回去创建了只包含10行的初始数组,并且对add循环的影响没有改变,因此它不是原始数组/数据帧的大小。很可能在我之前的测试中我认为我已经将列转换为int但我没有 - 检查这证明了我认为这样做的命令没有。
da = SierraFrame(range(10), np.zeros((10,8)))
da.extend_frame1()
编辑和可能的答案 +35分钟
如果没有更详细地回答这个问题。
此时,我的假设是将[1.0,2.0,3.0,4.0,5,6,7,8]添加到数据框中的备用线的基本功能是不同的,如果df包括所有一种类型,而不是包含浮点数和整数列。我刚用所有的int64测试了它,所有浮点数的平均加法值为0.41ms vs 0.37ms,混合数据帧的平均加法值为2.8ms。 Int8s耗时0.39ms。我想混合会影响大熊猫优化其动作的能力所以如果效率非常重要,那么所有列属于同一类型的数据框(可能是float64)是最好的选择。
使用Python 3.3.1在Linux x64上进行的测试
答案 0 :(得分:5)
如this blog post by the main author of pandas中所述,pandas DataFrame内部由“块”组成。块是一组具有相同数据类型的列。每个块都存储为其块类型的numpy数组。因此,如果您有五个int列,然后是五个float列,则会有一个int块和一个float块。
附加到多类型数组需要附加到每个底层numpy数组。附加到numpy数组很慢,因为它需要创建一个全新的numpy数组。因此,附加到多类型DataFrame很慢是有意义的:如果所有列都是一种类型,它只需要创建一个新的numpy数组,但如果它们是不同的类型,则必须创建多个新的numpy数组。
确保将数据保持为相同类型确实可以加快速度。但是,我会说主要结论不是“如果效率很重要,那么保持所有列的类型相同”。结论是如果效率很重要,请不要尝试附加到数组/ DataFrame 。
这就是numpy的工作原理。使用numpy数组的最慢部分是首先创建它们。它们具有固定的大小,当你“追加”到一个时,你真的只是创建一个全新的大小,这很慢。如果你绝对必须追加它们,你可以尝试一些类似于搞乱类型的东西来缓解疼痛。但最终你只需要接受,只要你试图附加到DataFrame(或者一般的numpy数组),你可能会遭受重大的性能损失。