numpy randn 和_numpy.random随机选择数组元素如何更高效

v2-6d5eb5e7ea0d29cdf7cb48474e49901a_1440w.jpg?source=172ae18b

最近在看代码库rlkit时,发现一句有意思的代码和注释(如下所示),大意是从列表中随机选择一个元素时使用np.random.randint比np.random.choice更加高效,相关的解释是np.random.choice会进行一些不必要的复制操作,使得效率相较于randint低一些。

possible_future_obs_idxs 

我做了相关的实验进行对比,发现使用np.random.random的实现比np.random.randint更快,并且是否使用参数size=1对结果的影响也很大,文末进行了总结。

1. random, randint, choice

生成长度为1e6的随机array,从中随机选择1个数和1000个数,比较两种情况下运行速度,测试代码如下:

import 

进行1e6次的实验结果(单位:s):

v2-3c7327daf8dced939197273cd094aafc_b.jpg

更直观的使用ipython的%timeit的结果:

import 

以上实验结果在不同环境中跑会有些许误差,但是应该能得到以下结论:

  • 随机选择一个数时,random最快,速度是randint的2倍;
  • 随机选择一个数时,不指定size=1的参数更快,以random为例,速度差异能到5倍左右;
  • 随机选择n个数时,指定size=n,randint最快。

以下是我的猜测和解释,如有问题欢迎指出:

  • choice会有内存申请和复制array的操作,通常是最慢的;
  • 指定size会有内存申请的操作,并且会转化为ndarray类型,因此产生一个随机数时不指定size=1更快;
  • random的输出是python的float类型,指定size后是ndarray类型,乘以N时,float类型和N都直接进行python的float类型运算,而ndarray乘以N多进行了数据转化和传递操作(转化为numpy的类型并传入底层进行运算,可以参考这个问题https://www.zhihu.com/question/24789359/answer/55643155),randint内部实现其实是一样的,但是乘以N的操作本身是在numpy的类型中进行的,减少了两次数据转化和传递,速度更快。
>>> 

为了让大家体会到数据格式转化的耗时,补充一个实验,注意上面是np.random.random()乘以的是python的常数,均为python内置数据类型的运算,而如果乘以的是numpy数据类型,结果可能不一样:

import 

因为涉及到数据格式转化和向底层代码的数据传递,简单的python内置运算可能比numpy更快,当运算较多时,numpy并行的优势才能显示出来。

2. 案例优化

我们以rlkit的这段代码为例进行优化,该段代码的目的是从不等长的列表组里对每个列表随机选择1个数据。这个案例特殊的地方在于列表组里有N个不等长的子列表,还要考虑循环处理子列表的时间,使用numpy并行进行向量对应位相乘速度更快,选择random_idx的过程能够加速80倍左右。

import 

3. Take Away

  • numpy的运算会涉及到数据格式转化和向底层代码的数据传递,当运算比较少时python内置运算可能比numpy更快,所以要注意运算量的类型,numpy的优势在于大规模的并行计算;
  • 随机选择一个数时,尽量避免设置size=1,不设置size的运行速度从快到慢为:random > randint > choice;
  • 随机选择n个数时,由于randint(size=n)内置了random(size=n) * N的操作,比外部实现的random(size=n) * N少了两次数据转化而更快,速度从快到慢为:randint > random > choice。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值