问题:
如果想要操作符合某一条件的数据,应该怎么做?
一、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能够进行更加复杂的运算
# 判断前四名学生,前四门课程中,成绩中大于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,否则返回Falsenp.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 统计指标
在数据挖掘/机器学习领域,统计指标的值也是我们分析问题的一种方式。常用的指标如下:
>>>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])
>>>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])
>>>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.])
>>>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])
>>>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 ])
>>>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对应的两个求下标的函数:
>>>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)
>>>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.matmul
与np.dot
没有区别。
若有用,欢迎点赞,若有错,请指正,谢谢!