使用numpy或cython进行高效的成对DTW计算

时间:2017-07-09 09:20:32

标签: python numpy cython joblib

我正在尝试计算numpy数组中包含的多个时间序列之间的成对距离。请参阅以下代码

print(type(sales))
print(sales.shape)

<class 'numpy.ndarray'>
(687, 157)

因此,sales包含687个长度为157的时间序列。使用pdist计算时间序列之间的DTW距离。

import fastdtw
import scipy.spatial.distance as sd

def my_fastdtw(sales1, sales2):
    return fastdtw.fastdtw(sales1,sales2)[0]

distance_matrix = sd.pdist(sales, my_fastdtw)

---编辑:尝试不使用pdist() -----

distance_matrix = []
m = len(sales)    
for i in range(0, m - 1):
    for j in range(i + 1, m):
        distance_matrix.append(fastdtw.fastdtw(sales[i], sales[j]))

---编辑:并行化内循环-----

from joblib import Parallel, delayed
import multiprocessing
import fastdtw

num_cores = multiprocessing.cpu_count() - 1
N = 687

def my_fastdtw(sales1, sales2):
    return fastdtw.fastdtw(sales1,sales2)[0]

results = [[] for i in range(N)]
for i in range(0, N- 1):
    results[i] = Parallel(n_jobs=num_cores)(delayed(my_fastdtw) (sales[i],sales[j])  for j in range(i + 1, N) )

所有方法都很慢。并行方法大约需要12分钟。有人可以建议一个有效的方法吗?

---编辑:按照以下答案中提到的步骤---

以下是lib文件夹的外观:

VirtualBox:~/anaconda3/lib/python3.6/site-packages/fastdtw-0.3.2-py3.6- linux-x86_64.egg/fastdtw$ ls
_fastdtw.cpython-36m-x86_64-linux-gnu.so  fastdtw.py   __pycache__
_fastdtw.py                               __init__.py

所以,那里有一个cyd版本的fastdtw。安装时,我没有收到任何错误。即使是现在,当我在程序执行期间按CTRL-C时,我可以看到正在使用纯python版本(fastdtw.py):

/home/vishal/anaconda3/lib/python3.6/site-packages/fastdtw/fastdtw.py in fastdtw(x, y, radius, dist)

/home/vishal/anaconda3/lib/python3.6/site-packages/fastdtw/fastdtw.py in __fastdtw(x, y, radius, dist)

代码仍然像以前一样缓慢。

2 个答案:

答案 0 :(得分:4)

TL; DR

你的fastdtw安装了快速cpp版本,然后默默地退回到纯python版本,这很慢。

您需要修复fastdtw - 包的安装。

整个计算在fastdtw完成,所以你无法真正从外部加速。并行化和python并不是一件容易的事情(但是?)。

fastdtw文档说它需要O(n)次操作进行比较,因此对于整个测试集,它需要大约10^9次操作的数量级,应该完成大约几秒钟,如果编程,例如,C。您看到的表现远不及它。

如果我们看一下我们看到的code of fastdtw,那就有两个版本:cython / cpp-version,它是快速的并且是通过cython导入的,而且是慢速回退的纯python版本。如果没有预设快速版本,则会默默使用慢速python版本。

所以运行你的计算,用Ctr+C打断它,你会看到你在python-code中的某个地方。您也可以转到lib文件夹,看看里面只有pure-python版本。

因此,快速fastdtw版本的安装失败。实际上,我认为wheel-package是拙劣的,至少在我的版本中只有纯python代码存在。

怎么办?

  1. 获取源代码,例如通过git clone https://github.com/slaypni/fastdtw
  2. 进入fstdtw文件夹并运行python setup.py build
  3. 注意错误。我是
  4.   

    致命错误:numpy / npy_math.h:没有这样的文件或目录

    1. 修复它。
    2. 对我来说,解决方法是更改​​setup.py中的以下几行:

      import numpy # THIS ADDED
      extensions = [Extension(
              'fastdtw._fastdtw',
              [os.path.join('fastdtw', '_fastdtw' + ext)],
              language="c++",
              include_dirs=[numpy.get_include()], # AND ADDED numpy.get_include()
              libraries=["stdc++"]
          )]
      
      1. 重复3. + 4。直到成功
      2. 运行python setup.py install
      3. 现在你的程序应该快100倍。 `

答案 1 :(得分:4)

说实话,fastdtw一点都不快

from cdtw import pydtw
from dtaidistance import dtw
from fastdtw import fastdtw
from scipy.spatial.distance import euclidean
s1=np.array([1,2,3,4],dtype=np.double)
s2=np.array([4,3,2,1],dtype=np.double)

%timeit dtw.distance_fast(s1, s2)
4.1 µs ± 28.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit d2 = pydtw.dtw(s1,s2,pydtw.Settings(step = 'p0sym', window = 'palival', param = 2.0, norm = False, compute_path = True)).get_dist()
45.6 µs ± 3.39 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit d3,_=fastdtw(s1, s2, dist=euclidean)
901 µs ± 9.95 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

fastdtwdtaidistance lib要慢219倍,比cdtw要慢20倍

考虑更改。这是dtaidistance git:

https://github.com/wannesm/dtaidistance

要安装,只需:

pip install dtaidistance