NumPy学习笔记——(4)ndarray运算

上一小节: NumPy学习笔记——(3)N维数组-ndarray基本操作.

问题
如果想要操作符合某一条件的数据,应该怎么做?

一、ndarray运算

1、逻辑运算

直接看下面的例子:

# 生成10名同学,5门功课的数据
>>> score = np.random.randint(40, 100, (10, 5))# 均匀分布,生成:最小值40,最大值100,10行5列

# 取出最后4名同学的成绩,用于逻辑判断
>>> test_score = score[6:, :]

# 逻辑判断, 如果成绩大于60就标记为True 否则为False
>>> test_score > 60
array([[ True,  True,  True, False,  True],
       [ True,  True,  True, False,  True],
       [ True,  True, False, False,  True],
       [False,  True,  True,  True,  True]])

# BOOL赋值, 将满足条件的设置为指定的值-布尔索引
>>> test_score[test_score > 60] = 1
>>> test_score
array([[ 1,  1,  1, 52,  1],
       [ 1,  1,  1, 59,  1],
       [ 1,  1, 44, 44,  1],
       [59,  1,  1,  1,  1]])

2、通用判断函数

  • (1)np.all():只要有一个不满足要求,就返回False
# 判断前两名同学的成绩[0:2, :]是否全及格
>>> np.all(score[0:2, :] > 60)
False
  • (2)np.any():只要有一个满足要求,就返回True
# 判断前两名同学的成绩[0:2, :]是否有大于90分的
>>> np.any(score[0:2, :] > 80)
True

3、np.where(三元运算符)

通过使用np.where能够进行更加复杂的运算

  • np.where(条件, value1, value2)

    • 条件:就是设置的满足要求的条件
    • value1:满足上述条件返回的值
    • value2:不满足上述条件返回的值
# 判断前四名学生,前四门课程中,成绩中大于60的置为1,否则为0
temp = score[:4, :4]
np.where(temp > 60, 1, 0)
# 结果:
array([[1, 1, 0, 1],
       [1, 0, 1, 1],
       [0, 1, 1, 1],
       [1, 1, 0, 1]])
  • 复合逻辑需要结合np.logical_and和np.logical_or使用
    • np.logical_and(条件1, 条件2):同时满足两个条件返回True,否则返回False
    • np.logical_or(条件1, 条件2):只要满足一个条件就返回True,都不满足返回False

接下来看怎么和where配合使用,直接看例子:

# 判断前四名学生,前四门课程中,成绩中大于60且小于90的换为1,否则为0
np.where(np.logical_and(temp > 60, temp < 90), 1, 0)
# 结果:
array([[1, 1, 0, 1],
       [0, 0, 1, 1],
       [0, 1, 1, 1],
       [1, 0, 0, 0]])


# 判断前四名学生,前四门课程中,成绩中大于90或小于60的换为1,否则为0
np.where(np.logical_or(temp > 90, temp < 60), 1, 0)
# 结果:
array([[0, 0, 0, 0],
       [1, 1, 0, 0],
       [1, 0, 0, 0],
       [0, 1, 1, 1]])

4、统计运算

如果想要知道学生成绩最大的分数,或者做小分数应该怎么做?

4.1 统计指标

在数据挖掘/机器学习领域,统计指标的值也是我们分析问题的一种方式。常用的指标如下:

  • (1)min(a, axis)

    • 返回数组的最小值或沿轴axis的最小值。
    • 注意:要是不传axis,那返回的就是a这个数组里面所有数的最小值。
>>>temp
array([[65, 64, 60, 65, 46],
       [98, 47, 87, 85, 92],
       [47, 62, 66, 82, 70],
       [68, 98, 55, 96, 61]])

>>>np.min(temp)  #计算数组中所有数的最小值
46

>>>np.min(temp, axis=0)# 沿着列
array([47, 47, 55, 65, 46])

>>>np.min(temp, axis=1)# 沿着行
array([46, 47, 47, 55])
  • (2)max(a, axis])

    • 返回数组的最大值或沿轴axis的最大值。
    • 不传axis,那返回的就是a这个数组里面所有数的最大值。
