NumPy 比较、掩码与布尔逻辑

news2025/7/23 5:27:33

文章目录

  • 比较、掩码与布尔逻辑
    • 示例:统计下雨天数
    • 作为通用函数(Ufuncs)的比较运算符
    • 使用布尔数组
      • 计数条目
      • 布尔运算符
    • 布尔数组作为掩码
    • 使用关键字 and/or 与运算符 &/| 的区别

比较、掩码与布尔逻辑

本文介绍如何使用布尔掩码来检查和操作 NumPy 数组中的值。
当你想根据某些条件提取、修改、计数或以其他方式处理数组中的值时,就会用到掩码:例如,你可能希望统计所有大于某个值的元素,或者移除所有高于某个阈值的异常值。
在 NumPy 中,布尔掩码通常是完成此类任务最高效的方法。

示例:统计下雨天数

假设你有一组数据,表示某个城市一年中每天的降水量。
例如,这里我们将使用 Pandas 加载 2015 年西雅图的每日降雨统计数据:

import numpy as np
from vega_datasets import data

# Use DataFrame operations to extract rainfall as a NumPy array
rainfall_mm = np.array(
    data.seattle_weather().set_index('date')['precipitation']['2015'])
len(rainfall_mm)
365

该数组包含 365 个数值,表示 2015 年 1 月 1 日至 12 月 31 日每天的降雨量(单位:毫米)。

作为初步的可视化,我们可以通过下图(使用 Matplotlib 生成)查看雨天的直方图:

%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('seaborn-v0_8-whitegrid')
plt.hist(rainfall_mm, 40);

直方图

这个直方图让我们对数据有了一个大致的了解:尽管这座城市以多雨著称,但实际上 2015 年西雅图大多数日子的降雨量几乎为零。
不过,这并不能很好地展示我们想要了解的信息:比如,这一年中有多少个下雨天?下雨天的平均降水量是多少?有多少天的降水量超过了 10 毫米?

一种方法是手动回答这些问题:我们可以遍历数据,每当遇到落在某个范围内的数值时就递增计数器。
但正如本章多次讨论的那样,从编写代码和计算结果的效率来看,这种方法都非常低效。
我们在NumPy 数组上的计算:通用函数中看到,NumPy 的 ufunc 可以用来替代循环,对数组进行快速的逐元素算术运算;同样地,我们也可以使用其他 ufunc 对数组进行逐元素比较,然后操作结果来回答我们关心的问题。
我们暂且把数据放在一边,先来讨论 NumPy 中的一些通用工具,看看如何利用掩码快速回答这类问题。

作为通用函数(Ufuncs)的比较运算符

NumPy 数组上的计算:通用函数 介绍了通用函数(ufuncs),并重点讲解了算术运算符。我们看到,对数组使用 +-*/ 等运算符会进行逐元素操作。
NumPy 还实现了诸如 <(小于)和 >(大于)这样的比较运算符,并将它们作为逐元素的通用函数。
这些比较运算符的结果总是一个布尔类型的数据数组。
所有六种标准的比较操作都可供使用:

x = np.array([1, 2, 3, 4, 5])
x < 3   # less than 小于
array([ True,  True, False, False, False])
x > 3  # greater than 大于
array([False, False, False,  True,  True])
x <= 3  # less than or equal to 小于等于
array([ True,  True,  True, False, False])
x >= 3  # greater than or equal to 大于等于
array([False, False,  True,  True,  True])
x != 3  # not equal 不等于
array([ True,  True, False,  True,  True])
x == 3  # equal 等于
array([False, False,  True, False, False])

也可以对两个数组进行逐元素比较,并包含复合表达式:

(2 * x) == (x ** 2)  # 等式判断
array([False,  True, False, False, False])

如同算术运算符一样,NumPy 中的比较运算符也是以通用函数(ufuncs)的形式实现的;例如,当你写下 x < 3 时,NumPy 在内部实际上调用的是 np.less(x, 3)
下表总结了常用的比较运算符及其对应的 ufunc:

