目录
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