在Python中高效地对稀疏数据进行移动平均并过滤阈值以上的数据

5
我正在进行一些基因组分析,但卡住了。我的数据非常稀疏,需要找到移动平均线超过某个阈值的位置,并将每个点标记为1或0。由于这种数据是唯一的,所以我无法使用可用的分析程序。
每个点代表人类基因组上的一个点(碱基)。对于每个数据集,有200,000,000个潜在点。数据本质上是一个 ~12000 个索引/值对列表,其中所有其他点都假定为零。我需要做的是对整个数据集进行移动平均,并返回平均值高于阈值的区域。
我目前正在顺序读取数据集中的每个点,并围绕我找到的每个点构建一个数组,但是对于大窗口大小,这样做速度非常慢。是否有更有效的方法来处理此问题,也许使用scipy或pandas?
编辑:Jamie的神奇代码很好用(但我还不能点赞)!非常感谢。

1
也许将数据转换为可用程序所能理解的格式会更有意义。与复杂的分析和结果可视化相比,数据转换很可能更容易实现。 - Wilbert
1个回答

4

您可以使用numpy将整个内容向量化。我已经创建了这个随机数据集,其中包含(约)12,000个介于0到199,999,999之间的索引和一个同样长的介于0到1之间的随机浮点数列表:

indices = np.unique(np.random.randint(2e8,size=(12000,)))
values = np.random.rand(len(indices))

然后,我构建了一个大小为 2*win+1 的索引数组,围绕每个 indices ,以及一个相应的数组,记录该点对移动平均值的贡献量:

win = 10

avg_idx = np.arange(-win, win+1) + indices[:, None]
avg_val = np.tile(values[:, None]/(2*win+1), (1, 2*win+1))

所有需要处理的就是重复的索引并将贡献添加到移动平均值中:
unique_idx, _ = np.unique(avg_idx, return_inverse=True)
mov_avg = np.bincount(_, weights=avg_val.ravel())

您现在可以获取移动平均值超过0.5的索引列表,例如:
unique_idx[mov_avg > 0.5]

就性能而言,首先将上述代码转换为函数:

def sparse_mov_avg(idx, val, win):
    avg_idx = np.arange(-win, win+1) + idx[:, None]
    avg_val = np.tile(val[:, None]/(2*win+1), (1, 2*win+1))
    unique_idx, _ = np.unique(avg_idx, return_inverse=True)
    mov_avg = np.bincount(_, weights=avg_val.ravel())
    return unique_idx, mov_avg

以下是针对测试数据描述的几种窗口大小的时间表:

In [2]: %timeit sparse_mov_avg(indices, values, 10)
10 loops, best of 3: 33.7 ms per loop

In [3]: %timeit sparse_mov_avg(indices, values, 100)
1 loops, best of 3: 378 ms per loop

In [4]: %timeit sparse_mov_avg(indices, values, 1000)
1 loops, best of 3: 4.33 s per loop

感谢你花时间认真思考这个问题。大部分代码对我来说都很陌生,因为我很少使用numpy,所以这非常有帮助。当你很快就想出了一种更好的解决方案时,我感觉自己在这上面浪费了很多时间! - Mark B
我发现将窗口大小增加到大约100以上会导致内存错误 :( - Mark B
@MarkB 那没什么意义。根据您提供的数字,移动平均值只会是一些百万条目数组。 - Jaime
我更详细地检查了我的数据集,其中一些数据集中有多达150,000条记录。使用您的示例数据,当窗口大小增加到2000时,我遇到了MemoryError,因此这是有道理的(10倍的数据,10倍较小的窗口大小)。看起来即使我在这台机器上有8Gb的内存,Python也不能使用超过1Gb的内存。但是,您的代码仍然非常有用。我最终做的是设置chunk_size参数,然后使用您的算法迭代数据,使用[chunk_begin-win]:[chunk_end+win],然后将块拼接在一起。 - Mark B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接