运算符对应的 ufunc运算符对应的 ufunc
==np.equal!=np.not_equal
<np.less<=np.less_equal
>np.greater>=np.greater_equal

就像算术通用函数(ufuncs)一样,这些比较运算符同样适用于任意大小和形状的数组。
下面是一个二维数组的示例:

rng = np.random.default_rng(seed=1701)
x = rng.integers(10, size=(3, 4))
x
array([[9, 4, 0, 3],
       [8, 6, 3, 1],
       [3, 7, 4, 0]])
x < 6
array([[False,  True,  True,  True],
       [False, False,  True,  True],
       [ True, False,  True,  True]])

在每种情况下,结果都是一个布尔数组,NumPy 提供了许多直接的方法来处理这些布尔结果。

使用布尔数组

给定一个布尔数组,你可以进行许多有用的操作。
我们将使用前面创建的二维数组 x 进行演示:

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

计数条目

要统计布尔数组中 True 条目的数量,可以使用 np.count_nonzero

# 小于6的条目数
np.count_nonzero(x < 6)
8

我们可以看到,有八个数组元素小于 6。
另一种获取此信息的方法是使用 np.sum;在这种情况下,False 会被当作 0True 会被当作 1

np.sum(x < 6)
np.int64(8)

np.sum 的好处在于,和其他 NumPy 聚合函数一样,这种求和操作也可以沿着行或列进行:

# 每一行小于6的条目数
np.sum(x < 6, axis=1)
array([3, 2, 3])

这将统计矩阵每一行中小于 6 的值的数量。

如果我们想快速检查某一行是否有任意值为 True,或者所有值都为 True,可以使用(你猜对了)np.anynp.all

# 是否有大于8的值?
np.any(x > 8)
np.True_
# 是否有小于0的值?
np.any(x < 0)
np.False_
# 所有值都小于10吗?
np.all(x < 10)
np.True_
# 所有值都等于6?
np.all(x == 6)
np.False_

np.allnp.any 也可以沿特定轴进行操作。例如:

# 是否每行的值都小于8?
np.all(x < 8, axis=1)
array([False, False,  True])

这里,第三行的所有元素都小于 8,而其他行则不是如此。

最后需要提醒一点:正如在 聚合:最小值、最大值以及所有其他内容 中提到的,Python 内置的 sumanyall 函数与 NumPy 版本的语法不同,尤其是在多维数组上使用时,可能会出错或产生意外结果。在这些示例中,请确保使用的是 np.sumnp.anynp.all

布尔运算符

我们已经看到如何统计降雨量小于 20 毫米的天数,或者降雨量大于 10 毫米的天数。 但如果我们想知道降雨量大于 10 毫米且小于 20 毫米的天数有多少天呢?这时可以用 Python 的按位逻辑运算符 &|^~ 来实现。 与标准算术运算符类似,NumPy 也重载了这些运算符,使其可以对(通常是布尔型)数组进行逐元素操作。

例如,我们可以这样解决这类复合问题:

np.sum((rainfall_mm > 10) & (rainfall_mm < 20))
np.int64(16)

这告诉我们有 16 天的降雨量在 10 到 20 毫米之间。

这里的括号非常重要。由于运算符优先级规则,如果去掉括号,这个表达式会被如下方式计算,这将导致错误:

rainfall_mm > (10 & rainfall_mm) < 20

Let’s demonstrate a more complicated expression. Using De Morgan’s laws, we can compute the same result in a different manner:
让我们展示一个更复杂的表达方式——利用德摩根定律,用另一种方式得出相同的结果:

np.sum(~( (rainfall_mm <= 10) | (rainfall_mm >= 20) ))
np.int64(16)

将比较运算符与布尔运算符结合应用于数组,可以实现高效且多样的逻辑操作。

下表总结了按位布尔运算符及其对应的通用函数 ufunc:

运算符对应的 ufunc运算符对应的 ufunc
&np.bitwise_and|np.bitwise_or
^np.bitwise_xor~np.bitwise_not

利用这些工具,我们可以开始回答关于天气数据的许多问题。
以下是结合掩码与聚合操作时可以计算的一些结果示例:

print("Number days without rain:  ", np.sum(rainfall_mm == 0))
print("Number days with rain:     ", np.sum(rainfall_mm != 0))
print("Days with more than 10 mm: ", np.sum(rainfall_mm > 10))
print("Rainy days with < 5 mm:    ", np.sum((rainfall_mm > 0) &
                                            (rainfall_mm < 5)))
Number days without rain:   221
Number days with rain:      144
Days with more than 10 mm:  34
Rainy days with < 5 mm:     83

布尔数组作为掩码

在前一节中,我们介绍了如何直接对布尔数组进行聚合计算。
更强大的用法是将布尔数组用作掩码,从而选择数据中的特定子集。让我们回到之前的 x 数组:

x
array([[9, 4, 0, 3],
       [8, 6, 3, 1],
       [3, 7, 4, 0]])

假设我们想要获取数组中所有小于 5 的值组成的数组。正如我们之前看到的,我们可以很容易地为这个条件获得一个布尔数组:

x < 5
array([[False,  True,  True,  True],
       [False, False,  True,  True],
       [ True, False,  True,  True]])

现在,要从数组中选取这些值,我们只需用这个布尔数组进行索引;这被称为掩码操作(masking operation):

x[x < 5]
array([4, 0, 3, 3, 1, 3, 4, 0])

返回的是一个一维数组,包含所有满足该条件的值;换句话说,就是所有在掩码数组中对应位置为 True 的值。

随后,我们可以对这些值进行任意操作。 例如,我们可以对西雅图降雨数据计算一些相关统计量:

# construct a mask of all rainy days
rainy = (rainfall_mm > 0)

# construct a mask of all summer days (June 21st is the 172nd day)
days = np.arange(365)
summer = (days > 172) & (days < 262)

print("Median precip on rainy days in 2015 (mm):   ",
      np.median(rainfall_mm[rainy]))
print("Median precip on summer days in 2015 (mm):  ",
      np.median(rainfall_mm[summer]))
print("Maximum precip on summer days in 2015 (mm): ",
      np.max(rainfall_mm[summer]))
print("Median precip on non-summer rainy days (mm):",
      np.median(rainfall_mm[rainy & ~summer]))
Median precip on rainy days in 2015 (mm):    3.8
Median precip on summer days in 2015 (mm):   0.0
Maximum precip on summer days in 2015 (mm):  32.5
Median precip on non-summer rainy days (mm): 4.1

通过结合布尔运算、掩码操作和聚合操作,我们可以非常快速地回答关于数据集的这类问题。

使用关键字 and/or 与运算符 &/| 的区别

一个常见的困惑点是关键字 andor 与运算符 &| 之间的区别。
什么时候应该用前者,什么时候用后者?

区别在于:andor 作用于整个对象,而 &| 作用于对象中的每个元素。

当你使用 andor 时,相当于让 Python 把整个对象当作一个布尔实体来处理。
在 Python 中,所有非零整数都会被判断为 True。因此:

bool(42), bool(0)
(True, False)
bool(42 and 0)
False
bool(42 or 0)
True

当你对整数使用 &| 时,表达式会作用于元素的位表示,对组成该数字的每一位分别执行按位与按位或操作:

bin(42)
'0b101010'
bin(59)
'0b111011'
bin(42 & 59)
'0b101010'
bin(42 | 59)
'0b111011'

注意,二进制表示的对应位会逐一比较,从而得出结果。

当你在 NumPy 中拥有一个布尔值数组时,可以将其视为一串比特,其中 1 = True0 = False,而 &| 的操作方式与前面的示例类似:

A = np.array([1, 0, 1, 0, 1, 0], dtype=bool)
B = np.array([1, 1, 1, 0, 1, 1], dtype=bool)
A | B
array([ True,  True,  True, False,  True,  True])

但是如果你对这些数组使用 or,它会尝试判断整个数组对象的真值,这并不是一个明确定义的值:

A or B
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

Cell In[38], line 1
----> 1 A or B


ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

类似地,当你对一个数组进行布尔表达式运算时,应使用 |&,而不是 orand

