整体操作numpy数组的方法

Python算法之旅

共 5403字,需浏览 11分钟

 ·

2022-01-05 12:28


说在前面

numpy数组的强大之处在于它可以对数组进行整体操作,代码简明,执行速度快。下面我们就来看看整体操作numpy数组的一些常用方法和经典案例。

 bae72b5a77eb345a369b3a6198334b1f.webp


1.  numpy数组与标量的运算

numpy数组支持与标量的加、减、乘、除和幂等算术运算,计算结果为一个新数组,其元素为标量与原数组每个元素进行计算的结果。演示代码如下:

>>> a = np.arange(8)>>> a.shape = (2, 4) #修改数组形状为2行4列>>> aarray([[0, 1, 2, 3],       [4, 5, 6,7]])>>> a + 2array([[2, 3, 4, 5],       [6, 7, 8,9]])>>> a - 2array([[-2, -1, 0,  1],       [ 2,  3, 4,  5]])>>> a * 2array([[ 0, 2,  4,  6],       [ 8, 10,12, 14]])>>> a / 2array([[0. , 0.5, 1. , 1.5],       [2. ,2.5, 3. , 3.5]])>>> a // 2array([[0, 0, 1, 1],       [2, 2, 3,3]], dtype=int32)>>> a % 2array([[0, 1, 0, 1],       [0, 1, 0,1]], dtype=int32)>>> a ** 2 #分别计算0**2,1**2,2**2,…,7**2array([[ 0, 1,  4,  9],       [16, 25,36, 49]], dtype=int32)>>> 2 ** a #分别计算2**0,2**1,2**2,…,2**7array([[ 1,   2,   4,  8],       [16,  32, 64, 128]], dtype=int32)
2.      numpy 数学函数和算术函数

numpy 包含大量的各种数学运算的函数,包括三角函数,算术运算的函数,复数处理函数等。

numpy 提供了标准的三角函数:sin()cos()tan()arcsin()arccos()arctan()函数返回给定角度的 sincos tan 的反三角函数。这些函数的结果可以通过 numpy.degrees() 函数将弧度转换为角度。

numpy.abs() 函数返回各元素的绝对值。

numpy.around() 函数返回指定数字的四舍五入值。

numpy.floor()函数返回小于或者等于指定表达式的最大整数,即向下取整。

numpy.ceil()函数返回大于或者等于指定表达式的最小整数,即向上取整。

numpy.reciprocal()函数返回各元素的倒数,如1/4 倒数为 4/1

3. numpy数组与数组的运算

(1)形状相同的数组进行算术运算。

可以对两个形状相同的numpy数组进行算术运算,得到一个新数组,其元素的值为原来的两个数组中对应位置上元素进行运算的结果。演示代码如下:

>>> a =np.array([[1,3,5,7,9],[2,4,6,8,10]])>>> aarray([[ 1,  3, 5,  7,  9],      [ 2,  4,  6,  8,10]])>>> b =  np.array([[1,2,3,4,5],[10,9,8,7,6]])>>> barray([[ 1,  2, 3,  4,  5],      [10,  9,  8, 7,  6]])>>> a + barray([[ 2,  5,  8,11, 14],      [12, 13, 14, 15, 16]])>>> a - barray([[ 0,  1, 2,  3,  4],      [-8, -5, -2,  1,  4]])>>> a * barray([[ 1,  6, 15, 28, 45],      [20, 36, 48, 56, 60]])>>> a / barray([[1.        , 1.5       , 1.66666667, 1.75      , 1.8       ],      [0.2       , 0.44444444, 0.75      , 1.14285714, 1.66666667]])>>> a % barray([[0, 1, 2, 3, 4],      [2, 4, 6, 1, 4]], dtype=int32)>>> a ** barray([[      1,      9,     125,    2401,  59049],      [   1024,  262144, 1679616, 2097152, 1000000]],dtype=int32)

(2)numpy数组广播机制。

当运算中的 2个数组的形状不同时,numpy将自动触发广播机制。演示代码如下:

>>> a = np.array([[ 0, 0,0],[10,10,10],[20,20,20],[30,30,30]])>>> b = np.array([1,2,3])>>> a + barray([[ 1, 2,  3],       [11, 12,13],       [21, 22,23],       [31, 32,33]])


图1-2展示了数组b如何通过广播来与数组a兼容。

237185997f63240f57ebc5d64596df15.webp

图1-2

注意:若想要两个数组通过广播机制来实现兼容,则其中某个数组的维度必须为1(即只有1行或1列);若条件不满足,则抛出异常。演示代码如下:

>>> a =np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])>>> b = np.array([[1],[2],[3],[4]])>>> a + barray([[ 2, 3,  4,  5],       [ 7,  8,  9,10],       [12, 13,14, 15],       [17, 18,19, 20]])>>> c = np.array([[1, 2],[3, 4]])>>> a + cTraceback (most recent call last):  File"", line 1, in <module>    a + cValueError: operands could not be broadcast togetherwith shapes (4,4) (2,2)


(3)连接数组。

concatenate()函数用于沿指定轴连接相同维度的两个或多个数组,函数格式如下:

np. concatenate((a1, a2, ...), axis=0)

其中a1, a2, ...表示多个相同维度的数组;axis表示沿着它连接数组的轴,值为0时增加行数,值为1时增加列数。演示代码如下:

>>> a = np.array([[1,2],[3,4],[5,6]])>>> aarray([[1, 2],       [3, 4],       [5, 6]])>>> b = np.array([[4, 5],[6,7]])>>> barray([[4, 5],       [6, 7]])>>> np.concatenate((a,b),axis=0) #沿轴0连接两个数组,要确保列数相同array([[1, 2],       [3, 4],       [5, 6],       [4, 5],       [6, 7]])>>> c = np.array([[1],[2],[3]])>>> carray([[1],       [2],       [3]])>>> np.concatenate((a,c),axis=1) #沿轴1连接两个数组,要确保行数相同array([[1, 2, 1],       [3, 4,2],       [5, 6,3]])


4.  numpy数组条件筛选函数

(1)where()函数

与使用布尔索引访问数组类似,numpy模块提供了where()函数来返回数组中满足条件的索引数组,或根据数组中的元素是否满足指定条件来决定取值x还是y,其语法格式如下:

numpy.where(condition[,x,y])

该函数有一个必选参数condition,通过判断原数组的每个元素是否满足条件,返回一个由满足条件的元素的索引构成的数组;x,y是可选参数,如果条件为真,则返回x,否则返回y。

如果只有一个condition参数,则该函数返回索引数组,或者是由索引数组构成的元组(多维数组);如果是有三个参数,则返回由x和y值构成的数组。演示代码如下:

>>> a = np.arange(1, 11)>>> aarray([ 1,  2, 3,  4,  5, 6,  7,  8,  9,10])>>> np.where(a % 2 == 1)  #提供1个参数,只返回满足条件的索引数组(array([0, 2, 4, 6, 8], dtype=int64),)>>> a[np.where(a % 2 ==1)]  #使用索引重构原数组array([1, 3, 5, 7, 9])>>> np.where(a % 2 == 1, 1,0)  #提供3个参数,满足条件取值1,否则取值0array([1, 0, 1, 0, 1, 0, 1, 0, 1, 0])>>>a=np.array([[1,2,3,4,5],[2,3,4,5,6],[3,4,5,6,7],[4,5,6,7,8]]) #二维数组>>> aarray([[1, 2, 3, 4,5],       [2, 3, 4, 5, 6],       [3, 4, 5, 6, 7],       [4, 5, 6, 7, 8]])>>> i =np.where((a>4) & (a<7)) #提供1个参数,只返回满足条件的索引数组>>> i #因为a是二维数组,故i为由索引数组构成的元组,分别存储了满足条件的数组元素的行索引和列索引(array([0, 1, 1, 2,2, 3, 3], dtype=int64), array([4, 3, 4, 2, 3, 1, 2], dtype=int64))>>> a[i] #使用索引重构原数组,相当于使用整数数组索引访问数组array([5, 5, 6, 5,6, 5, 6])>>> a[[0,1, 1, 2, 2, 3, 3],[4, 3, 4, 2, 3, 1, 2]] #使用整数数组索引访问数组array([5, 5, 6, 5,6, 5, 6])>>> np.where(a % 2 == 1, 1, 0)#提供3个参数,满足条件取值1,否则取值0array([[1, 0, 1, 0, 1],      [0, 1, 0, 1, 0],      [1, 0, 1, 0, 1],      [0, 1, 0, 1, 0]])>>> np.where(a % 2 == 1, a*2, a//2) #提供3个参数,奇数翻倍,偶数减半array([[ 2, 1,  6,  2, 10],       [ 1,  6,  2,10,  3],       [ 6,  2, 10, 3, 14],       [ 2,10,  3, 14,  4]])


2piecewise()函数

piecewise()函数用来筛选满足不同条件的元素,函数格式如下:

np.piecewise(x, condlist, funclist,*args, **kw)

关键参数说明:

x表示要进行操作的对象;condlist表示要满足的条件列表,可以是多个条件构成的列表;funclist是执行的操作列表,它与参数condlist是对应的,当条件为True时,则执行相对应的操作函数。返回一个array对象,和原始操作对象x具有完全相同的维度和形状。