>>>temp
array([[65, 64, 60, 65, 46],
       [98, 47, 87, 85, 92],
       [47, 62, 66, 82, 70],
       [68, 98, 55, 96, 61]])

>>>np.max(temp)  #计算数组中所有数的最大值
98

>>>np.max(temp, axis=0)  # 沿着列
array([98, 98, 87, 96, 92])

>>>np.max(temp, axis=1)  # 沿着行
array([65, 98, 82, 98])
  • (3)median(a, axis)

    • 计算沿指定轴axis的中位数。
    • 不传axis,那返回的就是a这个数组里面所有数的中位数。
>>>temp
array([[65, 64, 60, 65, 46],
       [98, 47, 87, 85, 92],
       [47, 62, 66, 82, 70],
       [68, 98, 55, 96, 61]])

>>>np.median(temp)# 所有数的中位数
65.5

>>>np.median(temp, axis=0)# 沿着列
array([66.5, 63. , 63. , 83.5, 65.5])

>>>np.median(temp, axis=1)#沿着行
array([64., 87., 66., 68.])
  • (4)mean(a, axis, dtype)

    • 沿指定轴axis计算算术平均值.
    • 不传axis,那返回的就是a这个数组里面所有数的算数平均值。
>>>temp
array([[65, 64, 60, 65, 46],
       [98, 47, 87, 85, 92],
       [47, 62, 66, 82, 70],
       [68, 98, 55, 96, 61]])

>>>np.mean(temp)# 数组中所有数的均值
70.7

>>>np.mean(temp, axis=0)# 沿着列
array([69.5 , 67.75, 67.  , 82.  , 67.25])

>>>np.mean(temp, axis=1)# 沿着行
array([60. , 81.8, 65.4, 75.6])
  • (5)std(a, axis, dtype)

    • 计算沿指定轴的标准偏差。
    • 不传axis,那返回的就是a这个数组里面所有数的表中偏差。
>>>temp
array([[65, 64, 60, 65, 46],
       [98, 47, 87, 85, 92],
       [47, 62, 66, 82, 70],
       [68, 98, 55, 96, 61]])

>>>np.std(temp)#所有数的标准偏差
16.712570119523807

>>>np.std(temp, axis=0)# 沿着列
array([18.30983342, 18.65978296, 12.18605761, 11.11305539, 16.66395811])

>>>np.std(temp, axis=1)# 沿着行
array([ 7.23878443, 17.97108789, 11.37717012, 17.9621825 ])
  • (6)var(a, axis, dtype)

    • 计算沿指定轴的方差。
    • 不传axis,那返回的就是a这个数组里面所有数的方差。
>>>temp
array([[65, 64, 60, 65, 46],
       [98, 47, 87, 85, 92],
       [47, 62, 66, 82, 70],
       [68, 98, 55, 96, 61]])

>>>np.var(temp)# 数组中所有数的方差
279.31

>>>np.var(temp, axis=0)# 沿着列
array([335.25  , 348.1875, 148.5   , 123.5   , 277.6875])

>>>np.var(temp, axis=1)# 沿着行
array([ 52.4 , 322.96, 129.44, 322.64])

上面容易出错的地方就是axis,只需要记住,axis从小到大,对应数组[]从外到里。这样对多维数组的记忆也就清晰了。

除了上述的几种之外,还有min和max对应的两个求下标的函数:

  • np.argmax(temp, axis)

    • 求最大值对应的下标
>>>temp
array([[65, 64, 60, 65, 46],
       [98, 47, 87, 85, 92],
       [47, 62, 66, 82, 70],
       [68, 98, 55, 96, 61]])

>>>np.argmax(temp) # 先把数组铺成一排,然后找最大值的下标
5

>>>np.argmax(temp, axis=0)# 沿着列
array([1, 3, 1, 3, 1], dtype=int64)

>>>np.argmax(temp, axis=1)# 沿着行
array([0, 0, 3, 1], dtype=int64)
  • np.argmin(temp, axis)

    • 求最小值对应的下标
>>>temp
array([[65, 64, 60, 65, 46],
       [98, 47, 87, 85, 92],
       [47, 62, 66, 82, 70],
       [68, 98, 55, 96, 61]])

>>>np.argmin(temp)# 先把数组铺成一排,然后找最小值的下标
4

