宁乡县建设局网站,重庆做网站微信的公司,上海百度搜索优化,北京西站附近的景点有哪些文章目录一、切片和索引1. 一维数组2. 二维数组二、索引的高级操作1. 整数数组索引2. 布尔数组索引三、广播机制1. 广播机制规则2. 对于广播规则另一种简单理解一、切片和索引
ndarray 对象的内容可以通过索引或切片来访问和修改#xff08;#xff09;#xff0c;与 Pytho…
文章目录一、切片和索引1. 一维数组2. 二维数组二、索引的高级操作1. 整数数组索引2. 布尔数组索引三、广播机制1. 广播机制规则2. 对于广播规则另一种简单理解一、切片和索引
ndarray 对象的内容可以通过索引或切片来访问和修改与 Python 中 list 的切片操作一样。ndarray 数组可以基于 0 - n 的下标进行索引先行后列都是从 0 开始。 区别在于数组切片是原始数组视图这就意味着如果做任何修改原始都会跟着更改。 这也意味着如果不想更改原始数组我们需要进行显式的复制从而得到它的副本.copy())。冒号分隔切片参数 [start:stop:step]。在开始之前先导入numpy包
import numpy as np1. 一维数组
通过 numpy.arange() 生成一个等区间的数组起始值默认为 0步长默认为 1终止值设置为 10。
ar1 np.arange(10)
ar1
#array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])从索引 2 开始到索引 7 停止间隔为 2。
ar2 ar1[2:7:2]
ar2
#array([2, 4, 6])这里需要解释以下冒号的作用如果只放置一个参数如果是 [2]将返回与该索引相对应的单个元素如果为 [2:]表示从该索引开始以后的所有项都将被提取如果为 [:2]表示不限制开始元素但会在该元素截止。如果使用了两个参数如 [2:7]那么则提取两个索引不包括停止索引之间的项。返回索引对应的数据注意是从0开始的。
print(ar1:,ar1)
print(ar1[4]:,ar1[4])
#ar1: [0 1 2 3 4 5 6 7 8 9]
#ar1[4]: 4通过 numpy.arange() 生成一个等区间的数组起始值设置为 1终止值设置为 20步长设置为 2。
ar3 np.arange(1,20,2)
ar3
#array([ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19])那么我们如何取出元素 9由于索引是从 0 开始的因此我们输出 ar3[4] 即可。1 从该索引开始以后的所有项都将被提取从索引 2 开始提取出后面所有数据。
print(ar3)
ar3[2:]
#[ 1 3 5 7 9 11 13 15 17 19]
#array([ 5, 7, 9, 11, 13, 15, 17, 19])2 从索引开始到索引结束不包含结束从索引 2 开始到索引 7包含索引 7。
print(ar3)
ar3[2:7]
ar3[:-2]
#[ 1 3 5 7 9 11 13 15 17 19]
#array([ 1, 3, 5, 7, 9, 11, 13, 15])3 步长取所有数据步长为 -1负数代表从右往左数。
ar3[::-1]
#array([19, 17, 15, 13, 11, 9, 7, 5, 3, 1])取数据 1 到 17 之间 并且间隔一位的数据。
ar3[1:-2:2]
print(ar3)
print(ar3[:6])
print(ar3[6:])
#[ 1 3 5 7 9 11 13 15 17 19]
#[ 1 3 5 7 9 11]
#[13 15 17 19]4 为什么切片和区间会忽略最后一个元素计算机科学家 edsger w.dijkstra艾兹格·W·迪科斯彻delattr 这一风格的解释应该是比较好的1 当只有最后一个位置信息时我们可以快速看出切片和区间里有几个元素range(3) 和 my_list[:3]。2 当起始位置信息都可见时我们可以快速计算出切片和区间的长度用有一个数减去第一个下表stop-start即可。3 这样做也让我们可以利用任意一个下标把序列分割成不重叠的两部分只要写成 my_list[:x] 和 my_list[x:] 就可以了。
2. 二维数组
同样适用上述索引提取方法我们定义 4 行 5 列的数据。np.arange(20) 表示起始值默认为 0终止值设置为 20步长默认为 1。reshape(4,5) 表示生成一个 4 行 5 列的二维数组。
ar4_5 np.arange(20).reshape(4,5)
ar4_5
#array([[ 0, 1, 2, 3, 4],
# [ 5, 6, 7, 8, 9],
# [10, 11, 12, 13, 14],
# [15, 16, 17, 18, 19]])我们通过 ar4_5.ndim 返回 ar4_5 的秩也就是几维。
ar4_5.ndim
#2切片表示的是下一维度的一个元素所以其代表一维数组。
ar4_5[2]
#array([10, 11, 12, 13, 14])我们也可以通过二次索引取得一维数组当中的元素。
ar4_5[2][2]
#12打印出 ar4_5 整体数组便于后续的操作观察。
print(ar4_5)
#[[ 0 1 2 3 4]
# [ 5 6 7 8 9]
# [10 11 12 13 14]
# [15 16 17 18 19]]我们可以取出从第三行和第四行的元素。
ar4_5[2:]
#array([[10, 11, 12, 13, 14],
# [15, 16, 17, 18, 19]])注意切片还可以使用省略号 “…”如果在行位置使用省略号那么返回值将包含所有行元素反之则包含所有列元素。例如我们需要取得第二列数据由于索引是从 0 开始的因此 第二列的元素就是 1。取出的就是每一行和第二列交叉的数据也就是 161116。
ar4_5[...,1]
#array([ 1, 6, 11, 16])我们需要返回第二列后的所有项。
ar4_5[...,1:]
#array([[ 1, 2, 3, 4],
# [ 6, 7, 8, 9],
# [11, 12, 13, 14],
# [16, 17, 18, 19]])我们需要返回第 2 行第 3 列的数据对于取出单个数值两种方法是一样的。
ar4_5[1,2] # 对应(1,2) 的元素
#7对于返回第 2 行第 3 列的数据我们也可以使用如下方法。
ar4_5[1][2]
#7对于上述关于取出单个数据的方法是否可以映射到取出一列元素呢如下例子所示答案是否定的。首先我们执行第一步操作就是 ar4_5[…]。此时代表取出 ar4_5 的每一行元素也就是打印 ar4_5 本身。然后我们执行第二步操作 ar4_5[…][1] 就是切片在 ar4_5 本身上打印处第二行也就是 [5, 6, 7, 8, 9]。
ar4_5[...][1]
array([5, 6, 7, 8, 9])二、索引的高级操作
在 NumPy 中还可以使用高级索引方式比如整数数组索引、布尔索引以下将对两种种索引方式做详细介绍。
1. 整数数组索引
我们先创建一个二维数组。
x np.array([[1,2],[3,4],[5,6]])
y x[[0,1,2],[0,1,0]]
y
#array([1,4,5])其中[0,1,2] 代表行索引[0,1,0] 代表列索引表示 y 分别获取 x 中的 (0,0)、(1,1) 和 (2,0) 表示的数据。然后我们先创建一个 43 的数组创建完成之后获取了 43 数组中的四个角上元素它们对应的行索引是 [0,0] 和 [3,3]列索引是 [0,2] 和 [0,2]。
b np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9,10,11]])
a b[[0,0,3,3],[0,2,0,2]] # (0,0) (0,2) (3,0) (3,2)r np.array([[0,0] ,[3,3]]).reshape(4) #用r代替[0,0,3,3]
l np.array([[0,2] ,[0,2]]).reshape(4) #用l代替[0,2,0,2]
s b[r,l].reshape((2,2))
s
#array([[ 0, 2],
# [ 9, 11]])然后我们先创建一个 3*3 的数组创建完成之后行取出第 2 行和第 3 行的元素列取出第 2 列和第 3 列的数据。这里需要注意的是不包含终止索引值。
a np.array([[1,2,3], [4,5,6],[7,8,9]])
b a[1:3, 1:3]
b
#array([[5, 6],
# [8, 9]])也就是 1:3 [1,2]。高级索引操作与常规的索引操作相同都可以使用 … 表示所有行1: 表示从第二列开始的所有列。
c a[1:3,[1,2]]
d a[...,1:]
print(b)
print(c)
print(d)
#[[5 6]
# [8 9]]
#[[5 6]
# [8 9]]
#[[2 3]
# [5 6]
# [8 9]]在了解了上述高级索引操作之后我们可以尝试创建一个 8x8 的国际象棋棋盘矩阵其中黑块代表是 0白块代表是 1具体棋盘如下所示。
[0 1 0 1 0 1 0 1][1 0 1 0 1 0 1 0][0 1 0 1 0 1 0 1][1 0 1 0 1 0 1 0][0 1 0 1 0 1 0 1][1 0 1 0 1 0 1 0][0 1 0 1 0 1 0 1][1 0 1 0 1 0 1 0]]
对于上述棋盘我们可以先生成一个 8x8 的全 0 数组然后将对应的元素设置为 1 即可。1 通过行索引从 1 开始步长为 2不设置终止值将第 1357 行元素全部设置为 1。2 通过列索引从 0 开始步长为 2不设置终止值将第 1357 行元素对应的列元素设置为 0。3 通过列索引从 1 开始步长为 2不设置终止值将第 1357 列元素全部设置为 1。4 通过行索引从 0 开始步长为 2不设置终止值将第 1357 行元素对应的行元素设置为 0。具体实现代码如下所示。
Z np.zeros((8, 8), dtypeint)
Z[1::2,::2] 1
Z[::2,1::2] 1
Z
#array([[0, 0, 0, 0, 0, 0, 0, 0],
# [1, 0, 1, 0, 1, 0, 1, 0],
# [0, 0, 0, 0, 0, 0, 0, 0],
# [1, 0, 1, 0, 1, 0, 1, 0],
# [0, 0, 0, 0, 0, 0, 0, 0],
# [1, 0, 1, 0, 1, 0, 1, 0],
# [0, 0, 0, 0, 0, 0, 0, 0],
# [1, 0, 1, 0, 1, 0, 1, 0]])2. 布尔数组索引
当输出的结果需要经过布尔运算如比较运算时此时会使用到另一种高级索引方式即布尔数组索引。下面示例返回数组中大于 6 的的所有元素
x np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])
print(x.shape)
x[x6]
#(4, 3)
#array([ 7, 8, 9, 10, 11])布尔索引所实现的是通过一维数组中的每个元素的布尔型数值对一个与一维数组有着同样行数或列数的矩阵进行符合匹配。这种作用其实是把一维数组中布尔值为 True 的相应行或列给抽取了出来。这里需要注意的是一维数组的长度必须和想要切片的维度或轴的长度一致。练习1 提取出数组中所有奇数。
x np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])
x[x%2 1]
#array([ 1, 3, 5, 7, 9, 11])2 将奇数值修改为 -1。
x np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])
x[x%2 1] -1
x
#array([[ 0, -1, 2],
# [-1, 4, -1],
# [ 6, -1, 8],
# [-1, 10, -1]])筛选出指定区间内数据 表示和。| 表示或。将数组 x 中大于 4 并且小于 9 的数据提取出来。
x np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])
x[(x4) (x9)]
#array([5, 6, 7, 8])将数组 x 中小于4或者大于 9 的数据提取出来。
x np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])
x[(x4) | (x9)]
#array([ 0, 1, 2, 3, 10, 11])True 和 False 的形式表示需要和不需要的数据我们先创建 3*4 的数组元素通过 np.arange(12) 自动生成表示从起始值 0 到终止值不包括终止值12步长是 1。
a3_4 np.arange(12).reshape((3,4))
a3_4
#array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])将行变量和列变量分别用 True 和 False 表示其中行变量和列变量按如下代码设置。
row1 np.array([False,True,True])
column1 np.array([True,False,True,False])a3_4 是 3 行, 做切片时也提供 3 个元素的数组轴的长度一致。通过 row1 和 column1 中的 True 和 False 就可以输出我们需要的元素True 表示需要False 表示不需要。
a3_4[row1]
#array([[ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])a3_4[:,column1]
#array([[ 0, 2],
# [ 4, 6],
# [ 8, 10]])那么我们是否可以用两个一维布尔数组进行切片呢我们继续进行试验得到如下结果
a3_4[row1,column1]
#array([ 4, 10])从结果上看它实际上等价于下面的代码。
a3_4[[1, 2],[0, 2]]输出的相当于是坐标序号为 (0,1),(2,2) 的数。索引形状不匹配从上面的结果可以知道能够进行切片的前提是两个一维布尔数组中 True 的个数需要相等否则会出现下面的情况。行变量当中存在 2 个 True 元素列变量当中存在 3 个 True 元素。
row2 np.array([False,True,True])
column2 np.array([True,False,True,True])其中行变量和列变量当中的 True 元素个数不一致,会导致错误。a3_4[row2, column2] 就相当于 a3_4[[1,2],[0,2,3]]。报错信息如下indexError: shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (3,)。是因为所选索引形状不匹配索引数组无法与该形状一起广播。当访问 numpy 多维数组时用于索引的数组需要具有相同的形状行和列。numpy 将有可能去广播所以若要为了实现不同维度的选择 可分两步对数组进行选择。1 例如我需要选择第 1 行和最后一行的第 134 列时先选择行再选择列。2 先读取数组 a3_4 的第一行和最后一行保存到 temp 然后再筛选相应的列即可。
a3_4
#array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])那么我们需要选择第 1 行和最后一行的第 134 列元素操作步骤如下1 先选行。
temp a3_4[[0,-1],:]
temp
#array([[ 0, 1, 2, 3],
# [ 8, 9, 10, 11]])2 再选择列。
temp[:,[0,2,3]]
temp
#array([[ 0, 2, 3],
# [ 8, 10, 11]])3 合并一条。
a3_4[[0,-1],:][:,[0,2,3]]但是如果有一个一维数组长度是 1 时这时又不会报错比如说如果我们需要提取第二行第 13 列的数据。
a3_4[[1],[0,2]]
#array([4, 6])以上相当于 (1,0) 和 (1,2)。数组索引及切片的值更改会修改原数组一个标量赋值给一个索引/切片时会自动改变/传播原始数组。
ar np.arange(10)
print(ar)
ab ar[:]
ar[5] 100
print(ab)
#[0 1 2 3 4 5 6 7 8 9]
#[ 0 1 2 3 4 100 6 7 8 9]可以使用复制操作。
ar np.arange(10)
b ar.copy()或者可以使用 b np.array(ar)。
b[7:9] 200
print(ar:,ar)
print(b:,b)三、广播机制
广播Broadcast是 numpy 对不同形状shape的数组进行数值计算的方式 对数组的算术运算通常在相应的元素上进行。如果两个数组 a 和 b 形状相同即满足 a.shape b.shape那么 a*b 的结果就是 a 与 b 数组对应位相乘。这要求维数相同且各维度的长度相同。
a np.array([1,2,3,4])
b np.array([10,20,30,40])
c a * b
print (c)
#[ 10 40 90 160]但如果两个形状不同的数组呢它们之间就不能做算术运算了吗当然不是为了保持数组形状相同NumPy 设计了一种广播机制 这种机制的核心是对形状较小的数组在横向或纵向上进行一定次数的重复使其与形状较大的数组拥有相同的维度。
a np.array([[ 0, 0, 0],[10,10,10],[20,20,20],[30,30,30]])
b np.array([1,2,3])
print(a b)下面的图片展示了数组 b 如何通过广播来与数组 a 兼容。 4x3 的二维数组与长为 3 的一维数组相加等效于把数组 b 在二维上重复 4 次再运算。
1. 广播机制规则
广播具有如下规则1 让所有输入数组都向其中形状最长的数组看齐形状中不足的部分都通过在前面加 1 补齐。2 输出数组的形状是输入数组形状的各个维度上的最大值。3 如果输入数组的某个维度和输出数组的对应维度的长度相同或者其长度为 1 时这个数组能够用来计算否则出错。4 当输入数组的某个维度的长度为 1 时沿着此维度运算时都用此维度上的第一组值。** 为了更清楚的理解这些规则看来看几个具体的示例**我们通过 np.ones() 生成一个全 1 数组np.arange() 生成一个有规律元素的数组。两个数组的形状分别为 M.shape(2,3),a.shape(3,)。可以看到根据规则 1数组 a 的维度更小所以在其左边补 1变为 M.shape - (2,3), a.shape - (1,3)。根据规则 2第一个维度不匹配因此扩展这个维度以匹配数组M.shape -(2,3), a.shape - (1,3)。现在两个数组的形状匹配了可以看到它们的最终形状都为(2,3)。
M np.ones((2,3))
print(M)
a np.arange(3)
print(a)
M a
#[[1. 1. 1.]
# [1. 1. 1.]]
#[0 1 2]
#array([[1., 2., 3.],
# [1., 2., 3.]])我们通过 np.arange() 生成两个有规律元素数组其中一个设置为三行一列便于对广播机制进行验证。两个数组的形状设置为 a.shape(3,1), b.shape(3,)。规则 1 告诉我们需要用 1 将 b 的形状补全a.shape - (3,1), b.shape - (1,3)。规则 2 告诉我们需要更新这两个数组的维度来相互匹配a.shape - (3,3), b.shape - (3,3)因为结果匹配所以这两个形状是兼容的。
a np.arange(3).reshape((3,1))
print(a:,a)
b np.arange(3)
print(b:,b)
a b
#a: [[0]
# [1]
# [2]]
#b: [0 1 2]
#array([[0, 1, 2],
# [1, 2, 3],
# [2, 3, 4]])2. 对于广播规则另一种简单理解
1 将两个数组的维度大小右对齐然后比较对应维度上的数值。2 如果数值相等或其中有一个为1或者为空则能进行广播运算。3 输出的维度大小为取数值大的数值。否则不能进行数组运算。数组 a 大小为(2, 3)数组 b 大小为 (1,)对其进行右对齐操作。 2 31
----------2 3所以最后两个数组运算的输出大小为2 3下面对其进行代码验证。
a np.arange(6).reshape(2, 3)
print(a:, a)
b np.array([5])
print(b:,b)
c a * b
c
#a: [[0 1 2]
# [3 4 5]]
#b: [5]
#array([[ 0, 5, 10],
# [15, 20, 25]])数组 a 大小为 (2, 1, 3)数组 b 大小为 (4, 1)对其进行右对齐操作。 2 1 34 1
----------2 4 3所以最后两个数组运算的输出大小为2, 4, 3。
a np.arange(6).reshape(2, 1, 3)
print(a:,a)
print(-*10)
b np.arange(4).reshape(4, 1)
print(b:,b)
print(-*10)
c a b
print(c,c.shape)
#a: [[[0 1 2]]
#
# [[3 4 5]]]
#----------
#b: [[0]
# [1]
# [2]
# [3]]
#----------
#[[[0 1 2]
# [1 2 3]
# [2 3 4]
# [3 4 5]]
#
# [[3 4 5]
# [4 5 6]
# [5 6 7]
# [6 7 8]]] (2, 4, 3)从这里能够看出1 两个数组右对齐以后对应维度里的数值要么相等要么有一个为 1要么缺失取大值。2 除此之外就会报错。像下面的两个数组就不能做运算。数组 a 大小为 (2, 1, 3)数组 b 大小为 (4, 2)对其进行右对齐操作。 2 1 34 2
----------2 跟 3 不匹配此时就不能做运算。
a np.arange(6).reshape(2, 1, 3)
print(a:,a)
print(-*10)
b np.arange(8).reshape(4, 2)
print(b:,b)
print(-*10)
a b
#a: [[[0 1 2]]
#
# [[3 4 5]]]
#----------
#b: [[0 1]
# [2 3]
# [4 5]
# [6 7]]
#----------
#---------------------------------------------------------------------------
#ValueError Traceback (most recent call last)
#ipython-input-68-2ebfaa0877fb in module
# 9 print(-*10)
# 10 # 运行报错
#--- 11 a b
#
#ValueError: operands could not be broadcast together with shapes (2,1,3) (4,2) 广播机制能够处理不同大小的数组数组之间必须满足广播的规则否则就会报错。事实上相同大小的数组运算也遵循广播机制。