
大家好 这里是「代码简单说」`,欢迎大家关注同名公众号,不定时更新更多实用有趣的教程 也欢迎大家在评论区一起讨论交流!~
关键词:NumExpr教程、NumExpr安装、NumExpr使用方法、NumPy性能优化、Python科学计算加速、数组计算加速、多线程计算、MKL优化、NumExpr与NumPy对比

在处理大规模数据分析、机器学习预处理、科学计算时,很多开发者都会遇到一个问题:
c = a * b - 4.1 * a > 2.5 * b这类代码写起来简单,但当数组达到几百万甚至上亿条数据时,计算速度和内存占用都会成为瓶颈。
最近在优化一个数据分析项目时,发现了一个专门用于加速 NumPy 表达式计算的库——NumExpr。
官方测试数据显示:
今天就详细介绍一下这个性能神器。
NumExpr 是一个专门为 NumPy 数组计算设计的高性能表达式求值器(Numerical Expression Evaluator)。
项目地址:
https://github.com/pydata/numexpr官方文档:
https://numexpr.readthedocs.io/它能够直接解析字符串形式的数学表达式:
"3*a+4*b"然后通过内部虚拟机执行计算。
相比 NumPy 传统运算方式:
result = 3 * a + 4 * bNumExpr 具有以下优势:
特性 | NumPy | NumExpr |
|---|---|---|
避免中间数组 | ❌ | ✅ |
CPU缓存优化 | ❌ | ✅ |
多线程计算 | 有限 | ✅ |
MKL加速 | 部分支持 | ✅ |
大数组性能 | 一般 | 优秀 |
很多开发者以为:
a * b + c只是一条运算。
实际上 NumPy 内部通常会经历:
temp = a * b
result = temp + c产生一个中间数组:
a
b
↓
temp
↓
result如果数组很大:
100000000那么:
额外内存 = 100000000 × 8 Byte
≈ 800MB仅临时变量就可能占用数百 MB 内存。
NumExpr不会创建完整中间数组。
而是:
数组
↓
切块(chunk)
↓
CPU缓存
↓
计算
↓
输出结果例如:
100000000元素被拆分为:
Chunk1
Chunk2
Chunk3
...每块放入 CPU Cache 后计算。
优点:
NumExpr并不是直接调用Python解释器。
执行流程:
表达式字符串
↓
解析器(Parser)
↓
生成Opcode
↓
虚拟机(VM)
↓
多线程执行
↓
返回结果例如:
"a*b-4.1*a>2.5*b"会被转换成内部操作码。
随后:
CPU核心1 → Chunk1
CPU核心2 → Chunk2
CPU核心3 → Chunk3
CPU核心4 → Chunk4并行执行。
因此在多核CPU上性能提升非常明显。
最简单方式:
pip install numexpr查看版本:
python -c "import numexpr;print(numexpr.__version__)"如果使用:
推荐:
conda install numexpr因为 Conda 版本通常自带 MKL 支持。
执行:
python -c "import numexpr; numexpr.test()"如果看到:
OK说明安装成功。
import numpy as np
import numexpr as ne创建测试数据:
a = np.arange(1000000)
b = np.arange(1000000)NumPy:
a + 1NumExpr:
ne.evaluate("a + 1")输出:
array([
1.,
2.,
3.,
...
1000000.
])NumPy:
a * b - 4.1 * a > 2.5 * bNumExpr:
ne.evaluate(
"a * b - 4.1 * a > 2.5 * b"
)返回:
array([
False,
False,
...
True
])复杂表达式通常能获得更明显加速。
NumExpr支持大量数学运算。
例如:
ne.evaluate(
"sin(a) + arcsinh(a/b)"
)结果:
array([...])支持:
函数类型 | 示例 |
|---|---|
三角函数 | sin、cos、tan |
反三角函数 | arcsin、arccos |
指数函数 | exp |
对数函数 | log |
双曲函数 | sinh、cosh |
平方根 | sqrt |
绝对值 | abs |
很多人不知道:
NumExpr还支持字符串比较。
s = np.array([
b'abba',
b'abbb',
b'abbcdef'
])判断:
ne.evaluate(
"b'abba' == s"
)结果:
array([
True,
False,
False
])import numpy as np
import time
a = np.random.rand(10000000)
b = np.random.rand(10000000)
start = time.time()
result = a * b - 4.1 * a > 2.5 * b
print(time.time() - start)import numexpr as ne
import numpy as np
import time
a = np.random.rand(10000000)
b = np.random.rand(10000000)
start = time.time()
result = ne.evaluate(
"a*b-4.1*a>2.5*b"
)
print(time.time() - start)官方给出的经验数据:
表达式复杂度 | 性能提升 |
|---|---|
a+1 | 0.95x~1.5x |
a+b+c+d | 1.5x~2.5x |
ab-4.1a>2.5*b | 2x~4x |
复杂数学函数 | 5x~15x |
NumExpr支持:
Intel MKL
Intel VML即:
Math Kernel Library
Vector Math Library对于:
sin()
cos()
exp()
log()等函数可进一步提升速度。
创建:
site.cfg配置MKL路径:
[mkl]
library_dirs = ...
include_dirs = ...重新编译:
pip install .编译日志中会显示:
MKL detected说明启用成功。
NumExpr最强大的特性之一:
自动多线程计算时能够同时使用:
CPU核心1
CPU核心2
CPU核心3
CPU核心4
...例如:
import numexpr as ne
print(
ne.detect_number_of_cores()
)输出:
16设置线程数:
ne.set_num_threads(8)查看线程数:
ne.get_num_threads()从:
CPython 3.13开始提供 Free Threading 版本。
即:
无GIL模式NumExpr已经能够在这种环境下运行。
官方建议:
使用:
Python主线程
+
NumExpr内部多线程使用:
多个Python线程
+
NumExpr单线程避免:
线程过度订阅
(Oversubscription)导致性能下降。
Pandas底层大量使用NumPy:
DataFrame
Series大规模筛选时收益明显。
例如:
矩阵计算
统计分析
数值模拟特征工程:
归一化
标准化
数学变换指标计算:
RSI
MACD
KDJ
ATR需要处理大量时间序列数据。
项目 | NumPy | NumExpr |
|---|---|---|
易用性 | ★★★★★ | ★★★★☆ |
生态 | ★★★★★ | ★★★☆☆ |
简单运算 | ★★★★★ | ★★★★☆ |
复杂表达式 | ★★★☆☆ | ★★★★★ |
内存占用 | ★★★☆☆ | ★★★★★ |
多线程能力 | ★★☆☆☆ | ★★★★★ |
超大数组计算 | ★★★☆☆ | ★★★★★ |
NumExpr 是一个专门针对 NumPy 数组表达式优化的高性能计算库。
核心优势包括:
如果你的项目中存在大量类似:
a*b+c*d-esin(x)+log(y)(a>0)&(b<100)这样的 NumPy 数组计算,那么 NumExpr 是非常值得引入的性能优化工具。
项目地址:
资源 | 链接 |
|---|---|
GitHub | https://github.com/pydata/numexpr |
官方文档 | https://numexpr.readthedocs.io/ |
PyPI | https://pypi.org/project/numexpr/ |
对于数据分析、机器学习、量化计算以及科学计算场景,NumExpr 往往只需极少代码改动,就能获得可观的性能提升。