切片(slice)简单来说就是更高级的索引操作,可以通过切片操作得到任意目标值,其切片对象的类型是与 Python 层面的slice相同的对象,即序列型对象,如array,list, string, tuple等,下面的介绍中将以array为例,通过一维和二维数组的来讲解,更高维的与二维类似,其他对象也与array类似。通过概念和代码实例的结合更容易理解
索引
在介绍切片内容之前,先来通过一张图了解序列对象的索引。 从图中可以看出包括正索引和负索引两部分,从左到右索引默认 0 开始,从右到左索引默认 -1 开始。
切片公式
切片操作基本表达式:
object[start_index : end_index : step
- start_index:表示起始索引(包含该索引本身); 该参数省略时,表示从“端点”开始取值,至于是从“起点”还是从“终点”开始,则由step参数的正负决定,step为正从“起点”开始,为负从“终点”开始。
- end_index:表示终止索引(不包含该索引本身);该参数省略时,表示一直取到数据”端点“,至于是到”起点“还是到”终点“,同样由step参数的正负决定,step为正时直到”终点“,为负时直到”起点“。
- step:表示步长值,正负数均可,但不能为0,当step省略时,默认为1。其绝对值大小决定了切取数据时的“步长”,而正负号决定了“切取方向”,正表示“从左往右”取值,负表示“从右往左”取值。
切片操作会将按照给定的索引和步长,截取序列中由连续的对象组成的片段,单个索引返回值可以视为只含有一个对象的连续片段。
实例讲解
一维数组
下面介绍中s表示开始索引,e表示结束索引,p表示步长,下标表示维度
import numpy as np
X=[1,2,3,4,5]
- 一个参数:X[i]
最基础的也最常见的切片操作,即通过索引获取结果
print(X[0])
1
- 两个参数:X[s:e]
使用起始索引和结束索引,也可以省略s或e,具体细节看上面公式讲解,取得连续的某些值(步长默认为1)
print(X[-1])
print('**'*10)
print(X[1:])
print('**'*10)
print(X[:-1])
print('**'*10)
print(X[1:-1])
5
********************
[2, 3, 4, 5]
********************
[1, 2, 3, 4]
********************
[2, 3, 4]
- 三个参数;X[s:e:p]
使用起始索引、结束索引和步长,取得想要得到的某些值,也可以省略s、e或p
print(X[0:4:2])
print('**'*10)
print(X[1::2])
print('**'*10)
print(X[::-1])
[1, 3]
********************
[2, 4]
********************
[5, 4, 3, 2, 1]
二维数组
X
[
n
0
,
n
1
]
X[n_0,n_1]
X[n0?,n1?]是通过 numpy 库引用二维数组中某一段数据集的一种写法。同样,
X
[
n
0
,
n
1
,
n
2
]
X[n_0,n_1,n_2]
X[n0?,n1?,n2?]表示取三维数组,取N维数组则有N个参数,N-1个逗号分隔。以二维数组为例:(s表示开始索引,e表示结束索引,p表示步长,下标表示维度)
import numpy as np
X = np.array([[0,1,2,3],[10,11,12,13],[20,21,22,23],[30,31,32,33]])
print(X)
print('**'*10)
[[ 0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]]
********************
- 取元素
X
[
n
0
,
n
1
]
X[n_0,n_1]
X[n0?,n1?]
基本形式表示通过索引取数组的某个值,例如X[1,0]表示取第二行第一个元素
print(X[1,0])
print('**'*10)
10
********************
-
X
[
s
0
:
e
0
,
s
1
:
e
1
]
X[s_0:e_0,s_1:e_1]
X[s0?:e0?,s1?:e1?]
这是最通用的切片操作,表示取第0维 的第
s
0
s_0
s0?到
e
0
e_0
e0?个元素,继续取 第1维 的第
s
1
s_1
s1?到
e
1
e_1
e1?个元素。如 X[1:3,1:3] 表示第0维第(1:3)个元素,然后取其第1维的第(1:3)个元素;
print(X[1:3,1:3])
print('**'*10)
[[11 12]
[21 22]]
********************
参考配图
-
X
[
:
e
0
,
s
1
:
]
X[:e_0,s_1:]
X[:e0?,s1?:]
特殊情况,即省略开始索引:X[:e_0,s_1:e_1],省略结束索引:X[s_0:,s_1:e_1],使用正负步长:X[:e_0,s_1:e_1],取某一维全部元素X[:,s1:e1]等,事实上和Python 的 序列切片规则是一样的。
import numpy as np
X = np.array([[0,1,2,3],[10,11,12,13],[20,21,22,23],[30,31,32,33]])
print(X[2:4,:4])
print('**'*10)
print(X[:2,:2:2])
print('**'*10)
print(X[:2,:2:-2])
print('**'*10)
print(X[:,:2])
print('**'*10)
print(X[:,0:3:2])
结果如下:
[[20 21 22 23]
[30 31 32 33]]
********************
[[ 0]
[10]]
********************
[[ 3]
[13]]
********************
[[ 0 1]
[10 11]
[20 21]
[30 31]]
********************
[[ 0 2]
[10 12]
[20 22]
[30 32]]
参考配图
切片结果为[]的原因
- 一种特殊的情况就是我们输入的索引超出了数据的索引,当start或end超出上文提到的有效索引范围?时,切片操作不会抛出异常,而是进行截断。
- 如果start的索引大于end索引,Python还是不会抛出异常,而是直接返回空序列。
- 当start_index表示的实际位置在end_index的左边时,而step为负数。
- 当start_index表示的实际位置在end_index的右边时,而step为正数,上面第二种为此类的特殊情况,即步长默认为1。
print(X[0:2,5::])
print('**'*10)
print(X[3:2,2::])
print('**'*10)
print(X[1:3:-1])
print('**'*10)
print(X[3:1:1])
[]
********************
[]
********************
[]
********************
[]
更高维度的数据,跟二维的是类似的,只是要输入正确的维度即可。
总结!!!
- start_index表示切片起始位置、end_index结束位置、step表示步长(为正表示从左到右,为负表示从右到左),所以一定要注意start_index、end_index、step三者的关系,否则可能得到空的结果。
- 当start_index或end_index省略时,取值的起始索引和终止索引由step的正负来决定,这种情况不会有取值方向矛盾(即不会返回空列表[]),但正和负取到的结果顺序是相反的,因为一个向左一个向右。
- “取单个元素(不带“:”)”时,返回的是对象的某个元素,其类型由元素本身的类型决定,而与母对象无关,如上面的a[0]=0、a[-4]=6,元素0和6都是“数值型”,而母对象a却是“list”型;“取连续切片(带“:”)”时,返回结果的类型与母对象相同,哪怕切取的连续切片只包含一个元素,如上面的a[-1:]=[9],返回的是一个只包含元素“9”的list,而非数值型“9”。
参考文章 彻底搞懂Python切片操作 Python中numpy数组切片
|