如何在具有给定可能元素的每个可能的长度为L的数组的数组上快速运行函数?

时间:2011-10-11 04:19:00

标签: python numpy scipy

我有一个函数calc_dG,对于任何对应于短DNA序列(3到15个碱基左右)的阵列,给出了该序列的结合能。实际上,它只是一个数组查找。 nndG是相邻碱基对的结合能阵列,因此当使用a,g,c,t - >时,可以用nndG[4*S[:-1]+S[1:]]计算结合能。以数字方式表示序列的0,1,2,3方式:这意味着可以在numpy中非常快速地计算许多序列的数组。

我需要找到长度为L的每个序列,它们都适合某些模板,并在一定范围内产生结合能值。

使用迭代器非常容易:只需遍历每个可能的数组输入,计算绑定能量,然后记录范围内的数组。然而,当在Python中实现时,这太慢了(对于长度为15,每个元素有4个可能的值,有4 ** 15个可能的数组等等)。我可以使用Weave或其他一些在C中实现它的方法,但我更愿意找到一个简单快速的基于数组的解决方案。

例如,如果每个元素具有相同的可能值(例如,[0,1,2,3]),则可以使用{{1}生成具有这些值的每个可能长度L 1D数组的数组。 };然后我可以做lambda x: indices(repeat([4],L)).reshape((L,-1)).transpose(),并使用结果[在所需范围内的结果]来获得我想要的数组作为最终结果。这比使用Python迭代器快得多,并且可能几乎与使用C迭代器一样快,如果不是更快。不幸的是,它不适用于任意模板,对于较长的序列,将耗尽内存,因为它必须在计算值之前将每个可能的数组存储在内存中。

有没有办法在不诉诸C的情况下完成所有这些?

1 个答案:

答案 0 :(得分:1)

如果我正确理解了您的问题,那么您最大限度地使用集合{0,1,2,3}中的整数f(i_1, i_2, ..., i_n)

您可以结合使用迭代和矢量化索引。

import numpy as np
import itertools

def cartesian_chunked(n, n_items=4, chunk_dim=3):
    if n > chunk_dim:
        p = n - chunk_dim
        q = chunk_dim
        outer = itertools.product(*([range(n_items)] * (n - chunk_dim)))
    else:
        p = 0
        q = n
        def outer_iter():
            yield ()
        outer = outer_iter()

    chunk = np.zeros([n_items**q, n], dtype=int)
    chunk[:,p:] = np.indices(np.repeat([n_items], q)).reshape(q, -1).T
    for seq in outer:
        chunk[:,:p] = seq
        yield chunk

def compute_energy(indices):
    base_energies = np.array([-1, 4, 8, 2.4])
    return (base_energies[indices]).sum(axis=1) 

max_energy = 0
max_config = None

# try out 4**10 ~ 1e6 combinations, in chunks of 4**8
for chunk in cartesian_chunked(n=10, n_items=4, chunk_dim=8):
    energies = compute_energy(chunk)
    j = np.argmax(energies)
    if energies[j] > max_energy:
        max_energy = energies[j]
        max_config = chunk[j].copy() # copy! the chunk is modified

print max_energy
print max_config