第3章 Numpy计算科学模块(二):切片与数组变形

目录

3.1 numpy数组的切片

 3.1.1切片的定义

3.1.2一维数组切片的使用 

3.1.3多维数组切片的使用

3.1.4多维数组的单索引切片的使用

3.1.5获取二维数组的行与列

3.1.6(重要)切片返回的是数组的视图

3.1.7通过copy()方法创建子数组的副本

3.2numpy数组的变形

3.2.1数组变形reshape()方法

3.2.2reshape()方法返回的是视图

3.2.3reshape()方法将低维数组进行升维操作

3.2.4reshape()方法将高维数组进行降维操作

3.2.5使用np.newaxis关键字将低维数组进行升维操作

3.1 numpy数组的切片


索引永远用中括号  

 3.1.1切片的定义

类似于 python 的列表, Numpy 数组同样可以使用切片 (slice) 来获取子数组,切片操作符用冒号表示。
语法:为获取数组的一个切片(子数组),使用:
x[start:stop:step]
一个完整的切片表达式包含两个冒号。
start 为开始索引, stop 为终止索引(不包括当前索引元素)。 step 为步长。
当只有一个冒号时, start=end ,表示切取 start 指定的那个元素。此时,退化为单索引。
如果以上 3 个参数都未指定,那么他们会被分别设置默认值 start=0 stop= 维度的大小)
step=0 ,此时, x(::) 为全数组 x 本身

3.1.2一维数组切片的使用 

一维数组的切片和 list 切片的使用类似。
注意:切片获得的子数组不包括 stop 索引的元素,子数组的范围是从 start stop-1
import numpy as np
x = np.arange(10)
print(x)
print(x[:5])#前五个元素
print(x[5:])#索引五之后的元素
print(x[4:7])#中间的子数组
print(x[::2])#每隔一个元素
print(x[1::2])#每隔一个元素,从索引1开始
[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4]
[5 6 7 8 9]
[4 5 6]
[0 2 4 6 8]
[1 3 5 7 9]
step 为负值时, start 为最大索引元素, stop 为最小索引元素(不包括此元素)。此时,输出逆序子 数组。逆序子数组的范围是从strat stop-1
import numpy as np
x = np.arange(10)
print(x)
print(x[::-1])#所有元素,输出逆序数全数组
print(x[6:2:-1])#从索引6开始,到索引2结束(不包括),逆序子数组
print(x[5::-2])#从索引5开始,每隔一个元素,输出逆序子数组
[0 1 2 3 4 5 6 7 8 9]
[9 8 7 6 5 4 3 2 1 0]
[6 5 4 3]
[5 3 1]
习题
随机生成一个 size=(10,) 的一维数组。通过切片操作,获得 [2,7) 的子数组;获得 [8,1) 的逆序子数
组;获得 [4,10] 间隔为 2 的子数组;获得 [6,1] 间隔为 3 的逆序子数组
import numpy as np
np.random.seed(5)
x = np.random.randint(10,size=(10,))
print(x)
print(x[2:7])#获得[2,7)的子数组
print(x[8:1:-1])#获得[8,1)的逆序子数组
print(x[4:10:2])#获得[4,10]间隔为2的子数组
print(x[6:1:-3])#获得[6,1]间隔为3的逆序子数组
[3 6 6 0 9 8 4 7 0 0]
[6 0 9 8 4]
[0 7 4 8 9 0 6]
[9 4 0]
[4 0]

3.1.3多维数组切片的使用

多维数组与一维数组类似,分别对每个维度的索引进行切片操作。
    多维通过 相隔,比如对二维数组的切片: x[start:stop:step,start:stop:step]
    多维索引可以类比为多维空间的坐标。那么多维切片,就是获得元素的多维索引坐标。
    对于二维数组,通常将第 1 维称为行,第 2 维称为列
    对于多维数组,一般直接称某一维,如第 1 维,第 3
