title: Speed comparison. numpy vs python standard
body: <p>I made a few experiment and found a number of cases where python's standard <code>random</code> and <code>math</code> library is faster than <code>numpy</code> counterpart.  </p>
  
  <p>I think there is a tendency that python's standard library is about 10x faster for small scale operation, while <code>numpy</code> is much faster for large scale (vector) operations.  My guess is that <code>numpy</code> has some overhead which becomes dominant for small cases.</p>
  
  <p>My question is: Is my intuition correct?  And will it be in general advisable to use the standard library rather than <code>numpy</code> for small (typically scalar) operations?</p>
  
  <p>Examples are below.</p>
  
  <pre><code>import math
  import random
  import numpy as np
  </code></pre>
  
  <p><strong>Log and exponential</strong></p>
  
  <pre><code>%timeit math.log(10)
  # 158 ns ± 6.16 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
  
  %timeit np.log(10)
  # 1.64 µs ± 93.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
  
  %timeit math.exp(3)
  # 146 ns ± 8.57 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
  
  %timeit np.exp(3)
  # 1.72 µs ± 78.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
  </code></pre>
  
  <p><strong>Generate normal distribution</strong></p>
  
  <pre><code>%timeit random.gauss(0, 1)
  # 809 ns ± 12.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
  
  %timeit np.random.normal()
  # 2.57 µs ± 14.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
  </code></pre>
  
  <p><strong>Choosing a random element</strong></p>
  
  <pre><code>%timeit random.choices([1,2,3], k=1)
  # 1.56 µs ± 55.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
  
  %timeit np.random.choice([1,2,3], size=1)
  # 23.1 µs ± 1.04 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  </code></pre>
  
  <p><strong>Same with numpy array</strong></p>
  
  <pre><code>arr = np.array([1,2,3])
  
  %timeit random.choices(arr, k=1)
  # 1.72 µs ± 33.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
  
  %timeit np.random.choice(arr, size=1)
  # 18.4 µs ± 502 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  </code></pre>
  
  <p><strong>With big array</strong></p>
  
  <pre><code>arr = np.arange(10000)
  
  %timeit random.choices(arr, k=1000)
  # 401 µs ± 6.16 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
  
  %timeit np.random.choice(arr, size=1000)
  # 41.7 µs ± 1.39 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  </code></pre>