x = np.arange(10)
(x > 4) & (x < 8)
array([False, False, False, False, False,  True,  True,  True, False,
       False])

尝试对整个数组求真或求假会导致和之前一样的 ValueError 错误:

(x > 4) and (x < 8)
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

Cell In[40], line 1
----> 1 (x > 4) and (x < 8)


ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2402477.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣HOT100之二分查找:35. 搜索插入位置

这道题属于是二分查找的入门题了&#xff0c;我依稀记得一些二分查找的编码要点&#xff0c;但是最后还是写出了一个死循环&#xff0c;无语(ˉ▽ˉ&#xff1b;)…又回去看了下自己当时的博客和卡哥的视频&#xff0c;这才发现自己分情况只分了两种&#xff0c;最后导致死循环…

使用API有效率地管理Dynadot域名,查看域名市场中所售域名的详细信息

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

IM即时通讯软件,构建企业局域网内安全协作

安全与权限&#xff1a;协同办公的企业级保障 在协同办公场景中&#xff0c;BeeWorks 将安全机制贯穿全流程。文件在局域网内传输与存储时均采用加密处理&#xff0c;企业网盘支持水印预览、离线文档权限回收等功能&#xff0c;防止敏感资料外泄&#xff1b;多人在线编辑文档时…

VueScan:全能扫描,高清输出

在数字化办公和图像处理的领域&#xff0c;扫描仪扮演着不可或缺的角色。无论是文档的数字化存档、照片的高清复制&#xff0c;还是创意项目的素材采集&#xff0c;一款性能卓越、操作便捷的扫描软件能大幅提升工作效率和成果质量。VueScan正是这样一款集多功能于一身的扫描仪软…

PyCharm项目和文件运行时使用conda环境的教程

打开【文件】—【新建项目】 按照下图配置环境 可以看到我这个项目里&#xff0c;报错“No module named modelscope” 点击终端&#xff0c;输入命令 #显示所有的conda环境 conda env list #选择需要激活的conda环境 conda activate XXX在终端中&#xff0c;执行pip install …

DeepSwiftSeek 开源软件 |用于 DeepSeek LLM 模型的 Swift 客户端 |轻量级和高效的 DeepSeek 核心功能通信

​一、软件介绍 文末提供程序和源码下载 DeepSeek Swift SDK 是一个轻量级且高效的基于 Swift 的客户端&#xff0c;用于与 DeepSeek API 进行交互。它支持聊天消息完成、流式处理、错误处理以及使用高级参数配置 DeepSeekLLM。 二、Features 特征 Supports chat completion …

Flask-Login使用示例

项目结构 首先创建以下文件结构&#xff1a; flask_login_use/ ├── app.py ├── models.py ├── requirements.txt └── templates/├── base.html├── index.html├── login.html├── register.html└── profile.html1. requirements.txt Flask2.3.3 Fl…

web第九次课后作业--SpringBoot基于mybatis实现对数据库的操作

前言 在前面我们学习MySQL数据库时&#xff0c;都是利用图形化客户端工具(如&#xff1a;idea、datagrip)&#xff0c;来操作数据库的。 在客户端工具中&#xff0c;编写增删改查的SQL语句&#xff0c;发给MySQL数据库管理系统&#xff0c;由数据库管理系统执行SQL语句并返回执…

wordpress免费主题网站

这是一款WordPress主题&#xff0c;由jianzhanpress开发&#xff0c;可以免费下载。专为中小微企业设计&#xff0c;提供专业的网站建设、网站运营维护、网站托管和网站优化等服务。主题设计简约、现代&#xff0c;适合多种行业需求。 主要特点&#xff1a; 多样化展示&#…

Go中的协程并发和并发panic处理

1 协程基础 1.1 协程定义&#xff08;Goroutine&#xff09; 概念&#xff1a;Go 语言特有的轻量级线程&#xff0c;由 Go 运行时&#xff08;runtime&#xff09;管理&#xff0c;相比系统线程&#xff08;Thread&#xff09;&#xff0c;创建和销毁成本极低&#xff0c;占用…