import numpy as np
np.random.seed(0)#设置随机数种子
x = np.random.randint(10,size=(3,4))#生成随机整数数组(3,4)
print(x)
print('-----')
print(x[:2,:3])
print('-----')
print(x[:1,:2])
[[5 0 3 3]
[7 9 3 5]
[2 4 7 6]]
-----
[[5 0 3]
[7 9 3]]
-----
[[5 0]]
x2[:2, :3] 切片的子数组元素,可以先按一维切片方式理解。
第一维: :2 对应切片范围为 [,2) ,索引为 0,1 ,规模为 2
第二维: :3 对应切片范围为 [,3) 。索引为 0,1,2 ,规模为 3
习题
1. 随机生成二维的整形数组 size=(6,7) 。为每个子数组输出 ndim shape
2. 取第3 行的所有元素;
    取第 4 列的所有元素;
    取第 3 行,第 [0,2) 范围的列元素;
    取第 2 列,第 [0,4) 范围的行元素;
    取第 [0,2) 范围的行和第 [2,5) 范围的列元素;
    行按间隔为 2 和列按间隔为 3
    逆序操作数组。
import numpy as np
np.random.seed(0)
x = np.random.randint(42,size=(6,7))
print(x)
print('-----')
print(x[2:3,0:7],x[2:3,0:7].ndim,x[2:3,0:7].shape)#取第3行的所有元素
print('-----')
print(x[0:7,3:4],x[0:7,3:4].ndim,x[0:7,3:4].shape)#取第4列的所有
print('-----')
print(x[2:3,0:2],x[2:3,0:2].ndim,x[2:3,0:2].shape)#取第3行,第[0,2)范围的列元素;
print('-----')
print(x[0:4,1:2],x[0:4,1:2].ndim,x[0:4,1:2].shape)#取第2列,第[0,4)范围的行元素;
print('-----')
print(x[0:2,2:5],x[0:2,2:5].ndim,x[0:2,2:5].shape)#取第[0,2)范围的行和第[2,5)范围的
列元素;
print('-----')
print(x[::2,::3])#行按间隔为2和列按间隔为3;
print('-----')
print(x[::-1,::-1])#逆序操作数组。
[[ 0 3 3 39 9 19 21]
[36 23 6 24 24 12 1]
[38 39 23 24 17 37 25]
[13 8 9 20 16 5 15]
[ 0 18 35 24 29 19 19]
[14 39 32 1 9 32 31]]
-----
[[38 39 23 24 17 37 25]] 2 (1, 7)
-----
[[39]
[24]
[24]
[20]
[24]
[ 1]] 2 (6, 1)
-----
[[38 39]] 2 (1, 2)
-----
[[ 3]
[23]
[39]
[ 8]] 2 (4, 1)
-----
[[ 3 39 9]
[ 6 24 24]] 2 (2, 3)
-----
[[ 0 39 21]
[38 24 25]
[ 0 24 19]]
-----
[[31 32 9 1 32 39 14]
[19 19 29 24 35 18 0]
[15 5 16 20 9 8 13]
[25 37 17 24 23 39 38]
[ 1 12 24 24 6 23 36]
[21 19 9 39 3 3 0]]
1

3.1.4多维数组的单索引切片的使用

对于 N 维数组,通过对某个维度进行单索引,获得 N-1 维的子数组。
       二维数组,获得第 n 行元素(一维数组), X[n,:] 。第 m 列元素(一维数组), X[:,m]
       三维数组, x[:,n,:] 为二维子数组,表示为在第 2 维度上对第 n 个索引进行切片(其他维度规模不
变)
       理解:三维 x-y-z 空间中,在 y 轴上的第 n 个坐标点上切一刀 ( 沿着平行于 x z 轴方向 ) ,获得一个二维平面。 再高维的话,可以抽象理解。从线性代数角度, N 维空间的 N - 1 维子空间。
