Skip to content

Latest commit

 

History

History
172 lines (125 loc) · 3.59 KB

切片.md

File metadata and controls

172 lines (125 loc) · 3.59 KB

#! https://zhuanlan.zhihu.com/p/426435347

切片(slice) 省略(Ellipsis) None对象

一定要看到最后

一般我们要对一个列表切片

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()

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)

还要补充一个关于...(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)

引入None对象

更复杂的情况

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对象,所以是能拼一起或者各种操作的。