#!/usr/bin/env python # coding: utf-8 # # Computação vetorizada com NumPy # # ## Contexto: "O incrível crescimento de Python" # # # # # # Fonte: StackOverflow blog [The Incredible Growth of Python](https://stackoverflow.blog/2017/09/06/incredible-growth-python/) # # # # Fonte: StackOverflow blog [Why is Python Growing So Quickly?](https://stackoverflow.blog/2017/09/14/python-growing-quickly/) # # ## Exemplo 1: MRUV # # > Exemplo do livro *Programming for Computations - Python: A Gentle Introduction to Numerical Simulations with Python* de Svein Linge e Hans Petter Langtangen. # # Altura ao longo do tempo de um objeto lançado verticalmente: # # $$y = {v_0}t + \frac{g{t^2}}{2}$$ # In[1]: import numpy as np import matplotlib.pyplot as plt v0 = 5 g = -9.81 t = np.linspace(0, 1, 1001) y = v0 * t + g * t**2 / 2 plt.plot(t, y) plt.xlabel('t (s)') plt.ylabel('y (m)') plt.show() # ## Exemplo 2: Random Walk # # Exemplo adaptado de Nicolas P. Rougier em [From Python to Numpy](http://www.labri.fr/perso/nrougier/from-python-to-numpy/) # # ### Random walk: solução OO # In[2]: import random class RandomWalker: def __init__(self): self.position = 0 self.path = [] def step(self): self.position += random.choice([-1, 1]) self.path.append(self.position) def walk(self, steps): for _ in range(steps): self.step() return self.path # In[3]: get_ipython().run_line_magic('matplotlib', 'inline') import matplotlib.pyplot as plt # In[4]: walker = RandomWalker() walker.walk(10) # In[6]: walker = RandomWalker() plt.plot(walker.walk(1000)) plt.show() # In[7]: get_ipython().run_cell_magic('timeit', '-n 1000', 'walker.walk(1000)\n') # ### Random Walk: solução procedural # In[8]: def random_walk(n): position = 0 walk = [position] for i in range(n): position += random.choice([-1, 1]) walk.append(position) return walk # In[9]: get_ipython().run_cell_magic('timeit', '-n 1000', 'walk = random_walk(1000)\n') # ### Random Walk: solução vetorizada com `itertools` # In[10]: from itertools import accumulate g = accumulate([1,2,3,4,5]) g # In[11]: next(g), next(g), next(g) # In[12]: list(g) # In[13]: g = accumulate([1,2,3,4,5]) list(g) # In[15]: def random_walk_itertools(n): steps = random.choices([-1, 1], k=n) # choice plural, Py ≥ 3.6 return [0]+list(accumulate(steps)) # In[16]: get_ipython().run_cell_magic('timeit', '-n 1000', 'walk = random_walk_itertools(1000)\n') # ### Random Walk: solução vetorizada com NumPy # In[17]: import numpy as np np.random.choice([-1, 1], 10) # In[18]: def random_walk_numpy(n): steps = np.random.choice([-1, 1], n) # choice singular! return np.cumsum(steps) # In[19]: get_ipython().run_cell_magic('timeit', '-n 1000', 'walk = random_walk_numpy(1000)\n') # In[21]: plt.plot(random_walk_numpy(1000)) plt.show() # ## Comparando desempenhos # In[22]: from timeit import timeit def cronometrar(expr, vezes=1000): return timeit(expr, globals=globals(), number=vezes) / vezes casos = ['RandomWalker().walk(1000)', 'random_walk(1000)', 'random_walk_itertools(1000)', 'random_walk_numpy(1000)', ] # In[23]: tempos = [] for caso in casos: t = cronometrar(caso) print(f'{t:07f}s', caso, sep='\t') tempos.append(t) # In[24]: fig, ax = plt.subplots() posições = np.arange(len(casos)) ax.barh(posições, tempos) ax.set_yticks(posições) ax.set_yticklabels(casos) plt.show() # In[25]: max(tempos) / min(tempos) # ## Referências # # * [From Python to Numpy](http://www.labri.fr/perso/nrougier/from-python-to-numpy/). Veja também a excelente [bibliografia](http://www.labri.fr/perso/nrougier/from-python-to-numpy/#bibliography) deste livro livre. # # * StackExchange: [How do I move away from the “for-loop” school of thought?](https://softwareengineering.stackexchange.com/questions/254475/how-do-i-move-away-from-the-for-loop-school-of-thought) # # * [Python is the fastest growing programming language due to a feature you've never heard of](https://jeffknupp.com/blog/2017/09/15/python-is-the-fastest-growing-programming-language-due-to-a-feature-youve-never-heard-of/)