【Numpy】数组的操作2

比较、掩码和布尔逻辑

当想基于某些准则来抽取,修改,计数或对一个数组中的值进行其他操作时,掩码就派上用场了

例如,统计数组中有多少值大于某个给定值,或者删除所有超过某些门限值的异常点

在numpy中,布尔掩码通常是完成此类任务的最高效方式

比较操作

Numpy实现了如<小于和>大于的逐元素比较的通用函数,这些比较运算的结果是一个布尔数据类型的数组

共有6中不同的比较操作:

 1 import numpy as np
 2 
 3 x = np.array([1,2,3,4,5])
 4 
 5 x < 3 # 小于
 6 Out[3]: array([ True,  True, False, False, False])
 7 
 8 x > 3 # 大于
 9 Out[4]: array([False, False, False,  True,  True])
10 
11 x <= 3 # 小于等于
12 Out[5]: array([ True,  True,  True, False, False])
13 
14 x >= 3 # 大于等于
15 Out[6]: array([False, False,  True,  True,  True])
16 
17 x != 3 # 不等于
18 Out[7]: array([ True,  True, False,  True,  True])
19 
20 x == 3 # 等于
21 Out[8]: array([False, False,  True, False, False])

利用复合表达式实现数组的逐元素比较也是可行的

1 (2 ** x) == (x ** 2)
2 Out[9]: array([False,  True, False,  True, False])

比较操作符也是借助通用函数来实现的,例如写 x  < 3,Numpy内部会使用np.less(x, 3)

和算术运算符一样,这些比较运算通用函数也是可以用于任意形状,大小的数组

 1 rng = np.random.RandomState(0)
 2 
 3 x = rng.randint(10, size=(3, 4))
 4 
 5 x
 6 Out[12]: 
 7 array([[5, 0, 3, 3],
 8        [7, 9, 3, 5],
 9        [2, 4, 7, 6]])
10 
11 x < 6
12 Out[13]: 
13 array([[ True,  True,  True,  True],
14        [False, False,  True,  True],
15        [ True,  True, False, False]])

操作布尔数组

给定一个布尔数组,可以实现很多操作

1 print(x)
2 [[5 0 3 3]
3  [7 9 3 5]
4  [2 4 7 6]]

1.统计记录的个数

统计布尔数组中的True记录的个数,可以使用np.count_nonzero函数

1 # 有多少值小于6?
2 np.count_nonzero(x < 6)
3 Out[15]: 8

另一种实现方式是利用np.sum,在这个例子里面,False会被解释为0,True会被解释为1:

1 np.sum(x < 6)
2 Out[16]: 8

sum的好处是,与其他Numpy的聚合函数一样,这个求和也可以沿着行或列进行:

1 np.sum(x < 6, axis=1)
2 Out[17]: array([4, 2, 2]) #每一行小于6的个数

如果要快速检查人意或者所有这些值是否为True,可以使用np.any()或np.all()

 1 # 有没有值大于8
 2 np.any(x >8) 
 3 Out[18]: True
 4 # 有没有值小于0
 5 np.any(x < 0)
 6 Out[19]: False
 7 # 是否所有值都小于10
 8 np.all(x < 10)
 9 Out[20]: True
10 # 是否所有值都等于6
11 np.all(x == 6)
12 Out[21]: False
13 
14 ###np.all和np.any也可以用于沿着特定的坐标轴
15 
16 np.all(x < 8, axis=1)
17 Out[22]: array([ True, False,  True])

这里的第一行和第三行的所有元素都小于8,而第二行不是所有的元素都小于8

 2.布尔运算符

现在已经知道了如何统计小于一个数或大于一个数的情况,如果想统计小于一个数且大于另外一个数的情况,可以通过Python的逐位逻辑运算符 & ,|,^, ~来实现的

同标准的算术运算符一样,Numpy用通用函数重载了这些运算符,这样可实现数组的逐位运算(通常是布尔运算)

1 import numpy as np
2 
3 x = np.arange(9).reshape((3,3))
4 
5 np.sum((x > 2) & (x < 5))
6 Out[3]: 2
7 
8 np.sum((x > 2) & (x < 8))
9 Out[4]: 5

利用A AND B 和 NOT (NOT A OR B)的等价原理

np.sum(~( (x > 2) | (x < 4)) )
Out[9]: 1

将比较运算符和布尔运算符用在数组上,可以实现更多有效的逻辑运算操作

以下总结了逐位的布尔运算符和其对应的通用函数:

将布尔数组作为掩码

通过掩码选择数据的子数据集

以前面x数组为例:假设我们希望抽取数组中所有小于5的元素

 1 x = np.random.randint(10, size=(3,4))
 2 
 3 x
 4 Out[13]: 
 5 array([[6, 0, 7, 1],
 6        [2, 2, 8, 7],
 7        [5, 1, 2, 6]])
 8 
 9 x < 5 # 得到一个布尔数组
10 Out[14]: 
11 array([[False,  True, False,  True],
12        [ True,  True, False, False],
13        [False,  True,  True, False]])

为了将这些值选出,可以进行简单的索引,即掩码操作

1 x[x<5]
2 Out[15]: array([0, 1, 2, 2, 1, 2])

返回的是一维数组,包含了所有满足条件的值,所有这些值是掩码数组对应位置为True的值

 花哨的索引

花哨的索引和前面那些简单的索引非常类似,但是传递的是索引数组,而不是单个标量

花哨的索引让我们能够快速获得并修改复杂的数组值的子数据集

探索花哨的索引

传递一个索引数组来一次性获得多个数组元素

假设希望获得三个不同的元素,可以这样实现:

另一种方法是通过传递索引的单个列表或数组来获取相同的结果:

利用花哨的索引,结果的形状与索引数组的形状一致,而不是与被索引数组的形状一样

花哨的索引也对多个维度适用

和标准的索引一样,第一个索引指的是行,第二个索引指的是列:

结果的第一个值是x[0, 2],第二个值是x[1, 1],第三个值是x[2, 3]

当我们将一个列向量和一个行向量组合在一个索引中时,会得到一个二维结果

这里的每一行的值都与每一列的向量匹配,正如我们看到的广播的算术运算:

需要注意的是,花哨索引返回的值反映的是广播后的索引数组的形状,而不是被索引的数组的形状

组合索引

花哨的索引可以与其他索引结合起来形成更强大的索引操作:

可以将花哨索引和简单的索引结合使用:

也可以将花哨的索引和切片操作组合使用:

更可以将花哨索引和掩码组合使用

用花哨的索引修改值

正如花哨的索引可以获取部分数组,也可以用来修改部分数组

设置数组中对应的值:

可以用任何的赋值操作来实现:

需要注意的是,操作重复的索引会导致一些出乎意料的结果产生,如下:

4去了哪里,x[0] = 4,然后x[0] =  6,覆盖地掉了,算是合理的解释,但是:

你可能期望的是x[3] = 2, x[4] = 3,因为这些索引值重复的次数,但为什么结果跟我们想的不一样呢

???????
如果希望累加,可以借助通用函数的at()方法来实现:

at()函数在这里对给定的操作,给定的索引以及给定的值执行的是就地操作,另一个实现该功能的类似方法是通用函数中的reduceat()函数

posted @ 2019-08-24 21:20  木屐呀  阅读(274)  评论(0编辑  收藏  举报
//增加一段JS脚本,为目录生成使用