NumExpr简单使用及适用范围

NumExpr作用:

通俗易懂的解释一下: 如 a+b+c 操作,一般情况是  a+b 是一个操作,把结果临时存起来 然后 再执行+c操作; 但是NumExpr 通过内置的一系列编译优化为 a+b+c; 节省了 中间的a+b的结果临时存起来这个操作,从而节省内存;

NumExpr在连续的数学运算上优化效果比较好;

 

安装方式:

pip install numexpr

 

适用范围:

支持运算符如下:

  • 逻辑运算符: &, |, ~
  • 比较运算符: <, <=, ==, !=, >=, >
  • 一元算术运算符: -
  • 二进制算术运算符: +, -, *, /, **, %, <<, >>

支持的函数如下:

  • where(bool, number1, number2): number – number1 if the bool condition is true, number2 otherwise.
  • {sin,cos,tan}(float|complex): float|complex – trigonometric sine, cosine or tangent. [三角正弦、余弦或正切。]
  • {arcsin,arccos,arctan}(float|complex): float|complex – trigonometric inverse sine, cosine or tangent. [反三角正弦、余弦或正切]
  • arctan2(float1, float2): float – trigonometric inverse tangent of float1/float2. [float1/float2的三角反切线]
  • {sinh,cosh,tanh}(float|complex): float|complex – hyperbolic sine, cosine or tangent.[双曲正弦、余弦或正切]
  • {arcsinh,arccosh,arctanh}(float|complex): float|complex – hyperbolic inverse sine, cosine or tangent.[双曲反正弦、余弦或正切]
  • {log,log10,log1p}(float|complex): float|complex – natural, base-10 and log(1+x) logarithms.[自然对数、10进制对数和对数(1+x)]
  • {exp,expm1}(float|complex): float|complex – exponential and exponential minus one.[指数和指数减一]
  • sqrt(float|complex): float|complex – square root.[平方根]
  • abs(float|complex): float|complex – absolute value.[绝对值]
  • conj(complex): complex – conjugate value.[共轭值]
  • {real,imag}(complex): float – real or imaginary part of complex.[复数的实部或虚部]
  • complex(float, float): complex – complex from real and imaginary parts.[由实部和虚部复合而成]
  • contains(str, str): bool – returns True for every string in op1 that contains op2.[对于op1中包含op2的每个字符串,返回True]

 

使用示例:

在一个复杂的有理函数表达式中加入更多的数组。假设,我们想计算下面涉及5个Numpy数组的值,每个数组都有100万个随机数(从正态分布抽取):

我们创建一个形状(1000000,5)的Numpy数组,并从中提取5个向量(1000000,1)用于有理函数:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import timeit

import numexpr as ne
import numpy as np

a = np.random.normal(size=(1000000, 5))
a1, a2, a3, a4, a5 = a[:, 0], a[:, 1], a[:, 2], a[:, 3], a[:, 4]


def tight_loop_very_slow():
    """
    """
    c = (a1 ** 2 + 2 * a2 + (3 / a3)) / (np.sqrt(a4 ** 2 + a5 ** 2))


def tight_loop_slow():
    """
    使用 numexpr 计算
    """
    c = ne.evaluate("(a1**2+2*a2+(3/a3))/(sqrt(a4**2+a5**2))")


if __name__ == '__main__':
    number = 100
    x = timeit.timeit(stmt="tight_loop_very_slow()", number=number, globals=globals())
    print(x)
    x = timeit.timeit(stmt="tight_loop_slow()", number=number, globals=globals())
    print(x)

运行结果如下:

发现 使用 NumExpr快了8倍;

 

总结:

  • NumExpr虽然能通过减少临时变量的个数及利用多核cpu来提升速度;但是 注意 要结合实际的 被计算 的数据量进行评估; 如 矩阵元素数量过少的话,NumExpr自身的 字符串编译成矢量操作及 额外的代码 增加了 CPU的指令数,反而增加了耗时(相当于 耗时的装炮弹,结果是打蚊子); 因此 对于需要优化的代码 要结合数据量 并使用 timeit 进行最小改动 范围的测试比较;
  • NumExpr所能操作的 numpy函数非常少; 使用范围有限; 
  • 如上代码示例中, 在使用 NumExpr时 sqrt 前面不要写成  np.sqrt 否则报错;
  • 代码修改幅度较小;

 

相关链接:

https://numexpr.readthedocs.io/en/latest/index.html

https://blog.csdn.net/weixin_38754123/article/details/106935084

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值