用实践带领你进入numpy的世界——(三):numpy基本运算讲解

                         QQ:3020889729                                                                                 小蔡

本节主要讲解numpy基本运算讲解。
补充,阅读时,如出现‘点积‘,请忽略,本文不包含该术语名词——仅仅含有’内积‘的叫法和‘矩阵乘法’
在这里插入图片描述
本文以jupyter notebook格式展开~
引入numpy库

import numpy as np

numpy数组的加法运算(减法类推)

标量相加-向量相加-矩阵相加

标量相加

创建标量数据——标量:即仅包含一个元素——一般来说它仅仅存在于0轴(维度)上

data_one = np.array([1], dtype=np.int32)  
data_two = np.array([0.5], dtype=np.float32)
print("data_one: \n数组内容:{0}, 数据类型:{1}, 数组轴数:{2}, 数组大小(元素个数):{3}".format(data_one, data_one.dtype, data_one.ndim, data_one.size))
print("data_two: \n数组内容:{0}, 数据类型:{1}, 数组轴数:{2}, 数组大小(元素个数):{3}".format(data_two, data_two.dtype, data_two.ndim, data_two.size))

结果(打印):
data_one:
数组内容:[1], 数据类型:int32, 数组轴数:1, 数组大小(元素个数):1
data_two:
数组内容:[0.5], 数据类型:float32, 数组轴数:1, 数组大小(元素个数):1


data_one与data_two相加

result_Add = data_one + data_two
print("result_Add: \n数组内容:{0}, 数据类型:{1}, 数组轴数:{2}, 数组大小(元素个数):{3}".format(result_Add, result_Add.dtype, result_Add.ndim, result_Add.size))

结果(打印):
result_Add:
数组内容:[1.5], 数据类型:float64, 数组轴数:1, 数组大小(元素个数):1


标量相加的特点:

1.存在数据相加后,数据类型自动转换为更加稳定(足够计算)的数据类型。(int32 + float32 = float64)
2.标量相加——轴数保持不变
3.标量相加——元素个数保持不变


向量相加(2D张量相加)

  1. 创建向量数据——向量:即仅包含一列或一行数据元素——一般来说,这样的数组存在着两个轴:第0和第1轴;并且行/列向量的区别在于,第0轴的维度大小。
  2. 如果第0轴维度为1,无论有多少个数据元素,那么它都是行向量(也就是第1轴维度大于等于1)。
  3. 如果第0轴维度为数据元素个数,那么它就是列向量——注意,列向量每一个元素在第0轴中占一个维度,不能存在多个元素共存(也就是第1轴维度等于1)。
  4. 特殊的向量:仅含一个元素的向量,既是行向量,也是列向量。(第0和第1轴维度大小均为1.)

创建行向量

data_one = np.zeros((1, 7))
data_two = np.ones((1, 7))
data_three = np.ones((1, 8))  # 创建于前面维度大小不同的行向量

行向量的另外一种创建方法:

# data_one = np.linspace(0, 5, 8)
# data_one = data_one[np.newaxis,:]  # 添轴,实现向量化(单单linspace仅仅创建一个[1,2,3,4,5,……]这样的内容而已,而向量应该是:[[1,2,3,4,5,……]])

创建列向量

data_four = np.linspace(0, 10, 20).reshape(20, 1)
data_five = np.linspace(-5, 5, 20).reshape(20, 1)
data_six = np.arange(0, 10, 1).reshape(10, 1) # 创建于前面维度大小不同的列向量
  • reshape注意事项:维度值之积应该保证为原数组的元素个数(大小),否则出现意外,会严重影响功能数据的正常进行。

查看数组数据

