我有一个函数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的情况下完成所有这些?
答案 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