python科学计算之numpy——ufunc函数用法


Posted in Python onNovember 25, 2019

写在前面

ufunc是universal function的缩写,意思是这些函数能够作用于narray对象的每一个元素上,而不是针对narray对象操作,numpy提供了大量的ufunc的函数。这些函数在对narray进行运算的速度比使用循环或者列表推导式要快很多,但请注意,在对单个数值进行运算时,python提供的运算要比numpy效率高。

四则运算

numpy提供的四则ufunc有如下一些:

python科学计算之numpy——ufunc函数用法

numpy提供的四则运算unfunc能够大大的提高计算效率,但如果运算式复杂,且参与运算的narray过大,会产生大量的中间结果,从而降低计算效率。例如:计算x=a*b+c时,实际上会按照如下方式计算:

t = a*b 
x = t+c 
del t

这会产生两次内存分配,一次时x,一次时t,所以按照

x = a*b 
x = x+c

会节省一次内存的分配,从而提高效率。

比较运算 & bool运算

numpy同时提供了=、<、>等这些比较运算符,这些运算符的结果是bool值或者bool数组。

python科学计算之numpy——ufunc函数用法

np.array([1,2,3]) < np.array([0,3,4])
array([False, True, True], dtype=bool)

逻辑运算and、or、not、xor等由于python提供了,所以numpy的这些逻辑运算符是以logical_开头的函数

a = np.arange(5)
b= np.arange(4,-1,-1)
## print a==b
[False False True False False]
## print a>b
[False False False True True]
## print np.logical_or(a == b, a > b)
[False False True True True]

对两个bool数组进行逻辑运算时,将发生ValueError异常,因为bool值也是True和False,numpy无法确定运算目的,可以使用numpy.any()和numpy.all()函数,他们的使用方法和python的any()、all()函数用法相同。以bitwise_开头的函数时用于位运算,如(bitwise_and、bitwise_or)等,也可以使用&、|、~和^来进行运算。

除了numpy提供的内置ufunc函数,用户也可以编写自定义的ufunc函数,方式是:

1. 编写对单个数值计算的目的函数;

2. 利用np.frompyfunc(func, nin, nout)将其转换为ufunc函数,其中func是上面编写的目的函数,nin是输入的参数个数,nout是返回值的个数。

## 基本形式
u_func = np.frompyfunc(func,nin,nout)
ret = u_func(narray_obj,param1,param2..)

这里返回的ret是object类型,所以实际上需要用astype()转换为目的类型。numpy.vectorize()也实现了和numpy.frompyfunc()一样的功能,区别是前者可以t通过otypes指定返回值的类型,不用再用astype()进行转换。

## 基本形式
u_func = np.frompyfunc(func,otypes=[dtype1,dtype2..]
ret = u_func(narray_object,param1,param2..)

广播

先看个例子:

a = np.arange(0,60,10).reshape(-1,1)
b = np.arange(0,5)
#a
array([[ 0],
  [10],
  [20],
  [30],
  [40],
  [50]])
#b
array([0, 1, 2, 3, 4])

ok,现在计算a+b,不过现在有一个问题,a和b的维度不一样,那应该怎么加?先看看结果吧

# a+b
array([[ 0, 1, 2, 3, 4],
  [10, 11, 12, 13, 14],
  [20, 21, 22, 23, 24],
  [30, 31, 32, 33, 34],
  [40, 41, 42, 43, 44],
  [50, 51, 52, 53, 54]])

结果来看,是用a的每一行的元素(这里a为列向量,每一行只有一个元素)与b的每一个元素相加,相当于:

a=array([[ 0, 0, 0, 0, 0],
  [10, 10, 10, 10, 10],
  [20, 20, 20, 20, 20],
  [30, 30, 30, 30, 30],
  [40, 40, 40, 40, 40],
  [50, 50, 50, 50, 50]])

而b是一个行向量,现在我们将这一个行向量重复6次,和a的第0轴长度相同,构成一个二维数组,相当于:

b=array([[0, 1, 2, 3, 4],
  [0, 1, 2, 3, 4],
  [0, 1, 2, 3, 4],
  [0, 1, 2, 3, 4],
  [0, 1, 2, 3, 4],
  [0, 1, 2, 3, 4]])

现在,再进行相加,自然就是对用元素相加了,也就是上面的结果,这就是numpy中的广播,对进行运算的两个narray对象shape不一样时,进行的维度补齐。总的来说,numpy的广播规则基于下面4个规则:

让所有输入数姐都向其中维数最多的数组看齐,shape属性中不足的部分都通过在前面加1补齐; 如上面的输入中,a.shape=(6,1),b.shape=(,5),a的维数是2,b的维数是1,所以b向a看齐,并且用1补齐,那么b.shape=(1,5)。

输出数组的shape属性是输入数组的shape属性的各个轴上的最大值 输出是各轴上最大值,所以a+b的输出的shape应该是(6,5);

如果输入数组的某个轴的长度 为 1或与输出数组的对应轴的长度相同,这个数组能够用来计算,否则出错

当输入数组的某个轴的长度为1?迹?刈糯酥嵩怂闶倍加么酥嵘系牡谝蛔橹?/p>

由于广播在numpy计算中比较常见,所以numpy提供了ogrid和mgrid来创建广播计算的数组,前者返回的是两个向量,后者返回的是进行广播运算的数组。

x,y = np.ogrid[:5,:5]
# x
array([[0],
  [1],
  [2],
  [3],
  [4]])
# y
array([[0, 1, 2, 3, 4]])
x,y=np.mgrid[:5,:5]
# x
[[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1],
[2, 2, 2, 2, 2],
[3, 3, 3, 3, 3],
[4, 4, 4, 4, 4]]
#y
[[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]]]

