3、Numpy数组操作

1、数组广播机制:

1.1 数组与数的计算:

在Python列表中,想要对列表中所有的元素都加一个数,要么采用map函数,要么循环整个列表进行操作。但是NumPy中的数组可以直接在数组上进行操作。
示例代码如下:

import numpy as np
a1 = np.random.random((3,4))
print(a1)
# [[0.10254961 0.42006636 0.83411968 0.14746217]
#  [0.73549387 0.45227716 0.56687141 0.2311978 ]
#  [0.4628344  0.89336244 0.24550492 0.54512446]]

# 如果想要在a1数组上所有元素都乘以10,那么可以通过以下来实现
a2 = a1*10
print(a2)
# [[1.02549609 4.20066355 8.3411968  1.47462172]
#  [7.3549387  4.52277161 5.6687141  2.31197797]
#  [4.62834399 8.93362443 2.45504922 5.45124464]]

# 也可以使用round让所有的元素只保留2位小数
a3 = a2.round(2)
print(a3)
# [[1.03 4.2  8.34 1.47]
#  [7.35 4.52 5.67 2.31]
#  [4.63 8.93 2.46 5.45]]

注意:以上例子是相乘,其实相加、相减、相除也都是类似的。

1.2 数组与数组的计算:

1、结构相同的数组之间的运算:

a1 = np.arange(0,24).reshape((3,8))
a2 = np.random.randint(1,10,size=(3,8))
a3 = a1 + a2 #相减/相除/相乘都是可以的
print(a1)
# [[ 0  1  2  3  4  5  6  7]
#  [ 8  9 10 11 12 13 14 15]
#  [16 17 18 19 20 21 22 23]]
print(a2)
# [[6 3 4 7 3 1 9 9]
#  [8 6 8 6 9 4 9 6]
#  [1 5 2 4 2 8 4 2]]
print(a3)
# [[ 6  4  6 10  7  6 15 16]
#  [16 15 18 17 21 17 23 21]
#  [17 22 20 23 22 29 26 25]]

2、与行数相同并且只有1列的数组之间的运算:

a1 = np.random.randint(10,20,size=(3,8)) #3行8列
a2 = np.random.randint(1,10,size=(3,1)) #3行1列
a3 = a1 - a2 #行数相同,且a2只有1列,能互相运算
print(a1)
# [[17 13 10 10 16 15 16 10]
#  [13 17 12 10 13 17 14 10]
#  [18 16 16 19 19 14 19 15]]
print(a2)
# [[4]
#  [8]
#  [1]]
print(a3)
# [[13  9  6  6 12 11 12  6]
#  [ 5  9  4  2  5  9  6  2]
#  [17 15 15 18 18 13 18 14]]

3、与列数相同并且只有1行的数组之间的运算:

a1 = np.random.randint(10,20,size=(3,8)) #3行8列
a2 = np.random.randint(1,10,size=(1,8)) #1行8列
a3 = a1 - a2
print(a1)
# [[18 17 19 18 18 15 13 12]
#  [13 12 12 13 14 14 11 18]
#  [16 12 11 15 14 19 16 14]]
print(a2)
# [[9 4 3 7 3 5 1 8]]
print(a3)
# [[ 9 13 16 11 15 10 12  4]
#  [ 4  8  9  6 11  9 10 10]
#  [ 7  8  8  8 11 14 15  6]]

广播原则:

如果两个数组的后缘维度(trailing dimension,即从末尾开始算起的维度)的轴长度相符或其中一方的长度为1,则认为他们是广播兼容的。广播会在缺失和(或)长度为1的维度上进行。看以下案例分析:

shape为(3,8,2)的数组能和(8,3)的数组进行运算吗?
分析:不能,因为按照广播原则,从后面往前面数,(3,8,2)和(8,3)中的2和3不相等,所以不能进行运算。