import numpy as np
np.random.seed(0)
x = np.random.randint(42,size=(6,7))
print(x)
[[ 0 3 3 39 9 19 21]
[36 23 6 24 24 12 1]
[38 39 23 24 17 37 25]
[13 8 9 20 16 5 15]
[ 0 18 35 24 29 19 19]
[14 39 32 1 9 32 31]]
print(x[:,2])
[ 3 6 23 9 35 32]
print(x[1,:])
[36 23 6 24 24 12 1]
在子数组中,通过对某个维度使用:切片,保持该维度元素规模不变。二维数组 x[:,start:stop:step] , 第一维保持不变,只对第二维进行切片。
print(x[:,::2])#切片为所有行元素,列为间隔元素
[[ 0 3 9 21]
[36 6 24 1]
[38 23 17 25]
[13 9 16 15]
[ 0 35 29 19]
[14 32 9 31]]
print(x[::-1,::-1])#当step为负值时,获得多维子数组的逆序操作
[[31 32 9 1 32 39 14]
[19 19 29 24 35 18 0]
[15 5 16 20 9 8 13]
[25 37 17 24 23 39 38]
[ 1 12 24 24 6 23 36]
[21 19 9 39 3 3 0]]
习题
1. 随机生成三维的整形数组 size=(3,4,2) 。为每个子数组输出 ndim shape
import numpy as np
x = np.random.randint(24,size=(3,4,2))
print(x)
[[[10 20]
[23 3]
[11 18]
[23 2]]
[[ 0 0]
[ 4 21]
[ 5 6]
[ 8 20]]
[[17 15]
[ 4 9]
[10 1]
[ 1 7]]]
2. 在第2 维上取第 2 个索引,其他维保持不变。 x[:,1,:] 。此时的子数组是几维的?
print(x[:,1,:])
print(x[:,1,:].ndim,x[:,1,:].shape)
[[23 3]
[ 4 21]
[ 4 9]]
2 (3, 2)

3. 在第3维上取第1个索引,其他维保持不变。此时的子数组是几维的

print(x[:,:,0])
print(x[:,:,0].ndim,x[:,:,0].shape)
[[10 23 11 23]
[ 0 4 5 8]
[17 4 10 1]]
2 (3, 4)

4. 在第1维上取第2个索引,在第2维上取第1个索引,第3维保持不变。此时的子数组是几维的

print(x[1,0,:])
print(x[1,0,:].ndim,x[1,0,:].shape)
[0 0]
1 (1,2)

3.1.5获取二维数组的行与列

获取二维数组的单行和单列。可以将索引与切片组合起来实现这个功能,用一个冒号表示空切片
import numpy as np
x = np.random.randint(10,size=(3,4))
print(x)
print(x[:,0])#x的第一列
print(x[0,:])#x的第一行
[[9 1 7 8]
[7 4 6 4]
[4 0 7 0]]
[9 7 4]
[9 1 7 8]
切片的省略
       切片语法上,对于多维数组,如果高维的切片使用冒号,可以省略冒号
       如果低维的切片使用冒号,那么该冒号不可省略
       x 2 维数组, x[0,:] 可等价于 x[0] , x[:,0] 不可等价于 x[0]
       x 3 维数组, x[0,:,:] 可等价于 x[0] ; x[:,0,:] 可等价于 x[:,0]
import numpy as np
x = np.random.randint(10,size=(2,3,4))
print(x)
print(x[:,2,:])
print(x[:,2])
[[[1 8 6 3]
[9 8 8 6]
[8 3 3 2]]
[[9 7 1 5]
[7 5 4 3]
[3 8 0 7]]]
[[8 3 3 2]
[3 8 0 7]]
[[8 3 3 2]
[3 8 0 7]]
习题
随机生成一个二维数组,使用切片获得单行和单列。
import numpy as np
x = np.random.randint(10,size=(2,3))
np.random.seed(1)
print(x)
print(x[0,:])
print(x[:,0])
[[5 8 9]
[5 0 0]]

[5 8 9]

[5 5]
随机生成一个三维数组,使用切片获得第 1 维第某个索引的切平面、第 3 维某个索引的切平面。
import numpy as np
x = np.random.randint(10,size=(3,3,4))
np.random.seed(1)
print(x)
print(x[0,0,:])
print(x[2,0,:])
[[[5 8 9 5]
[0 0 1 7]
[6 9 2 4]]

[[5 2 4 2]
[4 7 7 9]
[1 7 0 6]]

[[9 9 7 6]
[9 1 0 1]
[8 8 3 9]]]

