我正在努力想出一种非混淆,有效的方法来使用numpy来计算一组3D矢量中的自相关函数。
我在3d空间中有一组矢量,保存在数组中
a = array([[ 0.24463039, 0.58350592, 0.77438803],
[ 0.30475903, 0.73007075, 0.61165238],
[ 0.17605543, 0.70955876, 0.68229821],
[ 0.32425896, 0.57572195, 0.7506 ],
[ 0.24341381, 0.50183697, 0.83000565],
[ 0.38364726, 0.62338687, 0.68132488]])
如果上面的图片不可用,公式也会打印在下面: C(t,{v} n)= \ frac 1 {nt} \ sum {i = 0} ^ {n-1-t} \ vec v_i \ cdot \ vec v_ {i + t }
我正在努力以有效的方式编写代码,非混淆方式。我可以用两个嵌套的for循环来计算这个,但这很慢。通过使用numpy中的一个嵌入式函数,有一种快速的方法,但它们似乎使用完全不同的相关函数定义。这里已经解决了类似的问题,How can I use numpy.correlate to do autocorrelation?但是它不处理向量。你知道我怎么解决这个问题?
答案 0 :(得分:2)
NumPy例程适用于1D阵列。作为一个" minimal"改进,使用向量化操作进行标准化步骤(在前到后的行中使用np.arange
):
def vector_autocorrelate(t_array):
n_vectors = len(t_array)
# correlate each component indipendently
acorr = np.array([np.correlate(t_array[:,i],t_array[:,i],'full') for i in xrange(3)])[:,n_vectors-1:]
# sum the correlations for each component
acorr = np.sum(acorr, axis = 0)
# divide by the number of values actually measured and return
acorr /= (n_vectors - np.arange(n_vectors))
return acorr
对于较大的数组大小,应考虑使用傅立叶变换算法进行相关。如果您对此感兴趣,请查看库tidynamics的示例(免责声明:我编写了库,它只依赖于NumPy)。
作为参考,以下是NumPy代码(我为测试编写的代码),代码vector_autocorrelate和tidynamics的时序。
size = [2**i for i in range(4, 17, 2)]
np_time = []
ti_time = []
va_time = []
for s in size:
data = np.random.random(size=(s, 3))
t0 = time.time()
correlate = np.array([np.correlate(data[:,i], data[:,i], mode='full') for i in range(data.shape[1])])[:,:s]
correlate = np.sum(correlate, axis=0)/(s-np.arange(s))
np_time.append(time.time()-t0)
t0 = time.time()
correlate = tidynamics.acf(data)
ti_time.append(time.time()-t0)
t0 = time.time()
correlate = vector_autocorrelate(data)
va_time.append(time.time()-t0)
您可以看到结果:
print("size", size)
print("np_time", np_time)
print("va_time", va_time)
print("ti_time", ti_time)
尺寸[16,64,256,1024,4096,16384,65536]
np_time [0.00023794174194335938,0.0002703666687011719,0.0002713203430175781, 0.001544952392578125,0.0278470516204834,0.36094141006469727,6.922360420227051]
va_time [0.00021696090698242188,0.0001690387725830078,0.000339508056640625,0.0014629364013671875,0.024930953979492188,0.34442687034606934,7.005630731582642]
ti_time [0.0011148452758789062,0.0008449554443359375,0.0007512569427490234, 0.0010488033294677734,0.0026645660400390625,0.007939338684082031,0.048232316970825195]
或绘制它们
plt.plot(size, np_time)
plt.plot(size, va_time)
plt.plot(size, ti_time)
plt.loglog()
对于除非常小的数据系列之外的所有内容," N ** 2"算法无法使用。
答案 1 :(得分:1)
这是我的结果。它较慢(约4倍)并提供其他结果。为什么我要发布它呢?我认为值得看看如何衡量和有什么区别。如果 - 另外 - 任何人都找到了不同结果的原因,我会更高兴。
所以,这是我的解决方案:
%timeit [np.mean([np.dot(a[t], a[i+t]) for i in range(len(a)-t)]) for t in range(len(a))]
结果:每回路95.2μs±3.41μs(平均值±标准偏差,7次运行,每次10000次循环)
相比之下,您的解决方案速度提高了约4倍:
%timeit vector_autocorrelate(a)
提供:每循环24.8μs±1.46μs(平均值±标准偏差,7次运行,每次10000次循环)
答案 2 :(得分:1)
嗨,我遇到了类似的问题。这是我的主意
def fast_vector_correlation(M):
n_row = M.shape[0]
dot_mat = M.dot(M.T)
corr = [np.trace(dot_mat,offset=x) for x in range(n_row)]
corr/=(n_row-np.arange(n_row))
return corr
这个想法是dot_mat
包含行向量之间的所有标量积。要计算不同t
值下的相关性,您只需要对对角线(对角线的右上角部分)求和,如picture所示。
答案 3 :(得分:0)
我在这里发布答案以防其他人需要它,因为我花了很长时间才找到可行的方法。我最后通过定义以下函数来解决这个问题
def vector_autocorrelate(t_array):
n_vectors = len(t_array)
# correlate each component indipendently
acorr = np.array([np.correlate(t_array[:,i],t_array[:,i],'full') for i in xrange(3)])[:,n_vectors-1:]
# sum the correlations for each component
acorr = np.sum(acorr, axis = 0)
# divide by the number of values actually measured and return
acorr = np.array( [ val / (n_vectors - i) for i,val in enumerate(acorr)])
return acorr
如果有人有更好的想法,我真的很想听到,因为我认为现在还没有那么紧凑。虽然这比没有好,这就是我在这里发布的原因。