>>>np.argmin(temp, axis=0)# 沿着列
array([2, 1, 3, 0, 0], dtype=int64)

>>>np.argmin(temp, axis=1)# 沿着行
array([4, 1, 0, 2], dtype=int64)

二、数组间的运算

1、数组与数的运算

直接看例子就很明白了:

>>>a = np.array([[1,2,3], [3,4,5]])
>>>a
array([[1, 2, 3],
       [3, 4, 5]])
       
>>>a + 3  # 对数组a里面的所有的数都加3      
array([[4, 5, 6],
       [6, 7, 8]]) 
       
>>>a / 2  # 对数组a里面的所有的数都除以2
array([[0.5, 1. , 1.5],
       [1.5, 2. , 2.5]])

可以发现,数组与数的运算其实就是这个数作用到数组中的每一个元素了。

那python的列表是怎么样的呢?

# 可以对比python列表的运算,看出区别
>>>a = [1, 2, 3, 4, 5]
>>>a * 3
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]

假如乘一个数的话,python列表就把列表复制了几次。

2、数组与数组的运算

加入下面的两个数组,能进行计算吗?

arr1 = np.array([[1, 2, 3, 2, 1, 4], [5, 6, 1, 2, 3, 1]])
arr2 = np.array([[1, 2, 3, 4], [3, 4, 5, 6]])
arr1 + arr2

结果是不行的!那怎么样的才能进行计算呢?

2.1 广播机制

数组在进行矢量化运算时,要求数组的形状是相等的。当形状不相等的数组执行算术运算的时候,就会出现广播机制,该机制会对数组进行扩展,使数组的shape属性值一样,这样,就可以进行矢量化运算了。下面通过一个例子进行说明:

arr1 = np.array([[0],[1],[2],[3]])
arr1.shape
# (4, 1)

arr2 = np.array([1,2,3])
arr2.shape
# (3,)

arr1+arr2
# 结果是:
array([[1, 2, 3],
       [2, 3, 4],
       [3, 4, 5],
       [4, 5, 6]])

上述代码中,数组arr1是4行1列,arr2是1行3列。这两个数组要进行相加,按照广播机制会对数组arr1和arr2都进行扩展,使得数组arr1和arr2都变成4行3列。

下面通过一张图来描述广播机制扩展数组的过程:
在这里插入图片描述
广播机制首先需要判断参与计算的两个数组能否被广播机制处理?即判断是否广播兼容,规则是,比较两个数组的shape,从shape的尾部开始一一比对。

  • (1). 如果两个数组的维度相同,对应位置上轴的长度相同或其中一个的轴长度为1,广播兼容,可在轴长度为1的轴上进行广播机制处理。

  • (2). 如果两个数组的维度不同,那么给低维度的数组前扩展提升一维,扩展维的轴长度为1,然后在扩展出的维上进行广播机制处理

看一个例子:

import numpy as np
a = np.arange(1, 16).reshape([3, 5])
print(a)
print(a.shape)
b = np.array([2, 3, 4, 5, 6])
print(b)
print(b.shape)
print(a + b)

这里a数组的维度是2即二维数组(3, 5),b是一维数组(5,),判断一下是否广播兼容?b的最后一维的轴长度为5、a的最后一维的轴长度5,满足从后向前开始对应轴的轴长度相同规则。两个数组的维度不同一个是2维一个是1维,那么对b前扩展增加维度变为(1, 5)成为2维数组,此时a和b都是二维数组,维度相同。增维后的b的倒数第二维的长度是1,a倒数第二维轴长度为3,满足维度相同某轴长度为1的兼容规则,继续广播机制,将b倒数第二维轴长度继续加1直至变为和a数组倒数第二轴轴长度相同,这是b的shape经过不断的调整(广播机制)变为(3, 5),和a的shape相同,就可以广播计算了。每次对b倒数第二轴轴长度加1实际是拷贝增加一行。
广播机制需要扩展维度小的数组,使得它与维度最大的数组的shape值相同,以便使用元素级函数或者运算符进行运算。

如果是下面这样,则不匹配:

# 下面不匹配,因为对应的维度不相同或不为1
A  (1d array): 10
B  (1d array): 12