[5 8 9 5]
[9 9 7 6]

3.1.6(重要)切片返回的是数组的视图

数组切片操作返回的子数组是原数组的一个视图,而不是数值数据的副本。
       对子数组修改会直接修改原数组元素
       NumPy 数组切片和 Python 列表切片的不同之处:在 Python 列表中,切片是值的副本 ( 对副本修改,不影响原列表)
       专有名词: 副本 (copy) 指的是从内存空间中 开辟一个新的空间 ,存储该数组的一份拷贝。
       专有名词: 视图 (view) 指的是 共享原数组的内存空间 ,子数组是原数组的一个片段。
import numpy as np
x = np.random.randint(10,size=(3,4))
np.random.seed(1)
print(x)
x_sub = x[:2,:2]
print(x_sub)
[[5 8 9 5]
[0 0 1 7]
[6 9 2 4]]
[[5 8]
[0 0]]
现在如果修改这个子数组,将会看到 原始数组也被修改了! 结果如下所示:
print(x)
x_sub[0,0] = 99
print(x_sub)
print(x)
[[5 8 9 5]
[0 0 1 7]
[6 9 2 4]]
[[99 8]
[ 0 0]]
[[99 8 9 5]
[ 0 0 1 7]
[ 6 9 2 4]]
这种处理方式非常有用。如果原数组的规模非常大,通过 numpy 的切片操作,可以获得或处理数组的某些数据的片段,而不用复制底层的数据缓存

 习题

随机生成一个服从高斯分布的 2 维数组 size=(5*5) ,通过切片获得子数组,然后对切片子数组进行修改,验证切片返回为原数组的视图。

 

import numpy as np
x = np.random.normal(0,1,size=(5,5))
np.random.seed(1)
print(x)
x_sub = x[:2,:2]
print(x_sub)
print(x)
x_sub[0,0] = 99
print(x_sub)
print(x)

3.1.7通过copy()方法创建子数组的副本

尽管数组视图有一些非常好的特性,但是在有时需要明确地复制数组里的数据(子数组),或者是希望对子数组操作不影响原数组,numpy 提供了 copy() 方法,创建数组的一个拷贝或副本

 

import numpy as np
x = np.random.randint(10,size=(3,4))
print(x)
print('\n')

x_copy = x[:2,:2].copy()#创建子数组的一个副本
print(x_copy)
print('\n')

x_copy[0,0] = 42
print(x_copy)
print(x)
习题
随机生成一个服从高斯分布的 2 维数组 size=(5*5) ,通过切片获得子数组,然后分别验证它的视
图和副本模式。
import numpy as np
x = np.random.normal(10,size=(5,5))
print(x)
print('\n')

#副本模式
x_copy = x[:2,:2].copy()#创建子数组的一个副本
print(x_copy)
print('\n')

x_copy[0,0] = 42
print(x_copy)
print(x)

3.2numpy数组的变形


3.2.1数组变形reshape()方法

numpy.reshape(a,newshape) 

描述:通过 reshape() 实现数组变形,修改原始数组 shape 属性的方法。 不能改变元素总个数
参数 :a 为需要变形的数组。
参数: newshape 为变形后的 size ,可以输入元组( tuple )整形类型。比如原数组的 size=(1,9)
那么变形后的数组可以为 size=(3,3); 但是不能为 size=(2,3)
返回:变形后数组为原数组的一个视图,对该数组操作会改变原数组。
变形条件:原始数组的大小必须和变形后数组的大小一致,否者将会出错。

 

import numpy as np
x = np.arange(1,10)
print(x)
print(x.shape)#输出原数组的规模
x1 = x.reshape((3,3))
print(x1)
print(x1.shape)
[1 2 3 4 5 6 7 8 9]
(9,)
[[1 2 3]
[4 5 6]
[7 8 9]]
(3, 3)
reshape() 可以把数组从一维变成高维,但是不管怎么变,元素的个数要保持一致
reshape() 里的参数 (2,3) 是一个元组类型的参数
习题
随机生成一个自定义的二维数组,通过 reshape(), 转换为行向量,列向量,任意的二维数组,并输
出相应的数组 shpe nidm
import numpy as np
x = np.random.randint(6,size=(2,3))
print(x)
print(x.shape)#输出原数组的规模
print('\n')
x_row = x.reshape((6,))
print(x_row)
print(x_row.shape,x_row.ndim)
print('\n')
x_column = x.reshape((1,6))
print(x_column)
print(x_column.shape,x_column.ndim)
[[0 4 1]
[0 1 5]]
(2, 3)