print("data_one: \n数组内容:{0}, 数据类型:{1}, 数组轴数:{2}, 数组大小(元素个数):{3}".format(data_one, data_one.dtype, data_one.ndim, data_one.size))
print("data_two: \n数组内容:{0}, 数据类型:{1}, 数组轴数:{2}, 数组大小(元素个数):{3}".format(data_two, data_two.dtype, data_two.ndim, data_two.size))
print("data_four: \n数组内容:{0}, 数据类型:{1}, 数组轴数:{2}, 数组大小(元素个数):{3}".format(data_four, data_four.dtype, data_four.ndim, data_four.size))
print("data_five: \n数组内容:{0}, 数据类型:{1}, 数组轴数:{2}, 数组大小(元素个数):{3}".format(data_five, data_five.dtype, data_five.ndim, data_five.size))

结果(打印):
data_one:
数组内容:[[0. 0. 0. 0. 0. 0. 0.]], 数据类型:float64, 数组轴数:2, 数组大小(元素个数):7

data_two:
数组内容:[[1. 1. 1. 1. 1. 1. 1.]], 数据类型:float64, 数组轴数:2, 数组大小(元素个数):7

data_four:
数组内容:[[ 0. ]
[ 0.52631579]
[ 1.05263158]
[ 1.57894737]
[ 2.10526316]
[ 2.63157895]
[ 3.15789474]
[ 3.68421053]
[ 4.21052632]
[ 4.73684211]
[ 5.26315789]
[ 5.78947368]
[ 6.31578947]
[ 6.84210526]
[ 7.36842105]
[ 7.89473684]
[ 8.42105263]
[ 8.94736842]
[ 9.47368421]
[10. ]], 数据类型:float64, 数组轴数:2, 数组大小(元素个数):20

data_five:
数组内容:[[-5. ]
[-4.47368421]
[-3.94736842]
[-3.42105263]
[-2.89473684]
[-2.36842105]
[-1.84210526]
[-1.31578947]
[-0.78947368]
[-0.26315789]
[ 0.26315789]
[ 0.78947368]
[ 1.31578947]
[ 1.84210526]
[ 2.36842105]
[ 2.89473684]
[ 3.42105263]
[ 3.94736842]
[ 4.47368421]
[ 5. ]], 数据类型:float64, 数组轴数:2, 数组大小(元素个数):20


行向量相加——相加的向量维度要相同

print("data_one :", data_one)
print("data_two :", data_two)
print("相同维度的行向量相加:data_one + data_two = ", data_one + data_two)
# print("data_three :", data_three)
# print("维度不同的行向量相加:data_one + data_three = ", data_one + data_three)  # 会报错,说明向量相加应该保证维度相同

结果(打印):
data_one : [[0. 0. 0. 0. 0. 0. 0.]]
data_two : [[1. 1. 1. 1. 1. 1. 1.]]
相同维度的行向量相加:data_one + data_two = [[1. 1. 1. 1. 1. 1. 1.]]


列向量相加——相加的向量维度要相同

print("data_four :", data_four)
print("data_five :", data_five)
print("相同维度的行向量相加:data_four + data_five = ", data_four + data_five)
# print("data_three :", data_six)
# print("维度不同的行向量相加:data_four + data_six = ", data_four + data_six)  # 会报错,说明向量相加应该保证维度相同

结果(打印):
data_four : [[ 0. ]
[ 0.52631579]
[ 1.05263158]
[ 1.57894737]
[ 2.10526316]
[ 2.63157895]
[ 3.15789474]
[ 3.68421053]
[ 4.21052632]
[ 4.73684211]
[ 5.26315789]
[ 5.78947368]
[ 6.31578947]
[ 6.84210526]
[ 7.36842105]
[ 7.89473684]
[ 8.42105263]
[ 8.94736842]
[ 9.47368421]
[10. ]]
data_five : [[-5. ]
[-4.47368421]
[-3.94736842]
[-3.42105263]
[-2.89473684]
[-2.36842105]
[-1.84210526]
[-1.31578947]
[-0.78947368]
[-0.26315789]
[ 0.26315789]
[ 0.78947368]
[ 1.31578947]
[ 1.84210526]
[ 2.36842105]
[ 2.89473684]
[ 3.42105263]
[ 3.94736842]
[ 4.47368421]
[ 5. ]]
相同维度的行向量相加:data_four + data_five = [[-5. ]
[-3.94736842]
[-2.89473684]
[-1.84210526]
[-0.78947368]
[ 0.26315789]
[ 1.31578947]
[ 2.36842105]
[ 3.42105263]
[ 4.47368421]
[ 5.52631579]
[ 6.57894737]
[ 7.63157895]
[ 8.68421053]
[ 9.73684211]
[10.78947368]
[11.84210526]
[12.89473684]
[13.94736842]
[15. ]]


