Numexpr: Fast Array Expressions Without the Memory Bloat
If you've ever written something like (a + b) * c / d in NumPy and watched your memory usage spike, you know the pain. Each intermediate step creates a temporary array, which wastes RAM and slows things down, especially with large datasets. That’s where Numexpr comes in.
Numexpr is a small but powerful library that evaluates array expressions more efficiently than plain NumPy. It does this by combining the entire expression into a single operation, avoiding temporary arrays, and sometimes even using multiple CPU cores. The result? Faster execution, lower memory footprint, and less frustration.
What It Does
At its core, Numexpr works like eval() for NumPy arrays. You give it a string expression like 'a + b * c' and the arrays as local variables. It parses the expression, optimizes execution order, and runs it in a single pass. The output is a new array or scalar.
For example:
import numexpr as ne
import numpy as np
a = np.random.rand(10_000_000)
b = np.random.rand(10_000_000)
c = np.random.rand(10_000_000)
result = ne.evaluate('a + b * c')
That’s it. No temp arrays for b * c or a + (temp). Just one shot.
Why It’s Cool
1. No temporary arrays – This is the killer feature. NumPy creates intermediate arrays for each sub-expression, which can double or triple your memory usage. Numexpr avoids this entirely.
2. Multithreaded execution – By default, Numexpr uses all available CPU cores for heavy numeric operations (like trig, exp, log, etc.). For big arrays, this can mean 2x–4x speedups over plain NumPy.
3. Smart optimization – It recognizes common patterns like division, multiplication, and absolute value, and rearranges operations to minimize work. It also automatically uses look-up tables for certain functions.
4. VM-based evaluation – Under the hood, Numexpr compiles your expression into a virtual machine bytecode and runs that in a tight C loop. This is faster than Python’s eval() and much more memory efficient than NumPy’s vectorization.
5. Minimal syntax overhead – You write exactly the same math you’d write in NumPy, just inside a string. No new DSL or weird operators.
How to Try It
Install it with pip or conda:
pip install numexpr
Or if you use conda:
conda install numexpr
Then open a Python shell or script:
import numexpr as ne
import numpy as np
x = np.linspace(0, 10, 1_000_000)
y = np.sin(x) ** 2 + np.cos(x) ** 2
result = ne.evaluate('y') # Should be ~1 for all elements
# Compare performance
%timeit np.sin(x) ** 2 + np.cos(x) ** 2
%timeit ne.evaluate('sin(x)**2 + cos(x)**2')
You’ll likely see numexpr finish faster and use less memory.
For more complex expressions, you can pass multiple arrays as a dictionary:
ne.evaluate('a**2 + b**2 + 2*a*b', local_dict={'a': a, 'b': b})
Final Thoughts
Numexpr won’t replace NumPy for every task—broadcasting and fancy indexing still need NumPy. But for tight numeric loops, large data pipelines, or memory-constrained environments (like on a laptop or a cloud instance with limited RAM), it’s a no-brainer. It’s also a great tool when you need to run a bunch of heavy math on the CPU and don’t want to reach for Numba or Cython.
Give it a try next time you write a long expression with Pandas or NumPy. Your RAM will thank you.
Follow @githubprojects for more dev-friendly tools and libraries.
Repository: https://github.com/pydata/numexpr