例如,随机生成一个numpy数组a存储学生成绩,为学生设置1、2、3、4四个等级;临界分数分别为60、80和90分。演示代码如下:

a = np.random.randint(0, 101, 6)print(a)b = np.piecewise(a,[a<60,((60<=a)&(a<80)),((80<=a)&(a<90)),a>=90],[1, 2,3, 4])print(b)


5. 批量处理numpy数组案例分析

(1)随机生成一个二维numpy数组a,将数组中小于0的置零大于零的保留原值。

参考代码如下:

a = np.random.randint(-10, 10, (2, 3)) #生成2行3列元素值介于[-10,10)的随机整数print(a)#方法一:where()函数b = np.where(a>0, a, 0)print(b)#方法二:abs()函数b = (a + np.abs(a)) // 2print(b)#方法三:布尔索引a[a<0] = 0print(a)


(2)随机生成一个二维numpy数组a,对数组元素做y=2*x*x-3*x+5的运算(连续函数)。

参考代码如下:

a = np.random.randint(-10, 10, (2, 3)) #生成23列元素值介于[-10,10)的随机整数print(a)def fun(x): #连续函数    return2*x*x-3*x+5b = fun(a)print(b)


(3)随机生成一个二维numpy数组a,对数组元素做y=4*x-3(x>0),y=2*x+6(x<=0)的运算(非连续函数)。

参考代码如下:

a = np.random.randint(-10, 10, (2, 3)) #生成2行3列元素值介于[-10,10)的随机整数print(a)def fun2(x): #非连续函数    if x > 0:        y =4*x-3    else:        y = 2*x+6    return yfun_vec = np.vectorize(fun2) #先对fun2进行向量化处理b = fun_vec(a) #再调用向量化处理过的函数print(b)


(4)从存储身份证号码的数组中提取出生日期信息。

参考代码如下:

a = ["330281200409172215","522424200405202975","610528200409070018"]a = np.array(a)def fun3(x): #非连续函数    returnx[6:14]fun_vec = np.vectorize(fun3) #先对fun3进行向量化处理b = fun_vec(a) #再调用向量化处理过的函数print(b)


(5)随机生成一个numpy数组a,返回其对应的二进制数(非连续函数)。

参考代码如下:

a = np.random.randint(-10, 10, 3)print(a)def fun4(x): #非连续函数    returnbin(x)fun_vec = np.vectorize(fun4) #先对fun4进行向量化处理b = fun_vec(a) #再调用向量化处理过的函数print(b)


(6)随机生成2个numpy数组a和b,若a>b,返回a-b;否则返回b-a(非连续函数)。

参考代码如下:

a = np.random.randint(-10, 10, 3)b = np.random.randint(-10, 10, 3)print(a, b)def fun5(a, b): #非连续函数    if a > b:        return a- b    else:        return b- afun_vec = np.vectorize(fun5) #先对fun5进行向量化处理c = fun_vec(a, b) #再调用向量化处理过的函数print(c)


知识小贴士

vectorize()函数用来将函数向量化处理,以便可以批量处理numpy数组的每一个元素,其具体参数如下:

numpy.vectorize(pyfunc, otypes=None, doc=None,excluded=None, cache=False, signature=None)

pyfunc : python函数或方法。

otypes : 输出数据类型。必须将其指定为一个typecode字符串或一个数据类型说明符列表。每个输出应该有一个数据类型说明符。

doc : 函数的docstring。如果为None,则docstring将是pyfunc.__doc__。

excluded : 表示函数不会向量化的位置或关键字参数的字符串或整数集。这些将直接传递给未经修改的pyfunc。

cache :如果为True,则缓存第一个函数调用,该函数调用确定未提供otype的输出数。

signature : 广义通用函数签名,例如,(m,n),(n)->(m)用于矢量化矩阵 - 向量乘法。如果提供的话,pyfunc将调用(并期望返回)具有由相应核心维度的大小给出的形状的数组。默认情况下,pyfunc假定将标量作为输入和输出。

函数返回值:向量化的数组。


需要本文源代码和word文稿的,可以加入“Python算法之旅”知识星球参与讨论和下载文件,Python算法之旅”知识星球汇集了数量众多的同好,更多有趣的话题在这里讨论,更多有用的资料在这里分享。

我们专注Python算法,感兴趣就一起来!



相关优秀文章:

阅读代码和写更好的代码

最有效的学习方式

利用pandas模块处理学生成绩

利用pandas模块处理百家姓数据


浏览 88
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报