切片和索引
一、切片
(一)含义理解
笔者对切片的理解是:获取 被切片列表、数组 的一段地址。
我们可以举一个超能力猪肉的例子。假设我们要切片的对象就是这么一块超能力猪肉,但是这块猪肉不管被怎么切,它都不会少。
现在顾客A想要瘦肉的部分,于是我们就从猪肉中切取瘦肉的部分;然后顾客B想要一半肥肉一半瘦肉,我们同样将想要的猪肉切给他。
因为是超能力猪肉,所以,顾客A切过之后,顾客B 还是可以切到瘦肉。
这就是切片的含义,相信读者已经可以理解了。
(二)标准写法:列表名[start:stop:step]
注意1:
stop 不包含在内
设计原理:
- 可以直接计算出元素个数,末 - 初
- 分成两个部分,前一部分不包含,后一部分直接开始
注意2:
数组切片是原始数组视图(切改原改)。 如果不想改原始数组,我们就要进行显式的复制,从而得到它的副本。
关于这个注意2,我们继续用上面的例子。
当顾客A和顾客B得到猪肉之后,打算带回家料理。
顾客A先到家,并先将瘦肉切成片。这时候,我手上的超能力猪肉瘦肉的部分也被切成片了。
之后,顾客B也回到家了,他决定直接将一大块肥瘦兼并的猪肉一起放到水里煮。这时候,我手上的猪瘦肉的部分就自动粘回在一起了,并且,那半肥半瘦的部位开始发烫。
相信读者已经理解了,注意2的意思。如果不理解也没关系,下文有代码解释。
(三)Python中的切片
# 切片值 不会受到任何影响
a_list = [1,2,3,4]
b_list = a_list
c_list = a_list[:] # [:] 就是全部都切
d_list = a_list[1:3]
# 两者的改变 会 影响原始值,不会影响 被赋值的切片
a_list[1] = 10 # a_list 变 --> b_list变、c_list 不变、d_list 不变
b_list[2] = 10 # b_list 变 --> a_list变、c_list 不变、d_list 不变
# 被赋值的切片 被改变 不会 影响原始值
c_list[2] = 20 # c_list 变 --> a_list 不变、b_list 不变、d_list 不变
print(a_list)
print(b_list)
print(c_list)
print(d_list)
# --------------------------------------
[1, 10, 10, 4]
[1, 10, 10, 4]
[1, 2, 20, 4]
[2, 3]
1.浅拷贝 copy
两者互相打扰!!!
import copy
a_list = [100,[200,300]]
b_list = a_list.copy()
a_list[1][0] = 500
b_list[1][1] = 600
print(a_list)
print(b_list)
print(b_list[1][0])
# --------------------------------------
[100, [500, 600]]
[100, [500, 600]]
500
2.深拷贝 copy.deepcopy
两者互不干扰!!!
import copy
a_list = [100,[200,300]]
b_list = copy.deepcopy(a_list)
a_list[1][0] = 500
b_list[1][0] = 600
print(a_list)
print(b_list)
# --------------------------------------
[100, [500, 300]]
[100, [600, 300]]
(四)Ndarray中的切片
1.一维数组
# 示例1:
ar = np.arange(10)
print(ar)
# 切片本身被改变了
ar[5] = 100
ar[7:9] = 200
print(ar)
# --------------------------------------
[0 1 2 3 4 5 6 7 8 9]
[ 0 1 2 3 4 100 6 200 200 9]
# 示例2:
ar1 = np.arange(10)
print(ar1)
ar2 = ar1[2:7:2]
print(ar2)
ar3 = ar1[2:7]
print(ar3)
# --------------------------------------
[0 1 2 3 4 5 6 7 8 9]
[2 4 6]
[2 3 4 5 6]
2.二维数组
切片可以使用 ...
如果在行位置使用省略号,那么返回值将包含所有行元素;反之则包含所有列元素。
# 示例1:
ar4 = np.arange(20).reshape(4,5)
print(ar4)
# 获得行切片
ar4[2:]
# 获得列切片
ar4[...,1]
ar4[...,1:]
# --------------------------------------
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])
# 获得行切片
array([[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])
# 获得列切片
array([ 1, 6, 11, 16])
array([[ 1, 2, 3, 4],
[ 6, 7, 8, 9],
[11, 12, 13, 14],
[16, 17, 18, 19]])
# 示例2:
ar4 = np.arange(20).reshape(4,5)
print(ar4)
# 交集的思路 --> 行是所有行,列是所有列。两者相交
print(ar4[1,2]) # 此处的中括号里面是 , 代表满足交集思路
# 降维的思路 --> 先ar4[1] ,出来之后在 [2]
print(ar4[1][2])
# 降维证明 --> 先ar4[...] ,出来之后在 ar5[1]
print(ar4[...][1])
ar5 = ar4[...]
print(ar5[1])
# --------------------------------------
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])
7
7
[5 6 7 8 9]
[5 6 7 8 9]
二、索引
1.正向索引,则索引值从 0 开始
2.反向索引,则索引值从 -1 开始
(一)整数数组索引
# 示例1:
# 创建二维数组
x = np.array([
[1,2],
[3,4],
[5,6] ])
# [0,1,2]:行索引;
# [0,1,0]:列索引。
# 0->0:1 ; 1->1:4 ; 2->0:5
y = x[[0,1,2],[0,1,0]]
y
# --------------------------------------
array([1, 4, 5])
# 示例2:
a = np.arange(12).reshape(4,3)
print(a)
b = a[ [0,0,3,3],[0,2,0,2] ]
#为什么要 reshape --> 因为四维的不好理解,三维又存不下,所有换成 2*2
r = np.array([ [0,0],[3,3] ]).reshape(4)
l = np.array([ [0,2],[0,2] ]).reshape(4)
s = a[r,l].reshape((2,2))
print(s)
#--------------------------------------
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
[[ 0 2]
[ 9 11]]
# 示例3:
a = np.arange(1,10).reshape(3,3)
print(a)
b = a[1:3,1:3]
c = a[1:3,[1,2]] # 此处以第一个 , 为界限。[1,2]代表了:索引为1、2的列都取
d = a[...,1:]
print(b)
print(c)
print(d)
#--------------------------------------
[[1 2 3]
[4 5 6]
[7 8 9]]
[[5 6]
[8 9]]
[[5 6]
[8 9]]
[[2 3]
[5 6]
[8 9]]
练习:创建一个 8*8 的国际象棋棋盘矩阵(黑块为0,白块为1)
Z = np.zeros((8,8),dtype = int)
Z[1::2,0::2] = 1 # 行从1开始,以2为跨步;列从0开始,以2为跨步。两者相交
Z[0::2,1::2] = 1
print(Z)
#--------------------------------------
[[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]]
(二)布尔数组索引
1.布尔索引 简单理解就是:保留 True值 的索引
练习1:提取出数组中所有奇数
a = np.arange(0,12).reshape(4,3)
b = a[a%2 == 1] # 余数为1的值判断为True,然后将索引值放入
b
#--------------------------------------
array([ 1, 3, 5, 7, 9, 11])
练习2:将修改奇数值为 -1
–> 此题出得不是很好,因为下标和索引是一样的。
a = np.arange(0,12).reshape(4,3)
a[a%2 == 1] = -1
a
#--------------------------------------
array([[ 0, -1, 2],
[-1, 4, -1],
[ 6, -1, 8],
[-1, 10, -1]])
2.& | 的运用
x = np.arange(0,12).reshape((4,3))
x1 = x[(x>4) & (x<9)] # 合运算
x2 = x[(x<4) | (x>9)] # 或运算
print(x1)
print(x2)
#--------------------------------------
[5 6 7 8]
[ 0 1 2 3 10 11]
3.True 和 False 的形式表示需要和不需要的数据
(索引的“真”数量要一样,否则行列不匹配,就会报错!)
# 示例1:
ar1 = np.arange(12).reshape(3,4)
print(ar1)
# 行变量 存在3个元素
row = np.array([False,True,True]) # 只有为True的才能打印出来,数量是2
# 列变量 存在4个元素
colum = np.array([True,False,True,False]) # 只有为True的才能打印出来,数量是2
# 单独运行 行
print(ar1[row])
print(ar1[[1,2],:])
print(ar1[[1,2],...])
# 单独运行 列
print(ar1[:,colum])
print(ar1[:,[0,2]])
#--------------------------------------
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
# 单独运行 行
[[ 4 5 6 7]
[ 8 9 10 11]]
[[ 4 5 6 7]
[ 8 9 10 11]]
[[ 4 5 6 7]
[ 8 9 10 11]]
# 单独运行 列
[[ 0 2]
[ 4 6]
[ 8 10]]
[[ 0 2]
[ 4 6]
[ 8 10]]
# 示例2:
ar1 = np.arange(20).reshape(5,4)
print(ar1)
row = np.array([False,True,True,False,True]) # 只有为True的才能打印出来,数量是3
colum = np.array([True,False,True,False]) # 只有为True的才能打印出来,数量是2
#--------------------------------------
运行错误,True的数量不匹配,无法打印
# 示例3:
a = np.arange(12).reshape(3,4)
print(a)
b1 = np.array([False,True,True])
b2 = np.array([True,False,True,False])
# 使用 布尔型索引之后,会返回 数组的对角线
print(a[b1,b2])
# 如果想要返回 都为“真” 的数组,那就需要用 np.ix_() 函数
print(a[np.ix_(b1,b2)])
#--------------------------------------
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[ 4 10]
[[ 4 6]
[ 8 10]]
练习3:要 np.arange(12).reshape(3,4) 第1、3行的 1、3、4列
a = np.arange(12).reshape(3,4)
print(a)
b = a[[0,2],...]
print(b)
c = b[...,[0,2,3]]
print(c)
#-------------------------------------- ```
# 注意:由于形状不一样,所以不可以直接就 a[[0,2],[0,2,3]]
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[ 0 1 2 3]
[ 8 9 10 11]]
[[ 0 2 3]
[ 8 10 11]]
三、练习
练习1:创建0到24的5*5数组ar,通过索引,其ar[4]、ar[:2,3:]、ar[3][2]分别是多少
ar1 = np.arange(25).reshape(5,5)
print(ar1)
print(ar1[4])
print(ar1[:2,3:]) # :之后的数值是不包含的
print(ar1[3][2])
# --------------------------------------
[[ 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]]
[20 21 22 23 24]
[[3 4]
[8 9]]
17
练习2:创建0到9的2*5数组ar,筛选出元素值大于5的值并生成新的数组
ar2 = np.arange(2,12).reshape(2,5)
print(ar2)
x = ar2[ar2 > 5] # 为 True 的留下
print(x)
# --------------------------------------
[[ 2 3 4 5 6]
[ 7 8 9 10 11]]
[ 6 7 8 9 10 11]
练习3:创建一个2维10*10数组,使该数组边界值为1,内部的值为0
ar3 = np.zeros((10,10))
ar3[...,[0,-1]] = 1 # 所有行的 --> 第一列 和 最后一列
ar3[[0,-1],...] = 1 # 所有列的 --> 第一行 和 最后一行
ar3
# ----------------------------------------------------
array([[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[1., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[1., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[1., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[1., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[1., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[1., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[1., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[1., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]])
练习4:创建一个从10到49的ndarray对象,并进行倒序复制给另一个变量
ar4 = np.arange(10,50)
ar4_1 = ar4[::-1] # 意思就是从起点,向后倒着走一个⚪
ar4_1
# ----------------------------------------------------
array([49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33,
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
15, 14, 13, 12, 11, 10])
练习5:a=np.arange(0,20).reshape(4,5),需要更换第二行和三行的位置
import copy
ar5 = np.arange(0,20).reshape(4,5)
print(ar5)
ar5_1 = copy.deepcopy(ar5[1])
ar5_2 = copy.deepcopy(ar5[2])
ar5[1] = ar5_2
ar5[2] = ar5_1
print(ar5)
# ----------------------------------------------------
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]
[[ 0 1 2 3 4]
[10 11 12 13 14]
[ 5 6 7 8 9]
[15 16 17 18 19]]
练习6:分别反转练习5中二维数组的列和行
这里直接介绍一下转置,转置需要用到的函数就是 transpose()
示例1的转置比较容易理解,示例2的可能就不怎么好理解了。大家先看看代码,下面会介绍一个统一的方法。
# 示例1:
x = np.arange(4).reshape((2,2))
print(x)
x = x.transpose()
print(x)
# ----------------------------------------------------
[[0 1]
[2 3]]
[[0 2]
[1 3]]
示例1:
0轴表示一维,1轴上放二维的数字。当发生转置的时候,两轴互换位置,相当于从纸里面向外看。
# 示例2:
x = np.arange(16).reshape(2,3,4)
print(x)
x = x.transpose()
print(x)
# ----------------------------------------------------
[[[ 0 1 2 3]
[ 4 5 6 7]]
[[ 8 9 10 11]
[12 13 14 15]]]
[[[ 0 8]
[ 4 12]]
[[ 1 9]
[ 5 13]]
[[ 2 10]
[ 6 14]]
[[ 3 11]
[ 7 15]]]
示例2:
2轴表示三维,第二个中括号 [[ 8 9 10 11] [12 13 14 15]] 的数字就叠放在0轴和1轴形成的平面上方。