ogrid[]参数是有两种形式(1):[start:end:step]即起点、终点和步长;(2):[start:end:len]即起点、终点和数组长度,这里的长度为了和步长区分,在传入时时以虚数方式传入的,例如[1,5,4j]将产生[1,2,3,4]这样的数组。

另外广播支持特殊的下标None,意义时在对应位置上产生1的新轴,例如a[None,:]等效于a.reshape((1,-1)),a[:,None]等效于a.reshape((-1,1)),另外,np.ix_()能将一维数组转换为能进行广播的二维数组:

x=np.array([0,1,4,10])
y=np.array([2,3,8])
gy,gx=np.ix_(y,x)
#print gy
[[2]
[3]
[8]]
#print gx
[[ 0 1 4 10]]
# gx+gy
array([[ 2, 3, 6, 12],
  [ 3, 4, 7, 13],
  [ 8, 9, 12, 18]])

np.ix_()支持多个参数,从而支持n维空间的广播计算。

ufunc方法

ufunc函数对象本身还有一些方法函数,这些方法只对两个输入、一个输出的ufunc 函数有效,其他的ufunc对象调用这些方法时会抛出ValueError异常。

(1). reduce(),沿着指定轴对数组进行操作,相当于将相应的操作放到该轴元素之间。

np.add.reduce([1,2,3]) #1+2+3=6
np.add.reduce([[1,2,3],[4,5,6]]) #[1+4,2+5,3+6]=[5,7,9]
np.add.reduce([[1,2,3],[4,5,6]],axis=1) #[1+2+3,4+5+6]=[6,15]

(2). accumulate()和reduce()类似,区别时是前者会保留中间结果:

np.add.accumulate([1,2,3]) #[1,1+2,1+2+3]=[1,3,6]
np.add.accumulate([[1,2,3],[4,5,6]],axis=1) 
#
array([[ 1, 3, 6],
  [ 4, 9, 15]])

(3). reduceat()方法计算多纽reduce()的结果,通 过 indices参数指定一系列的起始和终止位置。它的计算有些特别,,计算的方法如下:

if indices[i] < indices[i+1]:
 result[i] = <op>.reduce(a[indices[i]:indices[i+1]])
else:
 result[i] = a[indices[i]]
#result[-1]的计算如下:
<op>.reduce(a[indices[-1]:])

例:

a = np.array([1,2,3,4])
result = np.add.reduceat(a, indices=[0,1,0,2,0,3,0])
## result
array([1,2,3,3,6,4,10])

## 计算过程如下:
 : a[0] -> 1
 : a[1] -> 2
 : a[0] + a[1] -> 1 + 2
 : a[2] -> 3
 : a[0] + a[1] + a[2] -> 1 + 2 + 3 = 6
 : a[3] -> 4
 :a[0] + a[1] + a[2] + a[4] - > 1 + 2 + 3 + 4 = 1 0