[0 4 1 0 1 5]
(6,) 1

[[0 4 1 0 1 5]]
(1, 6) 2

3.2.2reshape()方法返回的是视图

变形后数组为原数组的一个 视图 ,对该数组操作会改变原数组。
import numpy as np
x = np.arange(1, 10);
print('x:', x)
print('\n')
x1 = x.reshape((3, 3))
print('x1:', x1)
print('\n')
x1[0,0] = 3
# 对比结果,发现对变形后数组改变,会影响原数组元素的值
print('x:', x)
print('\n')
print('x1:', x1)
x: [1 2 3 4 5 6 7 8 9]

x1: [[1 2 3]
[4 5 6]
[7 8 9]]

x: [3 2 3 4 5 6 7 8 9]

x1: [[3 2 3]
[4 5 6]
[7 8 9]]
习题
随机生成一个自定义的二维数组,通过 reshape() ,转换为任意形状的二维数组、并输出相应的
数组 shape ndim
import numpy as np
x = np.arange(1,13)
print(x)
print('\n')
x_reshape = x.reshape((3,4))
print(x_reshape)
print('\n')
x_reshape[0,0]=125
print(x)
print('\n')
print(x_reshape)
print('\n')
print(x_reshape.shape,x_reshape.ndim)
[ 1 2 3 4 5 6 7 8 9 10 11 12]

[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]

[125 2 3 4 5 6 7 8 9 10 11 12]

