快速读取交错数据的方法?

2024-03-18

我有一个包含多个数据通道的文件。该文件以基本速率采样,每个通道都以该基本速率除以某个数字进行采样——它似乎总是 2 的幂,尽管我认为这并不重要。

所以,如果我有渠道a, b, and c,在 1、2 和 4 的分隔符处采样,我的流将如下所示:

a0 b0 c0 a1 a2 b1 a3 a4 b2 c1 a5 ...

为了增加乐趣,通道可以独立地是浮点型或整数型(尽管我知道每个通道),并且数据流不一定以 2 的幂结束:示例流无需进一步扩展即可有效。这些值有时很大,有时是小端,尽管我预先知道我要处理什么。

我有代码可以正确解压这些并用正确的值填充 numpy 数组,但它很慢:它看起来像(希望我没有掩盖太多;只是给出算法的想法):

for sample_num in range(total_samples):
    channels_to_sample = [ch for ch in all_channels if ch.samples_for(sample_num)]
    format_str = ... # build format string from channels_to_sample
    data = struct.unpack( my_file.read( ... ) ) # read and unpack the data
    # iterate over data tuple and put values in channels_to_sample
    for val, ch in zip(data, channels_to_sample):
        ch.data[sample_num / ch.divider] = val

而且速度很慢——在我的笔记本电脑上读取 20MB 的文件需要几秒钟。 Profiler 告诉我我花了很多时间Channel#samples_for()——这是有道理的;这里有一些条件逻辑。

我的大脑感觉有一种方法可以一次性完成此操作,而不是嵌套循环——也许使用索引技巧将我想要的字节读取到每个数组中?构建一个庞大的、疯狂的格式字符串的想法似乎也是一条值得怀疑的道路。

Update

感谢那些回复的人。无论如何,numpy 索引技巧将读取测试数据所需的时间从大约 10 秒减少到大约 0.2 秒,加速了 50 倍。


真正提高性能的最佳方法是摆脱所有样本的 Python 循环,并让 NumPy 在编译的 C 代码中执行此循环。这实现起来有点棘手,但这是可能的。

首先,您需要做一些准备。正如贾斯汀·皮尔(Justin Peel)所指出的,样本的排列模式在一定数量的步骤后会重复。如果 d_1, ..., d_k 是 k 个数据流的除数,b_1, ..., b_k 是流的样本大小(以字节为单位),lcm 是这些除数的最小公倍数,则

N = lcm*sum(b_1/d_1+...+b_k/d_k)

将是流模式之后重复的字节数。如果您已经确定前 N 个字节各自属于哪个流,则可以简单地重复此模式。

您现在可以通过类似于以下内容的方式构建前 N 个字节的流索引数组

stream_index = []
for sample_num in range(lcm):
    stream_index += [i for i, ch in enumerate(all_channels)
                     if ch.samples_for(sample_num)]
repeat_count = [b[i] for i in stream_index]
stream_index = numpy.array(stream_index).repeat(repeat_count)

Here, d是序列 d_1, ..., d_k 并且b是序列 b_1, ..., b_k。

现在你可以做

data = numpy.fromfile(my_file, dtype=numpy.uint8).reshape(-1, N)
streams = [data[:,stream_index == i].ravel() for i in range(k)]

您可能需要在末尾填充一点数据以使reshape() work.

现在,属于每个流的所有字节都位于单独的 NumPy 数组中。您可以通过简单地分配给dtype每个流的属性。如果您希望第一个流被解释为大端整数,只需编写

streams[0].dtype = ">i"

这不会以任何方式改变数组中的数据,只是改变它的解释方式。

这可能看起来有点神秘,但在性能方面应该要好得多。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

快速读取交错数据的方法? 的相关文章

随机推荐