# 下面不匹配,因为维度2和4不相同
A  (2d array):      2 x 1
B  (3d array):  8 x 4 x 3

总之就一句话:看对应维度相同不(如果是1,则看成相同),不相同则不能广播。

思考:下面两个ndarray是否能够进行运算?

arr1 = np.array([[1, 2, 3, 2, 1, 4], [5, 6, 1, 2, 3, 1]])
arr2 = np.array([[1], [3]])

答案是可以的。因为arr1的维度为(2, 6),arr2的维度为(2, 1),对应维度相同,所以可以。

三、数学:矩阵

1、矩阵和向量

1.1 矩阵

矩阵,英文matrix,和array的区别:矩阵必须是2维的,但是array可以是多维的。

如图:这个是 3×2 矩阵,即 3 行 2 列,如 m 为行,n 为列,那么 m×n 即 3×2。
在这里插入图片描述
矩阵的维数即行数×列数

矩阵元素(矩阵项):

在这里插入图片描述
​ ​ A i j ​​A_{ij} Aij 指第 i 行,第 j 列的元素。

1.2 向量

向量是一种特殊的矩阵,讲义中的向量一般都是列向量,下面展示的就是三维列 向量(3×1)。)
在这里插入图片描述

2、加法和标量乘法

矩阵的加法:行列数相等的可以加。

例:
在这里插入图片描述
矩阵的乘法:每个元素都要乘。

例:

在这里插入图片描述
组合算法也类似。

3、矩阵向量乘法

矩阵和向量的乘法如图:m×n 的矩阵乘以 n×1 的向量,得到的是 m×1 的向量

例:
在这里插入图片描述
下面是计算过程:

1*1+3*5 = 16
4*1+0*5 = 4
2*1+1*5 = 7

矩阵乘法遵循准则:

(M行, N列)*(N行, L列) = (M行, L列)

4、矩阵乘法

矩阵乘法:

m×n 矩阵乘以 n×o 矩阵,变成 m×o 矩阵。

举例:比如说现在有两个矩阵 A 和 B,那 么它们的乘积就可以表示为图中所示的形式。

在这里插入图片描述
再看一个例子:
在这里插入图片描述
求矩阵AB的结果

答案:

在这里插入图片描述

5、矩阵乘法的性质

矩阵的乘法不满足交换律:A×B≠B×A

矩阵的乘法满足结合律。即:A×(B×C)=(A×B)×C

单位矩阵:在矩阵的乘法中,有一种矩阵起着特殊的作用,如同数的乘法中的 1,我们称 这种矩阵为单位矩阵.它是个方阵,一般用 I 或者 E 表示,从 左上角到右下角的对角线(称为主对角线)上的元素均为 1 以外全都为 0。如:

在这里插入图片描述

6、逆、转置

在这里插入图片描述

7、矩阵运算

看下面,如果平时成绩占70%,期末成绩占30%,如何使用矩阵来计算呢?
在这里插入图片描述
可以是下面这样计算:
在这里插入图片描述

7.1 矩阵乘法api:

接下来看一下NumPy中,矩阵乘法如何使用:

  • (1)np.matmul
  • (2)np.dot

直接看例子:

>>> a = np.array([[80, 86],
[82, 80],
[85, 78],
[90, 90],
[86, 82],
[82, 90],
[78, 80],
[92, 94]])
>>> b = np.array([[0.7], [0.3]])

>>> np.matmul(a, b)
array([[81.8],
       [81.4],
       [82.9],
       [90. ],
       [84.8],
       [84.4],
       [78.6],
       [92.6]])

>>> np.dot(a,b)
array([[81.8],
       [81.4],
       [82.9],
       [90. ],
       [84.8],
       [84.4],
       [78.6],
       [92.6]])

上面两个看不出区别,那区别是什么呢?

np.matmul和np.dot的区别:

二者都是矩阵乘法。 np.matmul中禁止矩阵与标量的乘法。 在矢量乘矢量的內积运算中,np.matmulnp.dot没有区别。

上一小节: NumPy学习笔记——(3)N维数组-ndarray基本操作.

若有用,欢迎点赞,若有错,请指正,谢谢!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值