NumExpr:加速Python数值计算,比NumPy快6倍的秘密武器
近日,一位数据科学家发现了一个被称为“NumExpr”的库,声称其在某些复杂的数值计算上比NumPy快15倍。NumPy作为Python数值计算的基石,在数据科学领域中占据了主导地位,广泛应用于机器学习、数据探索和模型训练。NumExpr能否挑战这一霸主地位引起了广泛关注,因此决定进行实际测试以验证其性能。 什么是NumExpr? NumExpr是一个快速的数值表达式求值器,专为NumPy设计。它通过优化内存使用和多线程处理,使数组操作更加快速。据其GitHub页面介绍,NumExpr可以显著减少计算所需的时间和内存消耗,尤其在多核CPU上表现更为出色。 设置开发环境 为了测试NumExpr,作者建议创建一个独立的Python环境来安装必要的库。可以使用conda或Miniconda来创建和管理环境,步骤如下: 创建新的开发环境并安装所需的库: (base) $ conda create -n numexpr_test python=3.12 -y (base) $ conda activate numexpr_test (numexpr_test) $ pip install numexpr (numexpr_test) $ pip install jupyter 启动Jupyter Notebook: 在命令行输入 jupyter notebook,之后浏览器会自动打开Jupyter Notebook界面。如果未自动打开,可以在命令行输出的信息中找到URL手动打开。 性能对比测试 示例1:简单数组加法 首先,测试了简单的大数组加法运算,运行5000次: NumPy版本: python time_np_expr = timeit.timeit(lambda: 2*a + 3*b, number=5000) print(f"NumPy执行时间:{time_np_expr} 秒") 结果:12.036807 秒 NumExpr版本: python time_ne_expr = timeit.timeit(lambda: ne.evaluate("2*a + 3*b"), number=5000) print(f"NumExpr执行时间:{time_ne_expr} 秒") 结果:1.807596 秒 NumExpr在这个例子中表现出色,速度提升了约6倍。 示例2:蒙特卡洛模拟计算π 接下来,使用蒙特卡洛模拟计算π值,运行1000次: NumPy版本: python time_np_expr = timeit.timeit(lambda: monte_carlo_pi_numpy(num_samples), number=1000) print(f"NumPy执行时间:{time_np_expr} 秒") 结果:10.642844 秒 NumExpr版本: python time_ne_expr = timeit.timeit(lambda: monte_carlo_pi_numexpr(num_samples), number=1000) print(f"NumExpr执行时间:{time_ne_expr} 秒") 结果:8.077501 秒 在这个例子中,虽然NumExpr没有达到同样显著的速度提升,但也实现了约20%的改进。原因是NumExpr在SUM()函数方面尚未优化。 示例3:Sobel图像滤波器 然后,实现了用于图像边缘检测的Sobel滤波器: NumPy版本: python time_np_sobel = timeit.timeit(lambda: sobel_filter_numpy(image), number=100) print(f"NumPy执行时间:{time_np_sobel} 秒") 结果:8.093792 秒 NumExpr版本: python time_ne_sobel = timeit.timeit(lambda: sobel_filter_numexpr(image), number=100) print(f"NumExpr执行时间:{time_ne_sobel} 秒") 结果:4.938702 秒 NumExpr在这个场景中的性能接近于NumPy的两倍,效果显著。 示例4:傅里叶级数近似 最后,测试了傅里叶级数近似计算复杂周期函数的问题: NumPy版本: python start_time = time.time() approx_np = np.zeros_like(t) for n in range(1, n_terms + 1, 2): approx_np += (4 / (np.pi * n)) * np.sin(2 * np.pi * n * 5 * t) numpy_time = time.time() - start_time print(f"NumPy傅里叶级数时间:{numpy_time:.6f} 秒") 结果:7.765800 秒 NumExpr版本: python start_time = time.time() approx_ne = np.zeros_like(t) for n in range(1, n_terms + 1, 2): approx_ne = ne.evaluate("approx_ne + (4 / (pi * n)) * sin(2 * pi * n * 5 * t)", local_dict={"pi": pi, "n": n, "approx_ne": approx_ne, "t": t}) numexpr_time = time.time() - start_time print(f"NumExpr傅里叶级数时间:{numexpr_time:.6f} 秒") 结果:1.553160 秒 在这个例子中,NumExpr再次展现出强大的优势,速度提高了约5倍。 总结 通过对多个示例的测试,可以看出NumExpr在某些数值计算任务中确实比NumPy更快,尤其是在多核CPU环境下。虽然没有完全达到官方声称的15倍加速,但几倍甚至10倍的性能提升已经相当可观。对于需要高性能数值计算的数据科学家和研究人员来说,NumExpr是一个值得尝试的工具。尽管NumExpr不支持所有NumPy操作,但在测试中几乎没有发现负面影响。 业内人士评价与公司背景 NumExpr的开发和维护主要由Python科学计算社区成员承担,该社区一直致力于提升Python的性能和功能。NumExpr在多线程处理和内存管理方面的优化为其赢得了好评。一些资深数据科学家表示,NumExpr在处理大规模数据集时特别有用,能够在不牺牲代码可读性的前提下大幅提升计算效率。