我正在做一个实验来计算信号的近似熵。详细信息(和实际代码)可以在Wikipedia page上找到。不幸的是,虽然算法本身有效,但对于大型数据集来说速度非常慢(例如,2000长信号需要大约25秒)。由于我在很长的信号上做这个计算,在这个速度下,我希望我的实验能持续至少1个月。我想知道是否有任何方法可以加速算法。
public static void main(String[] args) {
int[] number = new int [10];
printReverse(reverseNumbersWhile(number));
}
public static int[] reverseNumbersWhile(int[] input){
System.out.println("Enter 10 numbers : ");
Scanner in = new Scanner(System.in);
for (int i = 0; i < input.length; i++){
input[i] = in.nextInt();
}
//System.out.println(input);
return input;
}
public static void printReverse(int[] value){
for (int i = value.length - 1; i >=0; i--){
System.out.print(value[i] + " ");
}
答案 0 :(得分:1)
我没有看到所有内容,而是举例说明如何使用向量计算优化函数:
def maxdist_opti(x_i,x_j):
return max(abs(x_i-x_j))
当您的数据存储到numpy数组中时,您可以在它们上使用numpy运算符(并且有很多这些运算符,您可以在这里查看:https://docs.scipy.org/doc/numpy-1.13.0/user/index.html)并且它会更快,在上面的例子中,我在numpy数组上使用了soustraction和np.max
函数。
这里,使用随机数据:
x_i = np.random.rand(10000)
x_j = np.random.rand(10000)
这里使用的数据不是很长,但你可以看到非常好的性能提升:
%timeit _maxdist(x_i,x_j)
100 loops, best of 3: 3.01 ms per loop
%timeit maxdist_opti(x_i,x_j)
10000 loops, best of 3: 28 µs per loop
您可以使用以下逻辑仅对整个公式进行矢量计算,并且性能的提升将是巨大的。
请注意,数据越长,使用矢量计算的优化程度就越高。
答案 1 :(得分:1)
通常在优化时,您应该从算法优化开始,这会降低算法的复杂性,而不仅仅是常量。
一条经验法则是查看最里面的循环 - 它包含大多数时间执行的操作。
我不确定我是否正确阅读了代码,但看起来U
是一个矩阵,_maxdist
对其列进行计算。在这种情况下,确保每列只执行一次计算是有意义的。
例如,计算每列的值,存储在数组中并在_phi
中使用。
答案 2 :(得分:1)
如果您愿意将该功能移至cython并添加一些类型注释,则可以获得显着的性能提升。这是我的算法版本:
apen.pyx:
cimport cython
from libc.math cimport fabs, log
import numpy as np
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.initializedcheck(False)
@cython.cdivision(True)
cdef double max_dist(double[:] x_i, double[:] x_j, int m) nogil:
#Performs the max function described in step 4 of ApEn algorithm
cdef double out
cdef double dist
out = fabs(x_i[0] - x_j[0])
for k in range(1, m - 1):
dist = fabs(x_i[k] - x_j[k])
if dist > out:
out = dist
return out
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.initializedcheck(False)
@cython.cdivision(True)
cdef double phi(double[:] Sn, int m, int r):
cdef int N = len(Sn)
cdef int i
cdef int j
cdef int k
cdef int c_val
cdef int counter
cdef double phi_sum = 0
cdef double phi
cdef double m_dist
#Performs step 3 of the ApEn algorithm
cdef double[:, :] x = np.empty((N - m + 1, m), dtype=np.float64)
with nogil:
for i in range(N - m + 1):
for j in range(0, m):
x[i, j] = Sn[j + i]
#Performs a combined steps 4 & 5 of the ApEn algorithm
for i in range(N - m + 1):
counter = 0
for j in range(N - m + 1):
m_dist = max_dist(x[i], x[j], m)
c_val = 1 if m_dist <= r else 0
counter += c_val
phi_sum += log(counter / (N - m + 1.0))
phi = phi_sum / (N - m + 1.0)
return phi
cpdef double approx_entropy(double[:] Sn, int m, int r):#Passing in steps 1 & 2 of the ApEn algorithm
cdef double ApEn = abs(phi(Sn, m, r) - phi(Sn, m + 1, r))#Performs step 6 of the ApEn algorithm
return ApEn
apen.pxd:
cdef double max_dist(double[:] x_i, double[:] x_j, int m) nogil
cdef double phi(double[:] Sn, int m, int r)
cpdef double approx_entropy(double[:] Sn, int m, int r)
setup.pxd:
from distutils.core import setup
from Cython.Build import cythonize
from distutils.core import Extension
import numpy as np
extensions = [
Extension("apen", sources=["apen.pyx"], include_dirs=[np.get_include()], extra_compile_args=["-w"]),
]
setup(
ext_modules = cythonize(extensions)
)
main.py:
import time
import apen
import numpy as np
start = time.time()
data = np.random.rand(2000)
#data = np.array([85, 80, 89] * 17, dtype=np.float64)
answer = apen.approx_entropy(Sn=data, m=2, r=3)
print(answer)
end = time.time()
print(end - start)
在我的笔记本电脑上使用此代码获取2000个随机数据点,cython代码在0.36秒内计算出ApEn。相比之下,维基百科代码需要14.75秒。这相当于<强> 40倍的速度提升。希望你觉得这很有帮助!