向量相加的特点:

  1. 存在数据相加后,数据类型自动转换为更加稳定(足够计算)的数据类型。(int32 + float32 = float64)
  2. 向量相加——维度大小要相同
  3. 向量相加——轴数保持不变
  4. 向量相加——元素个数保持不变 ②矩阵相加(2D张量相加)——矩阵可以简单理解为多个维度大小相同的行向量连接的形式

矩阵相加(2D张量)

向量与矩阵的关系

行向量:

[[1, 2, 3]]
[[4, 5, 6]]
[[7, 8, 9]]
矩阵:

[[1, 2, 3]
[4, 5, 6]
[7, 8, 9]]


创建矩阵

# 2*2
data_one = np.ones((2, 2))
# 2*2
data_two = np.empty((2, 2))
# 2*3
data_three = np.empty((2, 3))

查看矩阵数组数据

print("data_one: \n数组内容:\n {0} \n 数据类型:{1}\n 数组轴数:{2}\n 数组大小(元素个数):{3}\n".format(data_one, data_one.dtype, data_one.ndim, data_one.size))
print("data_two: \n数组内容:\n {0}\n数据类型:{1}\n 数组轴数:{2}\n 数组大小(元素个数):{3}\n".format(data_two, data_two.dtype, data_two.ndim, data_two.size))
print("data_three: \n数组内容:\n {0}\n数据类型:{1}\n 数组轴数:{2}\n数组大小(元素个数):{3}\n".format(data_three, data_three.dtype, data_three.ndim, data_three.size))

结果(打印):
data_one:
数组内容:
[[1. 1.]
[1. 1.]]
数据类型:float64
数组轴数:2
数组大小(元素个数):4

data_two:
数组内容:
[[7.26615900e+223 1.06097757e-153]
[1.27874063e-152 5.76502240e+228]]
数据类型:float64
数组轴数:2
数组大小(元素个数):4

data_three:
数组内容:
[[4.901e-321 4.901e-321 5.474e-321]
[5.474e-321 5.237e-321 5.237e-321]]
数据类型:float64
数组轴数:2
数组大小(元素个数):6


矩阵相加

data_one + data_two
# data_one + data_three  # 维度不同无法计算,报错

结果(打印):
array([[7.2661590e+223, 1.0000000e+000],
[1.0000000e+000, 5.7650224e+228]])


numpy数组的乘除法运算

标量乘除法运算

data_one = np.array([1], dtype=np.int32)
data_two = np.array([2], dtype=np.int32)
print("乘法运算:data_one * data_two \n 结果为:\n{0}  ,  dtype = {1}".format(data_one * data_two, (data_one * data_two).dtype))
print("除法运算:data_one / data_two \n 结果为:\n{0}  ,  dtype = {1}".format(data_one / data_two,  (data_one / data_two).dtype))

结果(打印):
乘法运算:data_one * data_two
结果为:
[2] , dtype = int32
除法运算:data_one / data_two
结果为:
[0.5] , dtype = float64


向量乘除法运算

data_one = np.random.randint(1, 10, (1,8))
data_two = np.random.randint(1, 10, (8,1))
data_three = np.random.randint(10, 20, (7,1))

查看数组数据

data_one

结果(打印):
array([[1, 6, 8, 5, 7, 5, 5, 3]])


查看数组数据

data_two

