1. 多维数组的切片操作
1) 列表切片与Numpy数组切片
在讲解多维数组的切片操作之前,我们看一看简单的一维数组切片是如何进行操作的,我们知道在 Python 的列表类型中有浅拷贝和深拷贝之说,在一个列表上进行切片操作,会生成一个新的列表。也就是说列表的切片操作不会影响到列表源数据。
In [1]: a=[1,2,3,4,5,6] In [2]: a[::] Out[4]: [1, 2, 3, 4, 5, 6] In [3]: a=[1,2,3,4,5,6] In [4]: id(a) #原列表内存地址 Out[4]: 136347440 In [5]: id(a[::]) #切片后新列表的内存地址 Out[5]: 136153128
由上述代码可见内存地址发生了变化。下面我们看看 Numpy 数组的切片是怎样的,如下:
In [1]: import numpy as np In [2]: data=np.array([1,2,3,4]) #切片操作 In [3]: data[0:4] Out[3]: array([1, 2, 3, 4]) In [4]: id(data) Out[4]: 84768232 #切片赋值操作 In [5]: data[0:4]=1 In [6]: data Out[6]: array([1, 1, 1, 1]) #内存地址相同 In [7]: id(data) Out[7]: 84768232
由此可见,当你传递一个数值给数组的切片的时候,数据被传递给了整个切片,这代表数据并不是被复制了,而是说明数组切片是在源数组上进行的。我们继续上面的演示:
#截取data1生成新的数组 In [12]: data1=data[1:3] In [13]: data1 Out[13]: array([1, 1]) #分别利用索引给data和data1的0位置进行赋值 In [14]: data[0]=12134 In [15]: data1[0]=12134 #在调用data原数组 In [16]: data Out[16]: array([12134, 12134, 1, 1])
可以看到非常神奇的事情发生了,当我们改变 data1时候,最终的变化也会体现在原数组上,初次接触到 Numpy 的小伙伴也许会感到惊讶,那么为什么会是这个样子的呢?
其实 Numpy 设计之初是针对非常大的数组来开发的,这就带来一个问题,如果 Numpy 每一次切片操作都要复制数据,这将会引起多少的内存占用。所以 Numpy 采用这种设计方式比较适合自身的特性。如果你就是想要一份数组切片的拷贝的话,这里需要使用 copy() 方法,将会得到一个副本,而上述过程中对原数组切片操作后得到的数组称为视图,比如原数组是a,切片后得到 b 数组,那么 b 叫做 a 的视图,这在下一篇文章我们还会讲解。
data[1:3].copy() #得到数组的副本
如果操作副本的话,将不会影响到源数组数据。
2) 二维数组切片基本操作
下面我们看二维数组的切片操作,示例如下:
In [1]: import numpy as np In [2]: a=np.array([[1,2,3],[4,5,6]]) In [3]: a Out[3]: array([[1, 2, 3], [4, 5, 6]]) In [4]: a[:] Out[4]: array([[1, 2, 3], [4, 5, 6]]) In [5]: a[0:1] Out[5]: array([[1, 2, 3]]) In [6]: a[1:2] Out[6]: array([[4, 5, 6]]) In [7]: a[:2] Out[7]: array([[1, 2, 3], [4, 5, 6]])
数组的切片操作,如 a[:2] 表示前两行,即 a 数组的全部,此时把 a 看做一个整体来进行操作,同时我们还可以进行多数组切片,这与多数组索引的使用方法类似,如下所示:
In [1]: import numpy as np In [2]: a=np.array([[1,2,3],[4,5,6]]) In [3]: a Out[3]: array([[1, 2, 3], [4, 5, 6]]) In [4]: a[:,1] Out[4]: array([2, 5]) In [5]: a[1,:] Out[5]: array([4, 5, 6]) In [6]: a[:,:] Out[6]: array([[1, 2, 3], [4, 5, 6]]) In [7]: a[0,:] Out[7]: array([1, 2, 3]) In [8]: a[1:,:] Out[8]: array([[4, 5, 6]])
对于二维数组来说,我们要按照行列的思想去理解它,形如 a[n,:]、a[:,n]、a[m:n,:]、a[:,m:n],都属于二维数组的切片形式,中括号中的第一个位置代表截取行,第二个位置代表截取列,中间需用逗号隔开。注意,我们要将 m:n 看做是一个整体,使用切片操作二维数组的中括号中就有一个冒号,三维数组就会有两个冒号,以此类推,且每个冒号与之间用逗号隔开,如 a[1:,:] 它的含义可以这样理解:
- 行位置表示截取第一行开始到末行终止;
- 列位置表示截取所有的列;
3) 三维数组切片的理解
按照上面二维数组的操作方式,理解三维数组的切片操作会简单一些,还是按照三维数组中 [个数:行:列] 的思想去理解它。三维的切片形如 b[n,::]、b[:,n:]、b[::,n]、b[:,:,n]、b[m:n,::]、b[:,m:n:]、b[::,m:n]、b[:,:,m:n],下面看一些简单的示例操作,方便大家进行理解:
In [15]: b=np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]) #生成三维数组,由两个二维数组组成 In [16]: b Out[16]: array([[[ 1, 2, 3], [ 4, 5, 6]], [[ 7, 8, 9], [10, 11, 12]]]) In [16]: b[1,1,:] Out[16]: array([10, 11, 12]) #最后生成的是两行两列的数组 In [17]: b[:,:,1] Out[17]: array([[ 2,5], [ 8,11]])
只要记住中括号中的三个位置分别代着不同的操作,这样理解起来就变得非常简单了。本节知识的需要各位小伙伴以注重理解为先,根据示例大家要多多的动手操作,用心去体会它的使用方法。
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/24092.html