再看多维数组

在前一篇文章中我们提到过多维数组,现在我们回头再看看多维数组的下标取数据。首先,多维数组的下标应该是一个长度和数组的维数相同的元组。如栗下标元组的长度比数组的维数大,就会出错;如果小,就 会 在 下 标 元 组 的 后 而 补 ,使得它的长度与数组维数相同。如果下标对象不是元组,则 numpy会首先把它转换为元组。这种转换可能会和用户所希望的不一致,因此为了避免出现问题,请 “显式”地使用元组作为下标。

a = np.arange(3*4*5).reshape(3,4,5)
array([[[ 0, 1, 2, 3, 4],
  [ 5, 6, 7, 8, 9],
  [10, 11, 12, 13, 14],
  [15, 16, 17, 18, 19]],

  [[20, 21, 22, 23, 24],
  [25, 26, 27, 28, 29],
  [30, 31, 32, 33, 34],
  [35, 36, 37, 38, 39]],

  [[40, 41, 42, 43, 44],
  [45, 46, 47, 48, 49],
  [50, 51, 52, 53, 54],
  [55, 56, 57, 58, 59]]])

lidx=[[0],[1]]
#a[lidx]

aidx = np.array(lidx)
#a[aidx]
array([[[[ 0, 1, 2, 3, 4],
   [ 5, 6, 7, 8, 9],
   [10, 11, 12, 13, 14],
   [15, 16, 17, 18, 19]]],


  [[[20, 21, 22, 23, 24],
   [25, 26, 27, 28, 29],
   [30, 31, 32, 33, 34],
   [35, 36, 37, 38, 39]]]])

可以看到,numpy把列表[[0],[1]]转换成元组([0],[1]),而把数组对象转换成(aidx,:,:)。

整数数组和切片做为下标

如果利用数组作为下标,但数组的维度都不一样,那么这个时候这些数组将会应用广播规则把这些数组转换成一样,转换的规则是上面说到的先用1补足然后取各个维度的最大值。

i0 = np.array([[1,2,1],[0,1,0]])
i1 = np.array([[[0]],[[1]]])
i2 = np.array([[[2,3,2]]])
#print i0.shape
(2, 3)
#print i1.shape
(2, 1, 1)
#print i2.shape
(1, 1, 3)
# i0补齐之后为 (1,2,3),然后取最大值为
(2,2,3)

这里将所有的数组进行广播,把所有的数组转换成shape=(2,2,3),利用numpy.broadcast_arrays()可以查看广播后的数组:

id0,id1,id2=np.broadcast_arrays(i0,i1,i2)
#id0
[[[1 2 1]
 [0 1 0]]

 [[1 2 1]
 [0 1 0]]
#id1
[[[0 0 0]
 [0 0 0]]

 [[1 1 1]
 [1 1 1]]]
#id2
[[[2 3 2]
 [2 3 2]]

 [[2 3 2]
 [2 3 2]]]

然后利用下标取元素时,例如i,j,k=1,1,1时,取得的元素应该是a[id0[i,j,k],id1[i,j,k],id2[i,j,k]]=a[1,1,3]=28。下标中含有切片时,首先来看第一种,就是整数数组时连续的,也就是数组之间没有切片,例如a[1:3,i0,i1],这种情况下,首先会把整数数组(i0,i1)广播,然后将切片的长度放到相应的位置构成一个维度,i0,i1广播后的shape=(2,2,3),切片的长度为2,所以最后的shape=(2,2,2,3)。最后的结果是a[1:3,id0[i,j,k],id1[i,j,k]]。再者,如果切片是再整数数组之间,那么同样会将数组广播,然后把切片位置替换为数组的维度或者切片的长度添加到索引的最后面,如a[i0,:,i1],i0,i1广播后的shape=(2,2,3),数组a的第二个轴的长度为4,所以最后的shape=(2,2,3,4)。

bool数组做为下标

用bool数组作为下标时,会将bool数组中为True的索引组成一个整数数组,然后以此数组作为下标。相当于用numpy.nonzero(bool_array)的结果,例如:

b2 = np.array([[True,False,True],[True,False,False]])
np.nonzero(b2)
##
(array([0, 0, 1]), array([0, 2, 0]))
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## 
## 相当于取[0,0],[0,2],[1,0]

除此之外,如果bool数组中有切片,那么相当于将bool值转换成nonzero()后的整数数组,切片位置不变。

以上这篇python科学计算之numpy——ufunc函数用法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python3处理HTTP请求的实例
May 10 Python
Pycharm取消py脚本中SQL识别的方法
Nov 29 Python
对Django外键关系的描述
Jul 26 Python
python中使用while循环的实例
Aug 05 Python
使用pandas的box_plot去除异常值
Dec 10 Python
python opencv圆、椭圆与任意多边形的绘制实例详解
Feb 06 Python
详解python环境安装selenium和手动下载安装selenium的方法
Mar 17 Python
Python作用域与名字空间原理详解
Mar 21 Python
python实现最短路径的实例方法
Jul 19 Python
如何利用Python动态模拟太阳系运转
Sep 04 Python
PyCharm2020最新激活码+激活码补丁(亲测最新版PyCharm2020.2激活成功)
Nov 25 Python
Python 解决空列表.append() 输出为None的问题
May 23 Python
OpenCV里的imshow()和Matplotlib.pyplot的imshow()的实现
Nov 25 #Python
Python解析json代码实例解析
Nov 25 #Python
python实现差分隐私Laplace机制详解
Nov 25 #Python
python3实现弹弹球小游戏
Nov 25 #Python
python数据化运营的重要意义
Nov 25 #Python
python实现拉普拉斯特征图降维示例
Nov 25 #Python
python模块hashlib(加密服务)知识点讲解
Nov 25 #Python
You might like
深入php var_dump()函数的详解
2013/06/05 PHP
学习php设计模式 php实现桥梁模式(bridge)
2015/12/07 PHP
Thinkphp框架开发移动端接口(2)
2016/08/18 PHP
php封装的单文件(图片)上传类完整实例
2016/10/18 PHP
Laravel利用gulp如何构建前端资源详解
2018/06/03 PHP
JavaScript地理位置信息API
2016/06/11 Javascript
真正好用的js验证上传文件大小的简单方法
2016/10/27 Javascript
js实现带三角符的手风琴效果
2017/03/01 Javascript
layui分页效果实现代码
2017/05/19 Javascript
图片加载完成再执行事件的实例
2017/11/16 Javascript
浅析vue中的MVVM实现原理
2019/03/04 Javascript
three.js 如何制作魔方
2020/07/31 Javascript
js+h5 canvas实现图片验证码
2020/10/11 Javascript
如何使用 vue-cli 创建模板项目
2020/11/19 Vue.js
[54:02]2018DOTA2亚洲邀请赛 4.1 小组赛 B组 IG vs VGJ.T
2018/04/03 DOTA
python编写的最短路径算法
2015/03/25 Python
解决nohup重定向python输出到文件不成功的问题
2018/05/11 Python
详解利用Python scipy.signal.filtfilt() 实现信号滤波
2019/06/05 Python
python 图片去噪的方法示例
2019/07/09 Python
django 配置阿里云OSS存储media文件的例子
2019/08/20 Python
Python字典底层实现原理详解
2019/12/18 Python
自定义Django Form中choicefield下拉菜单选取数据库内容实例
2020/03/13 Python
django实现日志按日期分割
2020/05/21 Python
详解python polyscope库的安装和例程
2020/11/13 Python
selenium自动化测试入门实战
2020/12/21 Python
python字典按照value排序方法
2020/12/28 Python
canvas中普通动效与粒子动效的实现代码示例
2019/01/03 HTML / CSS
专门经营化妆刷的美国彩妆品牌:Sigma Beauty
2017/09/11 全球购物
企业为何需要商业计划书
2013/12/26 职场文书
会计专业应届生自荐信
2014/02/07 职场文书
产品推广策划方案
2014/05/10 职场文书
服务明星事迹材料
2014/12/29 职场文书
分享:关于学习的励志名言赏析
2019/08/16 职场文书
vue中data改变后让视图同步更新的方法
2021/03/29 Vue.js
Apache Pulsar集群搭建部署详细过程
2022/02/12 Servers
box-shadow单边阴影的实现
2023/05/21 HTML / CSS