比较 布尔逻辑
本节介绍了使用布尔掩码来检查和操作NumPy数组中的值。
当您要基于某些条件提取,修改,计数或以其他方式操纵数组中的值时,就会出现屏蔽:例如,您可能希望对大于某个值的所有值进行计数,或者可能删除高于某个值的所有异常值阈。在NumPy中,布尔掩码通常是完成这些类型任务的最有效方法。
计算下雨天的例子
在这里,我们将使用Pandas加载2014年西雅图市的每日降雨量统计信息(每天的降水量)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
# 使用 pandas 提取 下雨的英尺数作为numpu数组
rainfall = pd.read_csv('../data/Seattle2014.csv')['PRCP'].values
inches = rainfall / 254.0 # 1/10mm -> inches
inches.shape
## 根据数组作图
import matplotlib.pyplot as plt
#Seaborn其实是在matplotlib的基础上进行了更高级的API封装
import seaborn;
seaborn.set(color_codes=True)#设定颜色
# seaborn.distplot(x, bins=20, kde=False, rug=True);#设置了20个矩形条
plt.hist(inches, 40);
plt.show();
[图片上传失败...(image-ced9c0-1584522338880)]
该直方图使我们对数据的外观有了大致的了解:西雅图的绝大多数日子在2014年的实测降雨量几乎为零。但这并不能很好地传达我们想要的信息看:例如,一年中有多少雨天?那些雨天的平均降雨量是多少?有多少天降雨超过半英寸?
挖掘详细数据
一种解决方法是手动解决这些问题:遍历数据,每当我们看到某个所需范围内的值时就增加一个计数器。出于本章所讨论的原因,从时间和计算结果的角度来看,这种方法都效率很低。我们在NumPy数组计算中看到:通用函数,可以使用NumPy的ufuncs代替循环来对数组进行快速的逐元素算术运算。以相同的方式,我们可以使用其他ufunc在数组上进行逐元素比较,然后我们可以操纵结果来回答所遇到的问题。我们现在将数据放在一边,并讨论NumPy中的一些常规工具,以使用masking快速回答这种类型的问题。
比较运算符为ufuncs
在numpy数组通用计算中,我们引入了ufuncs,尤其着重于算术运算符。我们看到在数组上使用+,-,*,/和其他会导致按元素进行操作。 NumPy还实现了比较运算符,例如<(小于)和>(大于)作为元素方式的ufunc。这些比较运算符的结果始终是具有布尔数据类型的数组。所有六个标准比较操作均可用:
# 与数组每个比较,也可以使用!= > ==等等
In [5]: 5
与算术运算符一样,比较运算符在NumPy中实现为ufunc;当使用x < 3其实调用内部NumPy使用np.less(x,3)。比较运算符及其等效ufunc如下所示:
== np.equal != np.not_equal
< np.less <= np.less_equal
> np.greater >= np.greater_equal
二维数组
In [27]: rng = np.random.randint(10,size=(3,3))
In [28]: rng
Out[28]:
array([[1, 3, 3],
[8, 7, 2],
[7, 0, 9]])
In [29]: x>6
Out[29]:
array([[False, False, False, False],
[ True, True, False, False],
[False, False, True, False]])
使用布尔数组
通过数组布尔运算可以统计很多对我们有用的信息
In [30]: x = np.random.randint(10,size=(3,3))
In [31]: x
Out[31]:
array([[1, 6, 0],
[3, 3, 8],
[0, 9, 7]])
# 计算数组小于等于3的数量,也可以使用np.sum(x<=3)
In [33]: np.count_nonzero(x<=3)
Out[33]: 5
用sum汇总的一个好处是可以根据行或者列来汇总
# 根据列汇总
In [45]: np.sum(x<=3,axis=0)
Out[45]: array([3, 1, 1])
np.any 和 np.all 方法用来判断数组任意一个元素是否符合条件和所有元素是否符合
In [49]: np.any(x<3)
Out[49]: True
In [50]: np.all(x<3)
Out[50]: False
###
In [53]: x
Out[53]:
array([[1, 6, 0],
[3, 3, 8],
[0, 9, 7]])
In [51]: # 判断每行都是否都大于等于3。可以看到第二行满足
...: np.all(x >= 3, axis=1)
Out[55]: array([False, True, False])
- 最后 需要注意的是:如聚合:最小,最大和介于两者之间的内容所述,Python内置了sum(),any()和all()函数。它们的语法与NumPy版本的语法不同,特别是在多维数组上使用时,将失败或产生意外结果。对于这些示例,请确保使用np.sum(),np.any()和np.all()!
布尔运算符
我们已经看到了如何计算,例如,降雨少于四英寸的所有日子,或降雨大于两英寸的所有日子。但是,如果我们想知道降雨小于四英寸且大于一英寸的全天,该怎么办?这是通过Python的按位逻辑运算符&,|,^和〜完成的。与标准算术运算符一样,NumPy将这些重载为ufunc,它们在(通常为Boolean)数组中逐个元素地工作。
In [58]: import numpy as np
...: import pandas as pd
...: # use pandas to extract rainfall inches as a NumPy array
...: rainfall = pd.read_csv('data/Seattle2014.csv')['PRCP'].values
...: inches = rainfall / 254.0 # 1/10mm -> inches
...: inches.shape
Out[58]: (365,)
# 计算降雨量在0.5到1的天数
In [61]:
...: np.sum((inches > 0.5) & (inches < 1))
Out[61]: 29
运算符等效ufunc运算符等效ufunc
& np.bitwise_and | np.bitwise_or
^ np.bitwise_xor ~ np.bitwise_not
通过这些条件就可以计算我们需要的信息
In [64]: print("Number days without rain: ", np.sum(inches == 0))
...: print("Number days with rain: ", np.sum(inches != 0))
...: print("Days with more than 0.5 inches:", np.sum(inches > 0.5))
...: print("Rainy days with < 0.2 inches :", np.sum((inches > 0) &
...: (inches < 0.2)))
Number days without rain: 215
Number days with rain: 150
Days with more than 0.5 inches: 37
Rainy days with < 0.2 inches : 75
布尔数组作为掩码参与数组运算
在上面,我们研究了直接在布尔数组上计算的聚合。一种更强大的模式是使用布尔数组作为掩码,以选择数据本身的特定子集。从前面返回x数组,假设我们想要一个数组,该数组的所有值都小于5,例如:
In [65]: x
Out[65]:
array([[1, 6, 0],
[3, 3, 8],
[0, 9, 7]])
#可以很容易地为此条件获得一个布尔数组:
In [69]: test=x<3
In [70]: test
Out[70]:
array([[ True, False, True],
[False, False, False],
[ True, False, False]])
现在要从数组中选择这些值,我们只需在此布尔数组上建立索引即可;这称为屏蔽操作:
#根据test的索引对应x数组选择True的值
In [71]: x[test]
Out[71]: array([1, 0, 0])
应用到上面统计下雨天的例子中
# construct a mask of all rainy days
rainy = (inches > 0)
# construct a mask of all summer days (June 21st is the 172nd day)
days = np.arange(365)
summer = (days > 172) & (days < 262)
print("雨天的中位数: ",
np.median(inches[rainy]))
print("夏天雨天的中位数: ",
np.median(inches[summer]))
print("夏季雨天最大降水量: ",
np.max(inches[summer]))
print("非夏天雨天的中位数:",
np.median(inches[rainy & ~summer]))
通过组合布尔运算,屏蔽运算和聚合,我们可以非常快速地为我们的数据集回答这类问题。
易混淆
当使用&和|在整数上,表达式对元素的位进行运算。当使用and或or时,等效于要求Python将对象视为单个布尔实体。在Python中,所有非零整数都将评估为True。
In [75]:
...: bool(42), bool(0)
Out[75]: (True, False)
In [76]: bool(42 or 0)
Out[76]: True
# 位运算
In [77]: bin(42 & 59)
Out[77]: '0b101010'
更新github