结果(打印):
array([[3],
[9],
[6],
[5],
[9],
[7],
[5],
[4]])


两向量相乘

print("向量相乘的向量形状:(8, 1) * (1, 8):\n", data_two * data_one)
print("向量相乘的向量形状:(1, 8) * (8, 1):\n", data_one * data_two)

结果(打印):
向量相乘的向量形状:(8, 1) * (1, 8):
[[ 3 18 24 15 21 15 15 9]
[ 9 54 72 45 63 45 45 27]
[ 6 36 48 30 42 30 30 18]
[ 5 30 40 25 35 25 25 15]
[ 9 54 72 45 63 45 45 27]
[ 7 42 56 35 49 35 35 21]
[ 5 30 40 25 35 25 25 15]
[ 4 24 32 20 28 20 20 12]]
向量相乘的向量形状:(1, 8) * (8, 1):
[[ 3 18 24 15 21 15 15 9]
[ 9 54 72 45 63 45 45 27]
[ 6 36 48 30 42 30 30 18]
[ 5 30 40 25 35 25 25 15]
[ 9 54 72 45 63 45 45 27]
[ 7 42 56 35 49 35 35 21]
[ 5 30 40 25 35 25 25 15]
[ 4 24 32 20 28 20 20 12]]


两向量相乘(形状不对称的向量)

print("向量相乘的向量形状:(1, 8) * (7, 1):\n", data_one * data_three)
print("向量相乘的向量形状:(7, 1) * (1, 8):\n", data_three * data_one)
# print("向量相乘的向量形状:(8, 1) * (7, 1):\n", data_two * data_three)  # 报错,维度错误

结果(打印):
向量相乘的向量形状:(1, 8) * (7, 1):
[[ 17 102 136 85 119 85 85 51]
[ 14 84 112 70 98 70 70 42]
[ 17 102 136 85 119 85 85 51]
[ 18 108 144 90 126 90 90 54]
[ 17 102 136 85 119 85 85 51]
[ 17 102 136 85 119 85 85 51]
[ 18 108 144 90 126 90 90 54]]
向量相乘的向量形状:(7, 1) * (1, 8):
[[ 17 102 136 85 119 85 85 51]
[ 14 84 112 70 98 70 70 42]
[ 17 102 136 85 119 85 85 51]
[ 18 108 144 90 126 90 90 54]
[ 17 102 136 85 119 85 85 51]
[ 17 102 136 85 119 85 85 51]
[ 18 108 144 90 126 90 90 54]]


向量相乘的特点总结:

  1. 相乘的两向量,必须存在一个向量的行数要与另一个向量的列数相同,否则不能相乘。

print("data_one : \n{0}, shape = {1}".format(data_one, data_one.shape))
print("data_two : \n{0}, shape = {1}".format(data_two, data_two.shape))
print("向量相除的向量形状:(8, 1) / (1, 8):\n{0} shape = {1}".format(data_two / data_one, (data_two / data_one).shape))
print("向量相除的向量形状:(1, 8) / (8, 1):\n{0} shape = {1}".format(data_one / data_two, (data_one / data_two).shape))

结果(打印):
data_one :
[[1 6 8 5 7 5 5 3]], shape = (1, 8)

data_two :
[[3]
[9]
[6]
[5]
[9]
[7]
[5]
[4]], shape = (8, 1)

向量相除的向量形状:(8, 1) / (1, 8):
[[3. 0.5 0.375 0.6 0.42857143 0.6
0.6 1. ]
[9. 1.5 1.125 1.8 1.28571429 1.8
1.8 3. ]
[6. 1. 0.75 1.2 0.85714286 1.2
1.2 2. ]
[5. 0.83333333 0.625 1. 0.71428571 1.
1.1.66666667]
[9. 1.5 1.125 1.8 1.28571429 1.8
1.8 3. ]
[7. 1.16666667 0.875 1.4 1. 1.4
1.4 2.33333333]
[5. 0.83333333 0.625 1. 0.71428571 1.
1.1.66666667]
[4. 0.66666667 0.5 0.8 0.57142857 0.8
0.8 1.33333333]] shape = (8, 8)

