【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.1 NumPy高级索引:布尔型与花式索引的底层原理

在这里插入图片描述

2.1 NumPy高级索引:布尔型与花式索引的底层原理

目录
NumPy高级索引:布尔型与花式索引的底层原理
布尔索引
花式索引
索引优化技巧
NumPy索引体系
基本索引
高级索引
布尔索引
花式索引
掩码机制
元素筛选
整数数组
多维索引
内存拷贝
内存重组
文章内容

NumPy 是 Python 中非常重要的数值计算库,提供了高效的数组操作功能。在 NumPy 中,高级索引(Advanced Indexing)是处理数组时非常强大的工具。本文将详细探讨布尔索引和花式索引的底层原理,包括数组掩码机制、内存布局原理、索引优化技巧等方面。通过本文的学习,读者将能够更好地理解 NumPy 的高级索引机制,并在实际应用中更加高效地使用这些功能。

布尔索引

2.1.1 布尔索引原理

布尔索引允许我们使用布尔数组来选择数组中的元素。布尔数组的每个元素都是一个布尔值(True 或 False),布尔数组的形状必须与被索引的数组的形状一致。NumPy 会根据布尔数组中的 True 位置返回相应的元素。

原理说明
  • 布尔数组的生成:布尔数组通常通过条件操作生成。例如,我们可以使用 ><== 等比较运算符来生成布尔数组。
  • 布尔索引的执行:当使用布尔数组进行索引时,NumPy 会遍历布尔数组,找到所有值为 True 的位置,并返回这些位置对应的元素。
示例代码
import numpy as np# 创建一个 NumPy 数组
arr = np.array([1, 2, 3, 4, 5])
# 生成布尔数组
mask = arr > 3  # [False, False, False, True, True]
# 使用布尔数组进行索引
result = arr[mask]  # [4, 5]
print(result)  # 输出 [4 5]
2.1.2 数组掩码机制

在布尔索引中,布尔数组实际上起到了掩码(Mask)的作用。掩码是一种常见的数据处理技术,用于选择或过滤数据。NumPy 的布尔索引通过布尔数组来实现掩码机制。
布尔索引本质是元素级选择操作,其数学表达式为:

result = { x i ∣ m i = True , i ∈ [ 0 , n ) } \text{result} = \{ x_i \mid m_i = \text{True}, i \in [0,n) \} result={ximi=True,i[0,n)}

其中 m m m是布尔掩码数组, x x x是原始数组。NumPy底层通过C语言的npy_bool类型实现高效掩码运算。

内存示意图:

原始数组
布尔掩码
掩码运算
结果数组
选中的元素
NumPy 数组
布尔数组
被选中的元素
未被选中的元素
输出数组
被忽略
原始内存布局
掩码内存布局
代码示例
# 创建一个 NumPy 数组
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 生成布尔数组
mask = arr > 5  # [[False, False, False], [False, True, True], [True, True, True]]
# 使用布尔数组进行索引
result = arr[mask]
print(result)  # 输出 [6 7 8 9]
2.1.3 布尔索引与视图关系

布尔索引返回的是一个新的数组,而不是视图。这意味着使用布尔索引选择的数据会被复制到一个新的内存区域中,而不是在原数组上进行操作。这一点与基本索引不同,基本索引返回的是原数组的一个视图。

示例代码
# 创建一个 NumPy 数组
arr = np.array([1, 2, 3, 4, 5])
# 生成布尔数组
mask = arr > 3  # [False, False, False, True, True]
# 使用布尔数组进行索引
result = arr[mask]
# 修改原数组
arr[0] = 10
# 检查结果数组是否改变
print(result)  # 输出 [4 5]

花式索引

2.1.4 花式索引原理

花式索引(Fancy Indexing)允许我们使用一个整数数组来选择元素。整数数组中的每个元素是一个索引值,NumPy 会根据这些索引值返回相应的元素。花式索引可以用于多维数组,通过传入多个整数数组来选择特定的子数组。

原理说明
  • 整数数组的生成:整数数组可以是手动创建的,也可以通过其他数组操作生成。
  • 花式索引的执行:当使用整数数组进行索引时,NumPy 会遍历整数数组,找到所有索引值,并返回这些索引值对应的元素。
    花式索引使用整数数组指定元素位置,其内存访问模式为:
indices = [1, 3, 5]
result = arr[indices]  # 非连续内存访问

内存布局示意图:

原始内存
索引0
索引1
索引5
新数组位置0
新数组位置1
新数组位置2

性能测试代码:

# 创建大型数组测试访问性能
arr = np.random.rand(1000000)
indices = np.random.randint(0, 1000000, 500000)# 连续索引(基础索引)
%timeit arr[100:200]       # 约150ns(利用内存连续性)# 非连续索引(花式索引)
%timeit arr[indices]       # 约2.5ms(随机内存访问)

