Python模块 —— NumPy
NumPy(二)—— 切片索引、数组操作、函数
大家可以关注知乎或微信公众号的share16,我们也会同步更新此文章。
二、切片索引
2.1 副本和视图
副本
是一个数据的完整的拷贝,如果我们对副本进行修改,它不会影响到原始数据,物理内存不在同一位置。
视图
是数据的一个别称或引用,通过该别称或引用亦便可访问、操作原有数据,但原有数据不会产生拷贝。如果我们对视图(可理解为子集)进行修改,它会影响到原始数据,物理内存在同一位置。
2.2 切片索引
ndarray对象的内容可以通过索引或切片来访问和修改,与 Python 中 list 的切片操作一样。
- 索引可正可负;正索引:从左往右,从0开始;负索引:从右往左,从-1开始;
- 切片:遵循左闭右开原则(即包含start,不包含end),start/end 是索引值;
- 布尔索引:通过布尔运算(如比较运算符)来获取符合指定条件的元素的数组;
import numpy as np
a = np.arange(101,126).reshape(5,5)
''' 切片 '''
b = a[3, -1] # 取某值
c = a[1:4, 2:5:2] # 取某区域/某几个值
d = a[1] # 取索引值为1的行
e = a[:, 2] # 取索引值为2的列
print(a, b, c, d, e, sep='\n\n')
''' 整数数组索引 '''
# 如:获取数组四个角的元素,其四个索引分别为:(0,0)、(0,4)、(4,0)和(4,4)
b = a[[0,0,4,4],[0,4,0,4]] # 行/列索引组成的列表
# 如:获取数组四个角的元素,其行索引分别为:(0,0)、(4,4);列索引分别为:(0,4)、(0,4)
x = np.array([[0,0],[4,4]]) # 行索引组成的数组
y = np.array([[0,4],[0,4]]) # 列索引组成的数组
c = a[x,y]
d = a[1:4,[1,-1]]
e = a[2][2]
print(a, b, c, d, e, sep='\n\n')
''' 布尔索引 '''
b = a[a>122]
print(b)
# >> [123 124 125]
2.3 小练习
2.3.1 交换数组中的列1和列3
import numpy as np
a = np.arange(9).reshape(3,3)
b = a[:, [2,1,0]]
print(a,b,sep='\n\n')
2.3.2 反转二维数组的行/列
import numpy as np
a = np.arange(9).reshape(3,3)
b = a[::-1, :] # 反转行
c = a[:, ::-1] # 反转列
print(a, b, c, sep='\n\n')
三、数组操作
Numpy 中包含了一些函数用于处理数组,如reshape、flat、stack、resize、split、unique等。
3.1 相关函数
import numpy as np
a = np.arange(4)
b = a.reshape(2,2)
print('增加维度(np.newaxis):\n{}\n\n增加维度(np.newaxis):\n{}\n\n扩展数组(np.tile):\n{}\n\n扩展数组(np.repeat):\n{}\n\n'.format(a[np.newaxis,:], a[:,np.newaxis], np.tile(b,(2,2)), np.repeat(b,(2,2),axis=0)))
3.2 小练习
3.2.1 给定两个随机数组A和B,验证它们是否相等
import numpy as np
a = np.random.randint(1,2,(2,5))
b = np.random.randint(1,2,(2,5))
# 比较两个数组是不是每一元素都相等,默认在1e-05的误差范围内
print(np.allclose(a,b))
# 检查两个数组是否具有相同的形状和元素
print(np.array_equal(a,b))
3.2.2 在给定的numpy数组中找到重复的条目(第二次出现以后),并将它们标记为True;第一次出现应为False。
import numpy as np
a = np.random.randint(1,5,size=10)
b = np.full_like(a,True,dtype=bool)
# 返回新列表元素在旧列表中首次出现的位置
c = np.unique(a,return_index=True)
for i in c[1]:
b[i] = False
print(a,b,c,sep='\n\n')
四、逻辑函数及数学函数
4.1 向量化和广播
向量化和广播这两个概念是 numpy 内部实现的基础。有了向量化,编写代码时无需使用显式循环。这些循环实际上不能省略,只不过是在内部实现,被代码中的其他结构代替。向量化的应用使得代码更简洁,可读性更强,也可以说使用了向量化方法的代码看上去更“Pythonic”。
广播(Broadcasting)机制描述了 numpy 如何在算术运算期间处理具有不同形状的数组,让较小的数组在较大的数组上“广播”,以便它们具有兼容的形状。并不是所有的维度都要彼此兼容才符合广播机制的要求,但它们必须满足一定的条件。
若两个数组的各维度兼容,也就是两个数组的每一维等长,或其中一个数组为 一维,那么广播机制就适用。如果这两个条件不满足,numpy就会抛出异常,说两个数组不兼容。
总结来说,广播的规则有三个:
- 如果两个数组的维度数dim不相同,那么小维度数组的形状将会在左边补1。
- 如果shape维度不匹配,但是有维度是1,那么可以扩展维度是1的维度匹配另一个数组;
- 如果shape维度不匹配,但是没有任何一个维度是1,则匹配引发错误;
4.2 逻辑函数
4.3 数学函数
4.4 小练习
4.4.1 将数组a中大于20的值替换为20,小于8的值替换为8
''' np.clip()
np.where(condition, x, y):满足条件,输出x,不满足输出y '''
import numpy as np
a = np.array([1,3,5,7,9,11,13,16,21,22])
a1 = np.clip(a,8,20)
a2 = np.where(a<8,8,a)
a2 = np.where(a2>20,20,a2) # 注:where里面是a2
print(a, a1, a2,sep='\n\n')
# >> [ 1 3 5 7 9 11 13 16 21 22]
# >> [ 8 8 8 8 9 11 13 16 20 20]
# >> [ 8 8 8 8 9 11 13 16 20 20]
4.4.2 对一个5x5的随机矩阵做归一化
''' 归一化:(x - x_min)/(x_max - x_min) '''
import numpy as np
a = np.random.randint(10,90,(5,5))
a_max = a.max()
a_min = a.min()
a0 = np.round((a - a_min)/(a_max - a_min),2)
print('原数组:\n{}\n\n归一化后的数组:\n{}\n'.format(a,a0))
4.4.3 获取a和b元素匹配的位置
import numpy as np
a = np.array([1, 2, 3, 2, 3, 4, 3, 4, 5, 6])
b = np.array([7, 2, 10, 2, 7, 4, 9, 4, 9, 8])
mask = np.equal(a, b)
print(mask)
# 方法1
x = np.where(mask)
print(x)
# 方法2
x = np.nonzero(mask)
print(x)
# >> [False True False True False True False True False False]
# >> (array([1, 3, 5, 7]),)
# >> (array([1, 3, 5, 7]),)
4.4.4 找出数组中与给定值最接近的数
import numpy as np
a = np.random.randint(10,20,(2,2))
b = 16
c = np.abs(a-b).argmin() # 返回数组中最小值的索引
print(a, c, a.flatten()[c],sep='\n\n')
谢谢大家 🌹