向量相除的向量形状:(1, 8) / (8, 1):
[[0.33333333 2. 2.66666667 1.66666667 2.33333333 1.66666667
1.66666667 1.]
[0.11111111 0.66666667 0.88888889 0.55555556 0.77777778 0.55555556
0.55555556 0.33333333]
[0.16666667 1.1.33333333 0.83333333 1.16666667 0.83333333
0.83333333 0.5 ]
[0.2 1.2 1.6 1. 1.4 1.
1.0.6 ]
[0.11111111 0.66666667 0.88888889 0.55555556 0.77777778 0.55555556
0.55555556 0.33333333]
[0.14285714 0.85714286 1.14285714 0.71428571 1. 0.71428571
0.71428571 0.42857143]
[0.2 1.2 1.6 1. 1.4 1.
1.0.6 ]
[0.25 1.5 2. 1.25 1.75 1.25
1.25 0.75 ]] shape = (8, 8)


print("data_one : \n{0}, shape = {1}".format(data_one, data_one.shape))
print("data_two : \n{0}, shape = {1}".format(data_two, data_two.shape))
print("data_three : \n{0}, shape = {1}".format(data_three, data_three.shape))
print("向量相除的向量形状:(1, 8) / (7, 1):\n{0} shape = {1}".format(data_one / data_three, (data_one / data_three).shape))
print("向量相除的向量形状:(7, 1) / (1, 8):\n{0} shape = {1}".format(data_three / data_one, (data_three / data_one).shape))
# print("向量相除的向量形状:(8, 1) / (7, 1):\n{0} shape = {1}".format(data_two / data_three, (data_two / data_three).shape)) # 报错,维度错误

结果(打印):
data_one :
[[1 6 8 5 7 5 5 3]], shape = (1, 8)

data_two :
[[3]
[9]
[6]
[5]
[9]
[7]
[5]
[4]], shape = (8, 1)

data_three :
[[17]
[14]
[17]
[18]
[17]
[17]
[18]], shape = (7, 1)

向量相除的向量形状:(1, 8) / (7, 1):
[[0.05882353 0.35294118 0.47058824 0.29411765 0.41176471 0.29411765
0.29411765 0.17647059]
[0.07142857 0.42857143 0.57142857 0.35714286 0.5 0.35714286
0.35714286 0.21428571]
[0.05882353 0.35294118 0.47058824 0.29411765 0.41176471 0.29411765
0.29411765 0.17647059]
[0.05555556 0.33333333 0.44444444 0.27777778 0.38888889 0.27777778
0.27777778 0.16666667]
[0.05882353 0.35294118 0.47058824 0.29411765 0.41176471 0.29411765
0.29411765 0.17647059]
[0.05882353 0.35294118 0.47058824 0.29411765 0.41176471 0.29411765
0.29411765 0.17647059]
[0.05555556 0.33333333 0.44444444 0.27777778 0.38888889 0.27777778
0.27777778 0.16666667]] shape = (7, 8)

向量相除的向量形状:(7, 1) / (1, 8):
[[17. 2.83333333 2.125 3.4 2.42857143 3.4
3.4 5.66666667]
[14. 2.33333333 1.75 2.8 2. 2.8
2.8 4.66666667]
[17. 2.83333333 2.125 3.4 2.42857143 3.4
3.4 5.66666667]
[18. 3. 2.25 3.6 2.57142857 3.6
3.6 6. ]
[17. 2.83333333 2.125 3.4 2.42857143 3.4
3.4 5.66666667]
[17. 2.83333333 2.125 3.4 2.42857143 3.4
3.4 5.66666667]
[18. 3. 2.25 3.6 2.57142857 3.6
3.6 6. ]] shape = (7, 8)