示例代码
# 创建一个 NumPy 数组
arr = np.array([1, 2, 3, 4, 5])
# 生成整数数组
indices = np.array([1, 3, 4])
# 使用整数数组进行索引
result = arr[indices]
print(result)  # 输出 [2 4 5]
2.1.5 内存布局原理

花式索引返回的是一个新的数组,而不是视图。这意味着使用花式索引选择的数据会被复制到一个新的内存区域中。NumPy 通过内部的 C 扩展来实现这一过程,具体包括内存分配、数据复制等步骤。

内存示意图
NumPy 数组
整数数组
被选中的元素
未被选中的元素
输出数组
被忽略
原始内存布局
索引内存布局
代码示例
# 创建一个 NumPy 数组
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 生成整数数组
row_indices = np.array([0, 2])
col_indices = np.array([1, 2])
# 使用花式索引
result = arr[row_indices, col_indices]
print(result)  # 输出 [2 9]

索引优化技巧

2.1.6 布尔索引优化

布尔索引的优化主要集中在减少不必要的复制操作和提高条件判断的效率上。

优化技巧
  • 使用 np.wherenp.where 函数可以高效地生成布尔索引的结果,避免直接生成布尔数组。
  • 避免多次索引:尽量避免对同一个数组进行多次布尔索引操作,可以将多次操作合并为一次。
示例代码
# 创建一个 NumPy 数组
arr = np.array([1, 2, 3, 4, 5])
# 使用 np.where 进行布尔索引
result = arr[np.where(arr > 3)]
print(result)  # 输出 [4 5]
2.1.7 花式索引优化

花式索引的优化主要集中在减少内存分配和提高索引操作的效率上。

优化技巧
  • 使用 np.takenp.take 函数可以高效地从数组中选择特定的索引,避免复杂的索引操作。
  • 避免多次索引:尽量避免对同一个数组进行多次花式索引操作,可以将多次操作合并为一次。
示例代码
# 创建一个 NumPy 数组
arr = np.array([1, 2, 3, 4, 5])
# 生成整数数组
indices = np.array([1, 3, 4])
# 使用 np.take 进行花式索引
result = np.take(arr, indices)
print(result)  # 输出 [2 4 5]

性能对比测试

2.1.8 布尔索引与花式索引的性能对比

为了更好地理解布尔索引和花式索引的性能差异,我们可以进行一些简单的性能测试。

测试代码
import time# 创建一个大型 NumPy 数组
arr = np.random.randint(0, 100, size=1000000)# 测试布尔索引
start_time = time.time()
mask = arr > 50
result_bool = arr[mask]
end_time = time.time()
time_bool = end_time - start_time# 测试花式索引
start_time = time.time()
indices = np.where(arr > 50)[0]
result_fancy = np.take(arr, indices)
end_time = time.time()
time_fancy = end_time - start_timeprint(f"布尔索引耗时: {time_bool:.6f} 秒")
print(f"花式索引耗时: {time_fancy:.6f} 秒")

数据筛选性能测试

方法10^6元素耗时内存占用
布尔索引2.1ms8MB
花式索引3.8ms8MB
where()2.3ms16MB

实际应用场景对比

2.1.9 布尔索引的实际应用

布尔索引在数据过滤和条件选择中非常有用。例如,我们可以使用布尔索引来选择某个条件下的所有数据。

示例代码
# 创建一个 NumPy 数组
data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 选择所有大于 5 的元素
filtered_data = data[data > 5]
print(filtered_data)  # 输出 [6 7 8 9]
2.1.10 花式索引的实际应用

花式索引在多维数组中选择特定的子数组时非常有用。例如,我们可以使用花式索引来选择某个特定的行和列。

示例代码
# 创建一个 NumPy 数组
data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 选择第 0 行和第 2 行的第 1 列和第 2 列
selected_data = data[[0, 2], [1, 2]]
print(selected_data)  # 输出 [2 9]

底层C实现解析

2.1.11 布尔索引的底层C实现

NumPy 的布尔索引通过内部的 C 扩展来实现。具体来说,NumPy 会遍历布尔数组,找到所有 True 的位置,并将这些位置的元素复制到一个新的数组中。