shape为(3,8,2)的数组能和(8,1)的数组进行运算吗?
分析:能,因为按照广播原则,从后面往前面数,(3,8,2)和(8,1)中的2和1虽然不相等,但是因为有一方的长度为1,所以能参与运算。

shape为(3,1,4)的数组能和(8,1)的数组进行运算吗?
分析:能,因为按照广播原则,从后面往前面数,(3,1,4)和(8,1)中的4和1虽然不相等且1和8不相等,但是因为这两项中有一方的长度为1,所以能参与运算。

2、数组形状的操作:

可以通过一些函数,非常方便的操作数组的形状。

2.1 reshape和resize方法:

两个方法都是用来修改数组形状的,但是有一些不同。

1、reshape是将数组转换成指定的形状,然后返回转换后的结果,对于原数组的形状是不会发生改变的。调用方式:

a1 = np.random.randint(0,10,size=(3,4))
a2 = a1.reshape((2,6)) #将修改后的结果返回,不会影响原数组本身
print(a1)
# [[2 8 3 1]
#  [5 9 7 7]
#  [4 8 5 9]]
print(a2)
# [[2 8 3 1 5 9]
#  [7 7 4 8 5 9]]
print(a1)
# [[2 8 3 1]
#  [5 9 7 7]
#  [4 8 5 9]]

注意:a1数组的形状未发生改变。
2、resize是将数组转换成指定的形状,会直接修改数组本身。并不会返回任何值。调用方式:

a3 = np.random.randint(0,10,size=(3,4))
print(a3)
# [[8 4 3 0]
#  [8 1 0 7]
#  [0 6 9 8]]
a3.resize((2,6)) #a1本身发生了改变
print(a3)
# [[8 4 3 0 8 1]
#  [0 7 0 6 9 8]]

2.2 flatten和ravel方法:

两个方法都是将多维数组转换为一维数组,但是有以下不同:

1、flatten是将数组转换为一维数组后,然后将这个拷贝返回回去,所以后续对这个返回值进行修改不会影响之前的数组。
2、ravel是将数组转换为一维数组后,将这个视图(可以理解为引用)返回回去,所以后续对这个返回值进行修改会影响之前的数组。
比如以下代码:

x = np.array([[1, 2], [3, 4]])
print(x)
# [[1 2]
#  [3 4]]
x.flatten()[0] = 100 #此时的x[0]的位置元素还是1
print(x)
# [[1 2]
#  [3 4]]
x1 = x.flatten()
print(x1)
# [1 2 3 4]
x.ravel()[0] = 100 #此时x[0]的位置元素是100
print(x)
# [[100   2]
#  [  3   4]]

3、不同数组的组合:

如果有多个数组想要组合在一起,也可以通过其中的一些函数来实现。
1、np.vstack:将数组按垂直方向进行叠加。数组的列数必须相同才能叠加。
示例代码如下:

a1 = np.random.randint(0,10,size=(3,5))
a2 = np.random.randint(0,10,size=(1,5))
a3 = np.vstack([a1,a2])
print(a3)
# [[5 4 7 7 2]
#  [7 0 2 6 7]
#  [7 7 6 8 0]
#  [1 4 6 1 1]]

2、hstack:将数组按水平方向进行叠加。数组的行必须相同才能叠加。示例代码如下:

a1 = np.random.randint(0,10,size=(3,2))
a2 = np.random.randint(0,10,size=(3,1))
a3 = np.hstack([a1,a2])
print(a1)
# [[4 4]
#  [6 6]
#  [3 2]]
print(a2)
# [[2]
#  [5]
#  [3]]
print(a3)
# [[4 4 2]
#  [6 6 5]
#  [3 2 3]]

3、concatenate([ ],axis):将两个数组进行叠加,但是具体是按水平方向还是按垂直方向。则要看axis的参数,如果axis=0,那么代表的是往垂直方向(行)叠加如果axis=1,那么代表的是往水平方向(列)上叠加如果axis=None,那么会将两个数组组合成一个一维数组。需要注意的是,如果往水平方向上叠加,那么行必须相同,如果是往垂直方向叠加,那么列必须相同
示例代码如下:

a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
print(np.concatenate((a, b), axis=0))
# [[1 2]
#  [3 4]
#  [5 6]]#array([[1, 2],
#       [3, 4],
#       [5, 6]])
print(b.T)
# [[5]
#  [6]]
print(np.concatenate((a, b.T), axis=1)) #b.T对b进行转置
# [[1 2 5]
#  [3 4 6]]# 结果:
#array([[1, 2, 5],
#       [3, 4, 6]])

print(np.concatenate((a, b), axis=None))
# [1 2 3 4 5 6]#array([1, 2, 3, 4, 5, 6])

4、数组的切割:

通过hsplit和vsplit以及array_split可以将一个数组进行切割。

1、hsplit:按照水平方向进行切割。用于指定分割成几列,可以使用数字来代表分成几部分,也可以使用数组来代表分割的地方。示例代码如下:

a1 = np.arange(16.0).reshape(4, 4)
print(a1)
# [[ 0.  1.  2.  3.]
#  [ 4.  5.  6.  7.]
#  [ 8.  9. 10. 11.]
#  [12. 13. 14. 15.]]
print(np.hsplit(a1,2)) #分割成两部分
# [array([[ 0.,  1.],
#        [ 4.,  5.],
#        [ 8.,  9.],
#        [12., 13.]]), array([[ 2.,  3.],
#        [ 6.,  7.],
#        [10., 11.],
#        [14., 15.]])]
print(np.hsplit(a1,[1,2])) #代表在下标为1的地方切一刀,下标为2的地方切一刀,分成三部分
# [array([[ 0.],
#        [ 4.],
#        [ 8.],
#        [12.]]), array([[ 1.],
#        [ 5.],
#        [ 9.],
#        [13.]]), array([[ 2.,  3.],
#        [ 6.,  7.],
#        [10., 11.],
#        [14., 15.]])]

2、vsplit:按照垂直方向进行切割。用于指定分割成几行,可以使用数字来代表分成几部分,也可以使用数组来代表分割的地方。示例代码如下:

#vsplit:按照垂直方向进行切割。
a1 = np.arange(16.0).reshape(4, 4)
print(a1)
# [[ 0.  1.  2.  3.]
#  [ 4.  5.  6.  7.]
#  [ 8.  9. 10. 11.]
#  [12. 13. 14. 15.]]
print(np.vsplit(a1,2)) #代表按照行总共分成2个数组
# [array([[0., 1., 2., 3.],
#        [4., 5., 6., 7.]]), array([[ 8.,  9., 10., 11.],
#        [12., 13., 14., 15.]])]
print(np.vsplit(a1,(1,2))) #代表按照行进行划分,在下标为1的地方和下标为2的地方分割
# [array([[0., 1., 2., 3.]]), array([[4., 5., 6., 7.]]), array([[ 8.,  9., 10., 11.],
#        [12., 13., 14., 15.]])]

3、split/array_split(array,indicate_or_seciont,axis):用于指定切割方式,在切割的时候需要指定是按照行还是按照列,axis=1代表按照列,axis=0代表按照行。示例代码如下:

#split/array_split(array,indicate_or_seciont,axis):用于指定切割方式,
# 在切割的时候需要指定是按照行还是按照列,axis=1代表按照列,axis=0代表按照行。
a1 = np.arange(16.0).reshape(4, 4)
print(a1)
# [[ 0.  1.  2.  3.]
#  [ 4.  5.  6.  7.]
#  [ 8.  9. 10. 11.]
#  [12. 13. 14. 15.]]
print(np.array_split(a1,2,axis=0)) #按照垂直方向切割成2部分
# [array([[0., 1., 2., 3.],
#        [4., 5., 6., 7.]]), array([[ 8.,  9., 10., 11.],
#        [12., 13., 14., 15.]])]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值