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 相关文章推荐
Python selenium文件上传方法汇总
Nov 19 Python
Python 迭代器与生成器实例详解
May 18 Python
python虚拟环境virtualenv的使用教程
Oct 20 Python
Python3安装Scrapy的方法步骤
Nov 23 Python
用Python写一段用户登录的程序代码
Apr 22 Python
python 解压pkl文件的方法
Oct 25 Python
基于wxPython的GUI实现输入对话框(1)
Feb 27 Python
python 使用pygame工具包实现贪吃蛇游戏(多彩版)
Oct 30 Python
python3连接kafka模块pykafka生产者简单封装代码
Dec 23 Python
python实现简易版学生成绩管理系统
Jun 22 Python
Python基于xlutils修改表格内容过程解析
Jul 28 Python
python中pop()函数的语法与实例
Dec 01 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
漫荒推荐:画风超赞的国风漫画推荐 超长假期不无聊
2020/03/08 国漫
php读取目录及子目录下所有文件名的方法
2014/10/20 PHP
Zend Framework教程之分发器Zend_Controller_Dispatcher用法详解
2016/03/07 PHP
PHP文件操作简单介绍及函数汇总
2020/12/11 PHP
(转载)JavaScript中匿名函数,函数直接量和闭包
2007/05/08 Javascript
ASP小贴士/ASP Tips javascript tips可以当桌面
2009/12/10 Javascript
javascript中的array数组使用技巧
2010/01/31 Javascript
Extjs Ext.MessageBox.confirm 确认对话框详解
2010/04/02 Javascript
js中函数声明与函数表达式
2015/06/03 Javascript
JS模式之单例模式基本用法
2015/06/30 Javascript
JavaScript实现LI列表数据绑定的方法
2015/08/04 Javascript
url传递的参数值中包含&amp;时,url自动截断问题的解决方法
2016/08/02 Javascript
js时间控件只显示年月
2017/01/08 Javascript
Node.js微信 access_token ( jsapi_ticket ) 存取与刷新的示例
2017/09/30 Javascript
Vue调试神器vue-devtools安装方法
2017/12/12 Javascript
Javascript将图片的绝对路径转换为base64编码的方法
2018/01/11 Javascript
Vue前后端不同端口的实现方法
2018/09/19 Javascript
详解React项目中碰到的IE问题
2019/03/14 Javascript
微信小程序生成二维码的示例代码
2019/03/29 Javascript
JS实现的雪花飘落特效示例
2019/12/03 Javascript
React实现类似淘宝tab居中切换效果的示例代码
2020/06/02 Javascript
python使用正则表达式匹配字符串开头并打印示例
2017/01/11 Python
详解python 拆包可迭代数据如tuple, list
2017/12/29 Python
代码分析Python地图坐标转换
2018/02/08 Python
python中将\\uxxxx转换为Unicode字符串的方法
2018/09/06 Python
Python内置函数property()如何使用
2020/09/01 Python
HTML5+JS实现俄罗斯方块原理及具体步骤
2013/11/29 HTML / CSS
Berghaus官网:户外服装和设备,防水服
2020/01/17 全球购物
入党转预备思想汇报
2014/01/07 职场文书
医学专业毕业生求职信
2014/06/20 职场文书
数学教研活动总结
2014/07/02 职场文书
助人为乐好少年事迹材料
2014/08/18 职场文书
2015年三八妇女节活动总结
2015/02/06 职场文书
工作简报范文
2015/07/21 职场文书
2015年工商局个人工作总结
2015/07/23 职场文书
利用js实现简单开关灯代码
2021/11/23 Javascript