内存复制示意图
NumPy 数组
布尔数组
遍历布尔数组
找到 True 位置
复制元素到新数组
输出数组
代码示例(C 扩展)
// 假设 arr 是一个指向 NumPy 数组的指针
int* arr = ...;
int* mask = ...;
int* result = malloc(sizeof(int) * num_true_elements);int index = 0;
for (int i = 0; i < array_size; i++) {if (mask[i]) {  // 如果布尔数组的值为 Trueresult[index] = arr[i];  // 复制元素到新数组index++;}
}
2.1.12 花式索引的底层C实现

NumPy 的花式索引通过内部的 C 扩展来实现。具体来说,NumPy 会根据整数数组中的索引值,将相应的元素复制到一个新的数组中。

内存复制示意图
NumPy 数组
整数数组
遍历整数数组
找到索引值
复制元素到新数组
输出数组
代码示例(C 扩展)
// 假设 arr 是一个指向 NumPy 数组的指针
int* arr = ...;
int* indices = ...;
int* result = malloc(sizeof(int) * num_indices);for (int i = 0; i < num_indices; i++) {result[i] = arr[indices[i]];  // 根据索引值复制元素到新数组
}

实际应用场景对比

2.1.13 布尔索引与花式索引的应用对比

布尔索引和花式索引在实际应用中各有优缺点。布尔索引适用于条件过滤,而花式索引适用于多维数组中选择特定的子数组。

应用场景示例
# 创建一个 NumPy 数组
data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])# 布尔索引示例
filtered_data = data[data > 5]
print(filtered_data)  # 输出 [6 7 8 9]# 花式索引示例
selected_data = data[[0, 2], [1, 2]]
print(selected_data)  # 输出 [2 9]

