#!/usr/bin/env python # coding: utf-8 # ## PyData.Tokyo Meetup #4 - Performance Tips # In[1]: get_ipython().run_line_magic('load_ext', 'watermark') get_ipython().run_line_magic('watermark', "-a 'Hideki Tanaka (@atelierhide)' -v -p numpy,numba,cython -d") # --- # ### Multiprocessing # In[2]: from multiprocessing import Pool import math pool = Pool(processes=4) get_ipython().run_line_magic('timeit', 'pool.map(math.sqrt, xrange(10000))') pool.close() pool.join() # --- # ### Numpy, Numba, Cython # In[3]: import numpy as np X = np.random.random((1000, 3)) # In[4]: 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 # In[5]: # Numpy def pairwise_numpy(X): return np.sqrt(((X[:, None, :] - X) ** 2).sum(-1)) # In[6]: # Numba from numba.decorators import autojit pairwise_numba = autojit(pairwise_python) # In[7]: # Cython get_ipython().run_line_magic('load_ext', 'Cython') # In[8]: get_ipython().run_cell_magic('cython', '', '\nimport numpy as np\ncimport cython\nfrom libc.math cimport sqrt\n\n@cython.boundscheck(False)\n@cython.wraparound(False)\ndef pairwise_cython(double[:, ::1] X):\n cdef int M = X.shape[0]\n cdef int N = X.shape[1]\n cdef double tmp, d\n cdef double[:, ::1] D = np.empty((M, M), dtype=np.float64)\n for i in range(M):\n for j in range(M):\n d = 0.0\n for k in range(N):\n tmp = X[i, k] - X[j, k]\n d += tmp * tmp\n D[i, j] = sqrt(d)\n return np.asarray(D)\n') # In[10]: get_ipython().run_line_magic('timeit', 'pairwise_python(X)') get_ipython().run_line_magic('timeit', 'pairwise_numpy(X)') get_ipython().run_line_magic('timeit', 'pairwise_numba(X)') get_ipython().run_line_magic('timeit', 'pairwise_cython(X)') # --- # ### List Comprehension, Map, Numpy # In[11]: import math import numpy as np # In[12]: def list_append(x): results = [] for i in xrange(x): results.append(math.sqrt(i)) return results def list_append2(x): results = [] for i in xrange(x): results.append(math.sqrt(i)) return results def list_comp(x): results = [math.sqrt(i) for i in xrange(x)] return results def list_map(x): results = map(math.sqrt, xrange(x)) return results def list_numpy(x): results = list(np.sqrt(np.arange(x))) return results # In[13]: x = 10000 get_ipython().run_line_magic('timeit', 'list_append(x)') get_ipython().run_line_magic('timeit', 'list_append2(x)') get_ipython().run_line_magic('timeit', 'list_comp(x)') get_ipython().run_line_magic('timeit', 'list_map(x)') get_ipython().run_line_magic('timeit', 'list_numpy(x)') # ### References # # - [High Performance Python Computing for Data Science](http://www.slideshare.net/tkm2261/high-performance-python-computing-for-data-science) # - [Numba vs. Cython](https://jakevdp.github.io/blog/2013/06/15/numba-vs-cython-take-2/)