如果您对数组的大小有上限(即您从 获取它iterate
,因此您可以通过entrysteps=10000
并知道它永远不会大于10000
),那么您可以预先分配您的数组并将其传递给 uproot 并拥有uproot 填充它而不是创建新数组。在您的情况下,您可以将其设为记录数组:
buffer = numpy.empty(20000, dtype=[("pt", "f8"), ("eta", "f8")])
pt_buffer = buffer["pt"]
eta_buffer = buffer["eta"]
pt_buffer
和是的eta_buffer
视图buffer
,它们恰好是交错的,但它们和数组一样好用。(我分配 的原因20000
,而不仅仅是10000
,将在下面解释。)
现在假设您对两个默认interpretation
为uproot.asdtype(">f8", "f8")
. uproot.asarray(">f8", pt_buffer)
使用解释和请求这些数组uproot.asarray(">f8", eta_buffer)
。第一个参数是 Numpy dtype,它将用于解释来自 ROOT 文件的原始数据(big-endian,因此是">"
),第二个参数是您要就地读取数据的数组。
for arrays in tree.iterate({"pt": uproot.asarray(">f8", pt_buffer),
"eta": uproot.asarray(">f8", eta_buffer)},
outputtype=tuple, entrysteps=10000):
start = int((arrays[0].ctypes.data - buffer.ctypes.data) / buffer.itemsize)
stop = start + len(arrays[0])
array_of_tuples = buffer[start:stop]
print(array_of_tuples)
请参阅有关此很少使用且未广泛宣传的功能的文档。
即使iterate
在名为 的字典中填充并向您发送数组arrays
,它们也是buffer
记录数组(“元组数组”)的列视图。通过查看原始文件buffer
,我们看到了您想要的结构。
但是,uproot 实际上填充buffer
了整个篮子的内容,从第一个相关篮子的开头开始,到最后一个相关篮子的末尾结束,以涵盖每个子范围:[0, 10000)
、[10000, 20000)
、[20000, 30000)
等。因此buffer
,您想要的部分可能会开始几个( )中的条目start != 0
并可能在20000
( stop - start != len(buffer)
) 之前结束。由于arrays[0]
是仅包含您想要的条目的第一列的视图,因此和buffer
之间的差异是您想要的字节数。除以给出条目数。结束位置更容易计算。arrays[0].ctypes.data
buffer.ctypes.data
buffer
buffer.itemsize
的预分配buffer
必须足够大,以包括您确实想要的所有条目以及与篮子一起出现并且需要被切断的任何其他条目。20000
如果没有篮子大于 是安全的10000
。对于给定的tree
,您可以通过以下方式确定任何分支的任何篮子中的最大条目数:
max(branch.basket_numentries(i) for branch in tree.values()
for i in range(branch.numbaskets))
显然,这不是这些函数的设计目的:asarray
是为了提高性能,避免重新分配像buffer
. 但是,假设您需要列中的数据:arrays[0]
andarrays[0]
发送到 for 循环的主体。在上面,我们还想查看格式化为记录数组(“元组数组”)的数据,所以我们实际上是在查看这个被称为buffer
. 为了明智地做到这一点——避免与该子范围无关的条目——我们必须明确地将它们删除,并且库中没有任何函数可以确定该子范围的位置。然而,这
start = int((arrays[0].ctypes.data - buffer.ctypes.data) / buffer.itemsize)
stop = start + len(arrays[0])
array_of_tuples = buffer[start:stop]
将是这种功能的一般实现。