Question bank — Vectorization — avoiding Python loops, speed comparison
This bank drills the boundary cases and misconceptions from the parent note: Vectorization. For the machinery behind each answer see NumPy Arrays vs Python Lists, Broadcasting Rules, Universal Functions (ufuncs), Big-O Complexity, Numba and Cython, and Memory Layout and Cache.
Notation used in this bank
Several traps below reuse the parent note's time model, so let's pin the symbols down before any of them appear. The Greek letter (tau) just means "time per one element" — a per-element cost measured in nanoseconds.
So and are just the two concrete values that the generic takes in the Python-loop case versus the vectorized case. Every formula below uses exactly these.
Look at the picture below before reading on — it shows why this ratio starts small (setup dominates) and climbs to a ceiling as grows.

True or false — justify
Vectorization makes the algorithm asymptotically faster (better Big-O).
A vectorized operation is always faster than the equivalent Python loop.
np.vectorize(f) compiles your Python function f into fast machine code.
f per element; the speed is barely above a hand-written loop. Real compilation needs ufuncs or Numba and Cython.Iterating with for x in numpy_array is at least as fast as iterating a Python list.
float64 must be boxed into a np.float64 object every step, adding overhead a list never pays.a[a < 0] = 0 and the loop version for i: if a[i]<0: a[i]=0 give the same result.
Building an array by calling np.append in a loop is total, like list.append.
np.append reallocates and copies the whole array every call, giving — worse than a list. Collect in a list then np.array once.When each element needs heavy work (say sin then exp), the absolute time saved by vectorizing is larger than for plain addition.
At very large , doubling the CPU clock speed will roughly halve a vectorized array-add.
Spot the error
out = np.array([]); for x in data: out = np.append(out, x*x) — what's wrong?
np.append copies the growing array each iteration () and you still loop in Python. Use out = data**2.M = [[u+v for v in col] for u in row] was "vectorized" to M = row + col. Why is that wrong?
row + col does an element-wise sum of equal-length vectors, not the outer/pairwise matrix. You need broadcasting: row[:,None] + col[None,:]. See Broadcasting Rules and the figure below.Someone writes total = 0; for x in arr: total += x and calls it fast because arr is a NumPy array. Error?
arr.sum(), which accumulates in C and may use SIMD.result = np.vectorize(my_slow_python_fn)(big_array) is submitted as an optimization. Error?
np.vectorize doesn't compile anything — it's a Python-level loop, so my_slow_python_fn runs once per element just as slowly. Rewrite with ufuncs or Numba and Cython.To "speed up", a coder replaces a + b with np.array([a[i]+b[i] for i in range(len(a))]). Error?
a + b.data.append(x) is used on a NumPy array inside a loop. Error?
ndarray has no .append method (that's a list method); the correct free function np.append also copies. Pre-allocate np.empty(N) and fill by index instead.
Why questions
Why does the speedup ratio rise as grows?
Why is a raw float64 in a NumPy array cheaper to add than a Python int?
Why can pre-allocating np.empty(N) and filling it beat growing an array?
Why does the assignment a[a < 0] = 0 remove the branch from Python?
a < 0 builds an entire boolean array in compiled C, and the masked assignment writes the matching elements in C too — so the per-element if decision never returns to the Python interpreter.Why does vectorization rely on arrays being contiguous in memory?
Why might numba beat pure NumPy for a complicated per-element formula?
numba can fuse the whole formula into one compiled loop, cutting memory passes. See Numba and Cython.
Edge cases
For , does vectorizing a + b help?
What happens to the speedup when the vectorized op becomes memory-bandwidth bound?
Two arrays of shapes (4,) and (3,) are added — what occurs?
ValueError rather than looping silently. See Broadcasting Rules.Is a[a < 0] = 0 still valid if no element is negative?
False, so zero elements are written; the operation is a harmless no-op, not an error.What does a + b return when both a and b are empty arrays (length 0)?
Does an empty array trigger memory-bound behavior, and can you broadcast (0,) with (3,)?
(0,) with (3,) fails with a ValueError since and neither axis is 1; only (0,) with (1,) or another (0,) broadcasts.Does vectorizing help when each iteration depends on the previous result (e.g. x[i] = x[i-1]*r)?
np.cumprod/cumsum-style scans or Numba and Cython for a compiled loop.If two vectors already have length 1, is broadcasting them meaningful?
a[:,None]+b[None,:] still produces a valid (1×1 or larger) grid with no error.Connections
- Vectorization — avoiding Python loops, speed comparison — the parent concepts these traps test.
- NumPy Arrays vs Python Lists — why boxed objects are the slow part.
- Broadcasting Rules — shape-mismatch edge cases above.
- Big-O Complexity — constant-factor vs growth-order distinction.
- Numba and Cython — when true compilation beats plain NumPy.
- Memory Layout and Cache — the bandwidth ceiling on speedups.