[[125 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]

(3, 4) 2
1

3.2.3reshape()方法将低维数组进行升维操作

通过 reshape() 方法可以将一个一维数组转变为二维的列向量和行向量。
size=(n,) 是一维数组; size=(n,1) 是二维数组的列向量; size(1,n) 是二维数组的行向量
一维数组有一个 [] ; 二维数组有两个嵌套的 [[]]

 习题

随机生成一个自定义的一维数组,通过 reshape() ,转换为任意形状的二维数组、并输出相应的
数组 shape ndim

 

import numpy as np
x = np.array([1, 2, 3])
print(x.shape, x.ndim, '\n', x, '\n')

# 通过变形获得的行向量:x->x1
x1 = x.reshape((1, 3))
print(x1.shape, x1.ndim, '\n', x1, '\n')

# 通过变形获得的列向量:x1->x2
x2 = x.reshape((3, 1))
print(x2.shape, x2.ndim, '\n', x2, '\n')
(3,) 1
[1 2 3]

(1, 3) 2
[[1 2 3]]

(3, 1) 2
[[1]
[2]
[3]]
通过 reshape() ,转换为任意形状的三维数组、并输出相应的数组 shape ndim
import numpy as np
x = np.array([1, 2, 3,4,5,6])
print(x.shape, x.ndim, '\n', x, '\n')

# 通过变形获得的行向量:x->x1
x1 = x.reshape((3,2,1))

print(x1.shape, x1.ndim, '\n', x1, '\n')

# 通过变形获得的列向量:x1->x2
x2 = x.reshape((3,1,2))
print(x2.shape, x2.ndim, '\n', x2, '\n')
(6,) 1
[1 2 3 4 5 6]

(3, 2, 1) 3
[[[1]
[2]]

[[3]
[4]]

[[5]
[6]]]

(3, 1, 2) 3

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

3.2.4reshape()方法将高维数组进行降维操作

几维数组,那么就有几个嵌套的 []
习题
随机生成一个自定义的二维数组,通过 reshape() ,降维为一维数组,并输出相应的数组 shape
ndim
x = np.random.randint(10, size=(3, 4))
print(x.shape, x.ndim, '\n', x, '\n')

# (3,4)->(12,)
x1 = np.reshape(x, (12,))
print(x1.shape, x1.ndim, '\n', x1, '\n')
(3, 4) 2
[[2 6 4 7]
[8 8 0 6]
[9 8 9 3]]

(12,) 1
[2 6 4 7 8 8 0 6 9 8 9 3]
随机生成一个自定义的三维数组,通过 reshape() ,降维为二维数组、一维数组,并输出相应的
数组 shape ndim
import numpy as np
np.random.seed(2)
x = np.random.randint(10, size=(3,2,3))
print(x.shape, x.ndim, '\n', x, '\n')

# (3,4)->(12,)
x1 = np.reshape(x, (18,))
print(x1.shape, x1.ndim, '\n', x1, '\n')
(3, 2, 3) 3
[[[8 8 6]
[2 8 7]]

[[2 1 5]
[4 4 5]]

[[7 3 6]
[4 3 7]]]

(18,) 1
[8 8 6 2 8 7 2 1 5 4 4 5 7 3 6 4 3 7]

3.2.5使用np.newaxis关键字将低维数组进行升维操作

知识点:类似于 reshape() 功能,在切片中,可通过 np.newaxis 关键字,将低维数组进行升操作。
     np.newaxis numpy 关键字,非 python 关键字。
     x[np.newaxis, :] :将一维数组 x 在第 1 维上进行升维。原 x 是新二维数组的 x[0,:] 元素,变为行向量。
     x[:, np.newaxis] :将一维数组 x 在第 2 维上进行升维。原 x 是新二维数组的 x[:,0] 元素,变为列向量。
     由于只有 二维数组 ,才有行向量和列向量。为了抽象,建议用第 1 ( axis=0 ) 、第 2 ( axis=1 ) 来标识。
import numpy as np
x = np.array([1,2,3])
print(x.shape,x.ndim,'\n',x,'\n')
(3,) 1
[1 2 3]
#将一维数组x在第1维上进行升维
x1 = x[np.newaxis,:]
print(x1.shape,x1.ndim,'\n',x1,'\n')
print(x1[0,:])#原x元素是新二维数组x1[0,:]
(1, 3) 2
[[1 2 3]]

[1 2 3]
#将一维数组x在第2维上进行升维
x2 = x[:,np.newaxis]
print(x2.shape,x2.ndim,'\n',x2,'\n')
print(x2[:,0])#原x元素是新二维数组x2[:,0]
(3, 1) 2
[[1]
[2]
[3]]

[1 2 3]
import numpy as np
x = np.array([1,2,3])
print(x,x.shape,'\n')
#通过变形获得的行向量
print(x.reshape((1,3)),x.reshape((1,3)).shape,'\n')
#通过newaxis获得的行向量
print(x[np.newaxis,:],x[np.newaxis,:].shape,'\n')
#通过变形获得的列向量
print(x.reshape((3,1)),x.reshape((3,1)).shape,'\n')
#通过newaxis获得的列向量
print(x[:,np.newaxis],x[:,np.newaxis].shape)
[1 2 3] (3,)

[[1 2 3]] (1, 3)

[[1 2 3]] (1, 3)

[[1]
[2]
[3]] (3, 1)

[[1]
[2]
[3]] (3, 1)
1

 习题

随机生成一个自定义的 一维 数组,通过 np.newaxis ,升维为二维行向量、二维列向量,并输出相
应的数组 shape ndim
import numpy as np
x = np.array([1,2,3])
print(x,x.shape,'\n')
#通过变形获得的行向量
print(x.reshape((1,3)),x.reshape((1,3)).shape,'\n')
#通过newaxis获得的行向量
print(x[np.newaxis,:],x[np.newaxis,:].shape,'\n')
#通过变形获得的列向量
print(x.reshape((3,1)),x.reshape((3,1)).shape,'\n')
#通过newaxis获得的列向量
print(x[:,np.newaxis],x[:,np.newaxis].shape)
[1 2 3] (3,)

[[1 2 3]] (1, 3)

[[1 2 3]] (1, 3)

[[1]
[2]
[3]] (3, 1)

[[1]
[2]
[3]] (3, 1)
1

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值