NumPy-切片和索引


对于内容的引用说明:

Numpy 笔记(二): 多维数组的切片(slicing)和索引(indexing):http://www.zmonster.me/2016/03/09/numpy-slicing-and-indexing.html,感谢ZMonster's Blog原创内容。


ndarray对象的内容可以通过索引或切片来访问和修改,ndarray对象中的元素遵循基于零的索引。 有三种可用的索引方法:字段访问,基本切片高级索引

基本切片是 Python 中基本切片概念到 n 维的扩展。 通过将startstopstep参数提供给内置的slice函数来构造一个 Pythonslice对象。 此slice对象被传递给数组来提取数组的一部分。简而言之,切片是有索性。

1、基本原理是这样:

1、切片需要使用序列生成,即冒号运算符‘:‘,一个单冒号为选取整个序列,也可以指定范围,如1:5表示1~4(包括)这4个元素。同时可以指定步长如1:6:2表示选取1,3,5这3个元素,其中start=1,stop=6,step=2,这个与Python的列表切片是一致的。

2、然后,使用逗号,来区分轴(axis),轴可以简单地理解为在某个维度上的投影。例如axis=0指的就是行,axis=1指的就是列。那么第一个选取就是行,第二个选取的就是列,中间用逗号隔开,例如下面的一条语句。

arr[:,2]

在行上选取的是:,即整个序列,在列上选取的是2,即第3列,这样得到的结果就是第三列(注意这时候得到的是行向量而不是列向量)

2、数组的索引和切片抽象表示:

  • 索引:获取数组中特定位置元素的过程。
  • 切片:获取数组元素子集的过程。

  • 一维数组的索引和切片:与Python的列表类似

    • a[n] :返回第n+1个元素。如果n为负数,则返回倒着数第n个元素。
    • a[n:m:k] :起始编号n,终止编号m,步长k,用冒号分割。如果n为空,即 n = 0 ;如果m为空,即 m = len(a)
  • 多维数组的索引和切片:

    • a[n,m,k,...] :每个维度一个索引值,最外list中第n个元素,倒数第二外list中第m个元素,以此类推。如果n为负数,则返回倒着数第n个元素。
    • a[n1:m1:k1,n2:m2:k2,n3:m3:k3,...] :每个维度的切片方法与一维数组相同。顺序为从外到内

3、切片操作

Numpy中多维数组的切片操作与Python中list的切片操作一样,同样由start,stop,step三个部分组成。

示例1

import numpy as np
a = np.arange(10)
s = slice(2,7,2)
print(a[s])

输出如下:

[2  4  6]

在上面的例子中,ndarray对象由arange()函数创建。 然后,分别用起始,终止和步长值272定义切片对象。 当这个切片对象传递给ndarray时,会对它的一部分进行切片,从索引27,步长为2

通过将由冒号分隔的切片参数(start:stop:step)直接提供给ndarray对象,也可以获得相同的结果。

示例2

import numpy as np
a = np.arange(10)
b = a[2:7:2]
print(b)

输出如下:

[2  4  6]

如果只输入一个参数,则将返回与索引对应的单个项目。 如果使用a:,则从该索引向后的所有项目将被提取。 如果使用两个参数(以:分隔),则对两个索引(不包括停止索引)之间的元素以默认步骤进行切片。

示例3

#对单个元素进行切片  
import numpy as np

a = np.arange(10)
b = a[5]
print(b)

输出如下:

5

示例4

#对始于索引的元素进行切片  
import numpy as np
a = np.arange(10)
print(a[2:])

输出如下:

[2  3  4  5  6  7  8  9]

示例5

#对索引之间的元素进行切片  
import numpy as np
a = np.arange(10)
print(a[2:5])

输出如下:

[2  3  4]

上面的描述也可用于多维ndarray

示例6

import numpy as np
a = np.array([[1,2,3],[3,4,5],[4,5,6]])
print(a)
# 对始于索引的元素进行切片
print('\n现在我们从索引 a[1:] 开始对数组切片')
print(a[1:])

输出如下:

[[1 2 3]
 [3 4 5]
 [4 5 6]]

现在我们从索引 a[1:] 开始对数组切片
[[3 4 5]
 [4 5 6]]

切片还可以包括省略号(...),来使选择元组的长度与数组的维度相同。 如果在行位置使用省略号,它将返回包含行中元素的ndarray

示例7

#省略号必须是三个

#最开始的数组
import numpy as np
a = np.array([[1,2,3],[3,4,5],[4,5,6]])
print(a)

# 这会返回第二列元素的数组:
print('\n第二列的元素是:')
print(a[...,1]) 