Qt Creator工具编译器配置

1、打开Qt Creator&#xff0c;工具-->选项 2、选择"编译器"&#xff0c;Manual配置编译器。 初始化填入“C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\cl.exe”&#xff0c;选择64位amd64。 ABI根据msvc版本进行选择msvc2015. 3、新建项目…

Spring框架学习day7--SpringWeb学习(概念与搭建配置)

SpringWeb1.SpringWeb特点2.SpringWeb运行流程3.SpringWeb组件4.搭建项目结构图&#xff1a;4.1导入jar包4.2在Web.xml配置**4.2.1配置统一拦截分发器 DispatcherServlet**4.2.2开启SpringWeb注解&#xff08;spring.xml&#xff09; 5.处理类的搭建6.SpringWeb请求流程(自己理…

打造高效多模态RAG系统:原理与评测方法详解

引言 随着信息检索与生成式AI的深度融合&#xff0c;检索增强生成&#xff08;RAG, Retrieval-Augmented Generation&#xff09; 已成为AI领域的重要技术方向。传统RAG系统主要依赖文本数据&#xff0c;但真实世界中的信息往往包含图像、表格等多模态内容。多模态RAG&#xf…

【C#】Quartz.NET怎么动态调用方法,并且根据指定时间周期执行,动态配置类何方法以及Cron表达式,有请DeepSeek

&#x1f339;欢迎来到《小5讲堂》&#x1f339; &#x1f339;这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。&#x1f339; &#x1f339;温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01;&#…

02 Deep learning神经网络的编程基础 逻辑回归--吴恩达

逻辑回归 逻辑回归是一种用于解决二分类任务&#xff08;如预测是否是猫咪等&#xff09;的统计学习方法。尽管名称中包含“回归”&#xff0c;但其本质是通过线性回归的变体输出概率值&#xff0c;并使用Sigmoid函数将线性结果映射到[0,1]区间。 以猫咪预测为例 假设单个样…

MySQL的并发事务问题及事务隔离级别

一、并发事务问题 1). 赃读&#xff1a;一个事务读到另外一个事务还没有提交的数据。 比如 B 读取到了 A 未提交的数据。 2). 不可重复读&#xff1a;一个事务先后读取同一条记录&#xff0c;但两次读取的数据不同&#xff0c;称之为不可重复读。 事务 A 两次读取同一条记录&…

ProfiNet 分布式 IO 在某污水处理厂的应用

随着城市化进程的加速&#xff0c;污水处理厂的规模和复杂性不断增加&#xff0c;对自动化控制系统的要求也越来越高。PROfinet 分布式 IO 作为一种先进的工业通信技术&#xff0c;以其高速、可靠、灵活的特性&#xff0c;为污水处理厂的自动化升级提供了有力支持。本文将结合某…

vue2 , el-select 多选树结构,可重名

人家antd都支持&#xff0c;elementplus 也支持&#xff0c;vue2的没有&#xff0c;很烦。 网上其实可以搜到各种的&#xff0c;不过大部分不支持重名&#xff0c;在删除的时候可能会删错&#xff0c;比如树结构1F的1楼啊&#xff0c;2F的1楼啊这种同时勾选的情况。。 可以全…

Excel处理控件Aspose.Cells教程:使用 C# 从 Excel 进行邮件合并

邮件合并功能让您能够轻松批量创建个性化文档&#xff0c;例如信函、电子邮件、发票或证书。您可以从模板入手&#xff0c;并使用电子表格中的数据进行填充。Excel 文件中的每一行都会生成一个新文档&#xff0c;并在正确的位置包含正确的详细信息。这是一种自动化重复性任务&a…

EXCEL通过DAX Studio获取端口号连接PowerBI

EXCEL通过DAX Studio获取端口号连接PowerBI 昨天我分享了EXCEL链接模板是通过获取端口号和数据库来连接PowerBI模型的&#xff0c;链接&#xff1a;浅析EXCEL自动连接PowerBI的模板&#xff0c;而DAX Studio可以获取处于打开状态的PowerBI的端口号。 以一个案例分享如何EXCEL…