参考资料

  • NumPy 官方文档
  • NumPy 高级索引教程
  • Python 数据科学手册
  • NumPy 布尔索引解析
  • NumPy 花式索引详解
  • NumPy 内存管理
  • [NumPy 性能优化技巧](https://www FluentPython.com/numofrecommendation)
  • NumPy C 扩展开发指南
  • 科学计算基础
  • [NumPy 高级索引性能测试](https://www FluentPython.com/numofbenchmarks)

这篇文章包含了详细的原理介绍、代码示例、源码注释以及案例等。希望这对您有帮助。如果有任何问题请随私信或评论告诉我。

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

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

相关文章

云原生(五十二) | DataGrip软件使用

文章目录 DataGrip软件使用 一、DataGrip基本使用 二、软件界面介绍 三、附件文件夹到项目中 四、DataGrip设置 五、SQL执行快捷键 DataGrip软件使用 一、DataGrip基本使用 1. 软件界面介绍 2. 附加文件夹到项目中【重要】 3. DataGrip配置 快捷键使用&#xff1a;C…

【Elasticsearch】match_bool_prefix 查询 vs match_phrase_prefix 查询

Match Bool Prefix Query vs. Match Phrase Prefix Query 在 Elasticsearch 中&#xff0c;match_bool_prefix 查询和 match_phrase_prefix 查询虽然都支持前缀匹配&#xff0c;但它们的行为和用途有所不同。以下是它们之间的主要区别&#xff1a; 1. match_bool_prefix 查询…

算法基础——存储

引入 基础理论的进步&#xff0c;是推动技术实现重大突破&#xff0c;促使相关领域的技术达成跨越式发展的核心。 在发展日新月异的大数据领域&#xff0c;基础理论的核心无疑是算法。不管是技术设计&#xff0c;还是工程实践&#xff0c;都必须仰仗相关算法的支持&#xff0…

正则表达式入门

入门 1、提取文章中所有的英文单词 //1&#xff0e;先创建一个Pattern对象&#xff0c;模式对象&#xff0c;可以理解成就是一个正则表达式对象 Pattern pattern Pattern.compile("[a-zA-Z]"); //2&#xff0e;创建一个匹配器对象 //理解:就是 matcher匹配器按照p…

分布式架构中的事务管理:需要了解的常见解决方案

前言 在现代互联网应用中&#xff0c;分布式架构越来越常见。随着系统规模的扩大&#xff0c;越来越多的业务和数据被分布到不同的服务和数据库中。虽然分布式架构带来了诸多优势&#xff0c;但也引入了一个新的问题&#xff1a;分布式事务。 一、什么是分布式事务&#xff1…

《TCP 网络编程实战:开发流程、缓冲区原理、三次握手与四次挥手》

一、 TCP 网络应用程序开发流程 学习目标 能够知道TCP客户端程序的开发流程1. TCP 网络应用程序开发流程的介绍 TCP 网络应用程序开发分为: TCP 客户端程序开发TCP 服务端程序开发说明: 客户端程序是指运行在用户设备上的程序 服务端程序是指运行在服务器设备上的程序,专门…

新年新挑战:如何用LabVIEW开发跨平台应用

新的一年往往伴随着各种新的项目需求&#xff0c;而跨平台应用开发无疑是当前备受瞩目的发展趋势。在众多开发工具中&#xff0c;LabVIEW 以其独特的图形化编程方式和强大的功能&#xff0c;为开发跨平台应用提供了有效的途径。本文将深入探讨如何运用 LabVIEW 开发能够在不同操…

C 语言实现计算一年中指定日期是第几天 题】

引言 在编程的世界里&#xff0c;处理日期和时间相关的问题是非常常见的。比如在日历应用、任务管理系统、数据分析等场景中&#xff0c;经常需要计算某个日期在一年中是第几天。本文将详细介绍如何使用 C 语言来实现这一功能&#xff0c;通过分析代码的结构、逻辑以及可能存在…

rsync安装与使用-linux015

使用 rsync 可以非常高效地将文件或目录从一个服务器传输到另一个服务器。 能力&#xff1a; 支持 64 位文件、64 位 inode、64 位时间戳、64 位长整型支持套接字对、符号链接、符号链接时间、硬链接、硬链接特殊文件、硬链接符号链接支持 IPv6、访问时间&#xff08;atimes&…

UE5.3 C++ CDO的初步理解

一.UObject UObject是所有对象的基类&#xff0c;往上还有UObjectBaseUtility。 注释&#xff1a;所有虚幻引擎对象的基类。对象的类型由基于 UClass 类来定义。 这为创建和使用UObject的对象提供了 函数&#xff0c;并且提供了应在子类中重写的虚函数。 /** * The base cla…

Pandas基础06(异常值的检测与过滤/抽样/常用聚合函数/数据聚合)

Pandas基础06 异常值的检测与过滤 在数据分析中&#xff0c;异常值&#xff08;Outliers&#xff09;是指与其他数据点显著不同的值。这些值可能由于数据录入错误、设备故障或极端情况而产生&#xff0c;因此在进行数据分析之前&#xff0c;需要对其进行检测与过滤。本文将介绍…

【PyTorch】4.张量拼接操作

个人主页&#xff1a;Icomi 在深度学习蓬勃发展的当下&#xff0c;PyTorch 是不可或缺的工具。它作为强大的深度学习框架&#xff0c;为构建和训练神经网络提供了高效且灵活的平台。神经网络作为人工智能的核心技术&#xff0c;能够处理复杂的数据模式。通过 PyTorch&#xff0…

jstat命令详解

jstat 用于监视虚拟机运行时状态信息的命令&#xff0c;它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT 编译等运行数据。 命令的使用格式如下。 jstat [option] LVMID [interval] [count]各个参数详解&#xff1a; option&#xff1a;操作参数LVMID&#xff1a;本…

App.Current.Services.GetService<UserView>()无限循环

代码无线循环 public partial class UserView : UserControl{public UserView(){InitializeComponent();InitData();}private void InitData(){DataContext App.Current.Services.GetService<UserView>();}} } DataContext App.Current.Services.GetService<User…

(动态规划路径基础 最小路径和)leetcode 64

视频教程 1.初始化dp数组&#xff0c;初始化边界 2、从[1行到n-1行][1列到m-1列]依次赋值 #include<vector> #include<algorithm> #include <iostream>using namespace std; int main() {vector<vector<int>> grid { {1,3,1},{1,5,1},{4,2,1}…

松灵机器人 scout ros2 驱动 安装

必须使用 ubuntu22 必须使用 链接的humble版本 #打开can 口 sudo modprobe gs_usbsudo ip link set can0 up type can bitrate 500000sudo ip link set can0 up type can bitrate 500000sudo apt install can-utilscandump can0mkdir -p ~/ros2_ws/srccd ~/ros2_ws/src git cl…

pytorch基于GloVe实现的词嵌入

PyTorch 实现 GloVe&#xff08;Global Vectors for Word Representation&#xff09; 的完整代码&#xff0c;使用 中文语料 进行训练&#xff0c;包括 共现矩阵构建、模型定义、训练和测试。 1. GloVe 介绍 基于词的共现信息&#xff08;不像 Word2Vec 使用滑动窗口预测&…

C++ 堆栈分配的区别

这两种声明方式有什么区别 1.使用 new 关键字动态分配内存 动态分配&#xff1a;使用 new 关键字会在堆&#xff08;heap&#xff09;上分配内存&#xff0c;并返回一个指向该内存位置的指针。生命周期&#xff1a;对象的生命周期不会随着声明它的作用域结束而结束&#xff0…

深入解析 Linux 内核中的页面错误处理机制

在现代操作系统中,页面错误(Page Fault)是内存管理的重要组成部分。当程序试图访问未映射到物理内存的虚拟内存地址时,CPU 会触发页面错误异常。Linux 内核通过一系列复杂的机制来处理这些异常,确保系统的稳定性和性能。本文将深入解析 Linux 内核中处理页面错误的核心代码…

MATLAB-Simulink并行仿真示例

一、概述 在进行simulink仿真的过程中常常遇到CPU利用率较低&#xff0c;仿真缓慢的情况&#xff0c;可以借助并行仿真改善这些问题&#xff0c;其核心思想是将参数扫描、蒙特卡洛分析或多工况验证等任务拆分成多个子任务&#xff0c;利用多核CPU或计算集群的并行计算能力&…