import numpy as np X = np.random.random((1000, 3)) def pairwise_numpy(X): return np.sqrt(((X[:, None, :] - X) ** 2).sum(-1)) %timeit pairwise_numpy(X) def pairwise_python(X): M = X.shape[0] N = X.shape[1] D = np.empty((M, M), dtype=np.float) for i in range(M): for j in range(M): d = 0.0 for k in range(N): tmp = X[i, k] - X[j, k] d += tmp * tmp D[i, j] = np.sqrt(d) return D %timeit pairwise_python(X) from numba import double from numba.decorators import jit, autojit pairwise_numba = autojit(pairwise_python) %timeit pairwise_numba(X) %load_ext cythonmagic %%cython import numpy as np cimport cython from libc.math cimport sqrt @cython.boundscheck(False) @cython.wraparound(False) def pairwise_cython(double[:, ::1] X): cdef int M = X.shape[0] cdef int N = X.shape[1] cdef double tmp, d cdef double[:, ::1] D = np.empty((M, M), dtype=np.float64) for i in range(M): for j in range(M): d = 0.0 for k in range(N): tmp = X[i, k] - X[j, k] d += tmp * tmp D[i, j] = sqrt(d) return np.asarray(D) %timeit pairwise_cython(X) %%file pairwise_fort.f subroutine pairwise_fort(X,D,m,n) integer :: n,m double precision, intent(in) :: X(m,n) double precision, intent(out) :: D(m,m) integer :: i,j,k double precision :: r do i = 1,m do j = 1,m r = 0 do k = 1,n r = r + (X(i,k) - X(j,k)) * (X(i,k) - X(j,k)) end do D(i,j) = sqrt(r) end do end do end subroutine pairwise_fort # Compile the Fortran with f2py. # We'll direct the output into /dev/null so it doesn't fill the screen !f2py -c pairwise_fort.f -m pairwise_fort > /dev/null from pairwise_fort import pairwise_fort XF = np.asarray(X, order='F') %timeit pairwise_fort(XF) from scipy.spatial.distance import cdist %timeit cdist(X, X) from sklearn.metrics import euclidean_distances %timeit euclidean_distances(X, X) %pylab inline labels = ['python\nloop', 'numpy\nbroadc.', 'sklearn', 'fortran/\nf2py', 'scipy', 'cython', 'numba'] timings = [13.4, 0.111, 0.0356, 0.0167, 0.0129, 0.00987, 0.00912] x = np.arange(len(labels)) ax = plt.axes(xticks=x, yscale='log') ax.bar(x - 0.3, timings, width=0.6, alpha=0.4, bottom=1E-6) ax.grid() ax.set_xlim(-0.5, len(labels) - 0.5) ax.set_ylim(1E-3, 1E2) ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda i, loc: labels[int(i)])) ax.set_ylabel('time (s)') ax.set_title("Pairwise Distance Timings")