#! https://zhuanlan.zhihu.com/p/426435347
一定要看到最后
一般我们要对一个列表切片
a = [1, 2, 3, 4, 5, 6]
a[1:3]
>>> [2, 3]
# 其实完整写法是
a[1:3:1]
>>> [2, 3]
所以方括号中的含义是 [start: stop: step]
,如果省略 start,默认就是从开头(索引0);如果省略 stop,默认就是到末尾(索引-1);如果省略 step,默认就是步长为1。
因此几个常见但让人摸不着头脑的用法是:
a = [1, 2, 3, 4, 5, 6]
a[:] # 全省略,就是从头到尾间隔1,即原始
>>> [1, 2, 3, 4, 5, 6]
a[::-1] # 从头到尾步长-1,即倒序
>>> [6, 5, 4, 3, 2, 1]
a[-1::] # 从倒数第一个开始到最后一个,即最后一个
>>> [6]
slice() 是 python 中的一个内置函数,实现切片对应,一般用在较为复杂的代码开头提前定义好切片的样式;等价于常用的简易版:
用法。我们来重复上述操作
myslice = slice(1,3)
a[myslice]
>>> [2, 3]
myslice = slice(None,3)
a[myslice]
>>> [1, 2, 3]
可以发现,使用slice时,空的部分需要写为None。
我们来看对多维数组的一些操作
import numpy as np
a = np.arange(9).reshape(3,3)
>>> array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
# 取出第一行所有元素
a[0]
>>> array([0, 1, 2])
# 取出前两行所有元素
a[:2]
>>> array([[0, 1, 2],
[3, 4, 5]])
# 取出第二列所有元素
a[:,1]
>>> array([1, 4, 7])
# 取出后两列所有元素
a[:,1:]
>>> array([[1, 2],
[4, 5],
[7, 8]])
在上述后面两个用法中,索引逗号前面的 :
代表了所有行。
还要补充一个关于...(ellipsis)
的用法,表示
import numpy as np
a = np.arange(9).reshape(3,3)
# 取出第二列所有元素
a[...,1]
>>> array([1, 4, 7])
似乎并没有简化,那我们再看一个例子
import numpy as np
a = np.arange(27).reshape(3,3,3)
>>> array([[[ 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, 25, 26]]])
# 取出第二个块所有元素
a[1,:,:]
>>> array([[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]])
# 等价于
a[1,...]
>>> array([[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]])
ellipsis会自动帮我们去填充,有点像tensor里的 -1 用法。
最后我们来看一点高级用法
import numpy as np
a = np.arange(27).reshape(3,3,3)
a[None].shape
>>> (1, 3, 3, 3)
# 这里的`None`表示在指定位置(此处是第一维)添加一维。
a[:,None].shape
>>> (3, 1, 3, 3)
# 这里的`None`表示在指定位置(此处是第二维)添加一维。
a[:,:,:,None].shape
>>> (3, 3, 3, 1)
# 等价于
a[...,None].shape
>>> (3, 3, 3, 1)
a[:,None,None].shape
>>> (3, 1, 1, 3, 3)
更复杂的情况
import numpy as np
a = np.arange(27).reshape(3,3,3)
a[:,None,...,None,None,None].shape
>>> (3, 1, 3, 3, 1, 1, 1)
# 等价于
myslice = (slice(None), None,) + (...,) + (None,)*3
>>> (slice(None, None, None), None, Ellipsis, None, None, None)
a[myslice].shape
>>> (3, 1, 3, 3, 1, 1, 1)
这样可以自定义更多的复杂组合,但必须使用到 slice()
而不是 :
这是因为 python 中的 None是一个对象,":" 是一个 slice() 对象,"..." 是一个 ellipse对象,所以是能拼一起或者各种操作的。