向量相除的特点总结:

  1. 相除的两向量,必须存在一个向量的行数要与另一个向量的列数相同,否则不能相除。
  2. 向量除法也就相当于:矩阵1 * (1/矩阵2)

矩阵乘法运算

一般计算只支持形状相同的矩阵,但是使用np.dot可以实现数学上的点积

创建矩阵

# 创建矩阵——2*2
data_one = np.ones((2, 2), dtype=np.int32)
# 2*2
data_two = np.random.randint(1, 10, (2, 2))
# 3*3
data_three = np.random.randint(-5, 10, (3, 3))
# 3*3
data_four = np.random.randint(1, 10, (3, 3))

形状相同的矩阵相乘(内积)(2*2)

data_one * data_two

结果(打印):
array([[8, 1],
[3, 5]])

data_two * data_one  # 交换乘积顺序,不影响计算

结果(打印):
array([[8, 1],
[3, 5]])


形状相同的矩阵相乘(3*3)

data_four * data_three 
# print(data_four * data_two) # 报错,维度错误

结果(打印):
array([[-25, 8, 12],
[ 0, -18, 28],
[ 30, -5, 5]])


以上运算仅仅支持矩阵形状完全相同的乘法运算

创建一个2*3的矩阵为dot乘法做准备

创建一个2*3的矩阵
data_seven = np.random.randint(13,  29, (2, 3))
data_seven

结果(打印):
array([[24, 16, 28],
[16, 13, 28]])


引入之前的data_one矩阵
查看data_one数组数据

data_one

结果(打印):
array([[1, 1],
[1, 1]])


进行dot乘法运算

np.dot(data_one, data_seven)  
  • data_one与data_seven的矩阵乘法,顺序确定,不可随意调换顺序 ,否则可能行列关系不对应,而导致报错。
    结果(打印):
    array([[40, 29, 56],
    [40, 29, 56]])

矩阵除法运算

维度形状相同的矩阵除法运算

data_one / data_two  # 引入之前的data_one, data_two

结果(打印):
array([[0.125 , 1. ],
[0.33333333, 0.2 ]])


满足矩阵乘法,维度形状不定的矩阵除法运算(即23与34,也可以是23与38)

np.dot(data_one, 1/data_seven)  # 相当于:data_one / data_seven

结果(打印):
array([[0.10416667, 0.13942308, 0.07142857],
[0.10416667, 0.13942308, 0.07142857]])

np.dot(1/data_one, data_seven)   # 相当于:data_seven / data_one

结果(打印):
array([[40., 29., 56.],
[40., 29., 56.]])


numpy运算讲解的总结

1.加减法总结

  • 无论是标量、向量、矩阵——都应该保证形状大小相同。
  • 标量是只存在第0轴的array数组,向量和矩阵存在第0和第1轴的array数组。
  • 行向量——第0轴维度大小只能是1;列向量——第1轴维度大小只能是1.

2.乘除法总结

  • 标量直接相乘;向量只需要保证相乘的向量存在一组行列对应的关系即可相乘。
  • 行列关系:某一向量或矩阵的行数与另一个运算的向量或矩阵的列数相等。
  • 矩阵相乘有两种:
    1.一种是矩阵形状完全相同,可以直接相乘(也叫内积);
    2.第二种是满足行列关系,可以使用np.dot进行线代数学的矩阵乘法。

矩阵乘法规则可查‘矩阵乘法’得知。

实用性简要说明

我们用得比较多的其实是向量和矩阵的相关运算。
因为我们可以通过使用向量和矩阵来存储有一定关系的数据,或者存在某种规则下的数据,我们只需要使用对应的运算方法,就可以实现大量数据的快速计算——这样既保证了数据的完整,也保证了效率(主要原因)。


厌倦了,一个数据一个数据单独处理,为什么不试试对数据进行某种约定,转换成矩阵或向量来处理大量数据呢?

Numpy,是你走上数据处理之路上的好朋友。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章