# 现在我们从第二行切片所有元素:
print('\n第二行的元素是:')
print(a[1,...])

# 现在我们从第二列向后切片所有元素:
print('\n第二列及其剩余元素是:')
print(a[...,1:])

输出如下:

我们的数组是:
[[1 2 3]
 [3 4 5]
 [4 5 6]]

第二列的元素是:
[2 4 5]

第二行的元素是:
[3 4 5]

第二列及其剩余元素是:
[[2 3]
 [4 5]
 [5 6]]

4、索性操作

最简单的情况,对于一个多维数组来说,最简单的情况就是访问其中一个特定位置的元素了,如下所示:

# coding: utf-8
import numpy as np
arr = np.array([
    [1, 2, 3, 4],
    [2, 4, 6, 8],
    [3, 6, 9, 12],
    [4, 8, 12, 16]
])
print( '第二行第二列的值:', arr[1, 1])
第二行第二列的值: 4

相比之下,如果用Python的list来表示上述二维数组,获取同一个位置的元素的方法为:

# coding: utf-8
arr = [
    [1, 2, 3, 4],
    [2, 4, 6, 8],
    [3, 6, 9, 12],
    [4, 8, 12, 16]
]
print ('第二行第二列的值:', arr[1][1])

try:
    print ('第二行第二列的值(尝试用 Numpy 的方式获取):', arr[1, 1])
except Exception as e:
    print(str(e))

输出如下:

第二行第二列的值: 4
list indices must be integers or slices, not tuple

如果只是二维数组,这种差别可能看起来并不大,但想象一下假如有一个10维的数组,用Python的标准做法需要写10对中括号,而用Numpy依然只需要一对。

获取多个元素

事实上,在Numpy的索引操作方式`x=arr[obj]`中,obj不仅仅可以是一个用逗号分隔开的数字序列,还可以是更复杂的内容。

  1. 用逗号分隔的数组序列

    • 序列的长度和多维数组的维数要一致
    • 序列中每个数组的长度要一致
import numpy as np

arr = np.array([
    [1, 2, 3, 4],
    [2, 4, 6, 8],
    [3, 6, 9, 12],
    [4, 8, 12, 16]
])

print(arr[[0, 2], [3, 1]])

输出:

[4 6]

以上面这个例子来说,其含义是:选择第一行和第三行,然后对第一行选择第四列,对第三行选择第二列。

2.boolean/maskindex

这个不太好翻译,所以就用原来的英语表达。

所谓booleanindex,就是用一个由boolean类型值组成的数组来选择元素的方法。比如说对下面这样多维数组

array([[1, 2, 3, 4],
       [2, 4, 6, 8],
       [3, 6, 9, 12],
       [4, 8, 12, 16]])

如果要取其中值大于5的元素,就可以用上 boolean index 了,如下所示:

import numpy as np

arr = np.array([[1, 2, 3, 4],
                [2, 4, 6, 8],
                [3, 6, 9, 12],
                [4, 8, 12, 16]])
mask = arr 
>
 5

print ('boolean mask is:')
print (mask)

print (arr[mask])

输出如下:

boolean mask is:
[[False False False False]
 [False False  True  True]
 [False  True  True  True]
 [False  True  True  True]]
[ 6  8  6  9 12  8 12 16]

除了比较运算能产生booleanmask数组以外,Numpy本身也提供了一些工具方法:

  • numpy.iscomplex
  • numpy.isreal
  • numpy.isfinite
  • numpy.isinf
  • numpy.isnan

5、切片和索引的同异

切片和索引都是访问多维数组中元素的方法,这是两者的共同点,不同之处有:

  1. 切片得到的是原多维数组的一个视图(view),修改切片中的内容会导致原多维数组的内容也发生变化
  2. 切片得到在多维数组中连续(或按特定步长连续)排列的值,而索引可以得到任意位置的值,自由度更大一些

不考虑第一点的话,切片的操作是可以用索引操作来实现的,不过这没有必要就是了。

对于第一点,见下面的实验:

import numpy as np

arr = np.arange(12).reshape(2, 6)
print('array is:')
print( arr)

slc = arr[:, 2:5]
print ('slice is:')
print (slc)

slc[1, 2] = 10000
print ('modified slice is:')
print (slc)
print ('array is now:')
print (arr)

输出如下:

array is:
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]]
slice is:
[[ 2  3  4]
 [ 8  9 10]]
modified slice is:
[[    2     3     4]
 [    8     9 10000]]
array is now:
[[    0     1     2     3     4     5]
 [    6     7     8     9 10000    11]]

results matching ""

    No results matching ""