NumPy 完全入门指南:核心数据结构与高效数值计算

NumPy 完全入门指南:核心数据结构与高效数值计算

在数据科学和机器学习领域,NumPy 是 Python 生态中最重要的基础库之一。它提供了高性能的多维数组对象 ndarray 以及丰富的数值运算函数。本文将带你从零开始学习 NumPy 的核心概念,包括数组创建、索引切片、形状操作、广播机制、通用函数等,并配有大量代码示例。


1. NumPy 是什么?为什么需要它?

NumPy (Numerical Python)是 Python 数值计算的核心库。它提供了 ndarray(N-dimensional array)对象,用于高效存储和操作大规模多维数据。

1.1 为什么需要 NumPy?

Python 原生的 list 在数值计算中存在明显不足:

  • 运算慢:逐个元素运算需要显式循环,效率低。
  • 不支持批量计算:无法直接对列表所有元素执行数学运算。
  • 多维处理困难:嵌套列表处理高维数据非常繁琐。

NumPy 的优势:

  • 向量化运算:底层 C 实现,避免 Python 循环,速度极快。
  • 高性能:连续内存存储,缓存友好。
  • 多维支持:轻松处理矩阵、张量等复杂数据结构。

对比示例:计算两个列表对应元素相加

python 复制代码
# 原生 list
a = [1, 2, 3]
b = [4, 5, 6]
c = [a[i] + b[i] for i in range(len(a))]  # 需要循环

# NumPy
import numpy as np
a_np = np.array([1, 2, 3])
b_np = np.array([4, 5, 6])
c_np = a_np + b_np   # 直接相加,向量化

2. ndarray:核心数据结构

ndarray 是 NumPy 中最重要的类,代表一个同质的 N 维数组(所有元素类型相同)。

python 复制代码
import numpy as np

# 从列表创建一维数组
arr1 = np.array([1, 2, 3])
print(arr1)          # [1 2 3]

# 创建二维数组
arr2 = np.array([[1, 2], [3, 4]])
print(arr2)
# [[1 2]
#  [3 4]]

2.1 数组属性

每个 ndarray 都有以下重要属性:

属性 说明 示例
ndim 维度数(轴的数量) arr.ndim → 2
shape 形状,每个维度大小的元组 arr.shape → (2, 3)
size 元素总数 arr.size → 6
dtype 元素的数据类型 arr.dtype → int64
itemsize 每个元素的字节大小 arr.itemsize → 8
python 复制代码
arr = np.array([[1, 2, 3], [4, 5, 6]])
print("维度:", arr.ndim)       # 2
print("形状:", arr.shape)      # (2, 3)
print("元素总数:", arr.size)   # 6
print("数据类型:", arr.dtype)  # int64(64位整数)
print("每元素字节:", arr.itemsize)  # 8

2.2 数据类型

NumPy 支持丰富的数据类型,常用有:

  • int8, int16, int32, int64
  • float16, float32, float64
  • bool
  • complex64, complex128

创建数组时指定类型:

python 复制代码
arr_float = np.array([1, 2, 3], dtype=np.float32)
print(arr_float.dtype)   # float32

类型转换:

python 复制代码
arr_int = arr_float.astype(np.int32)

特殊值:

  • 缺失值np.nan(浮点型,不能用 None 代替)
  • 无穷大np.inf

3. 创建数组的各种方式

3.1 从列表或元组创建

python 复制代码
np.array([1, 2, 3])
np.array([(1,2), (3,4)])   # 元组也可

3.2 全0 / 全1 数组

python 复制代码
np.zeros((2, 3))        # 2行3列全0
np.ones((2, 3))         # 全1
np.zeros_like(arr)      # 形状和 arr 相同的全0数组
np.ones_like(arr)

3.3 等差序列

python 复制代码
np.arange(0, 10, 2)      # [0,2,4,6,8]
np.linspace(0, 1, 5)     # [0, 0.25, 0.5, 0.75, 1.0]
np.logspace(0, 2, 3)     # [1, 10, 100]  (10^0, 10^1, 10^2)

3.4 随机数组

python 复制代码
# [0,1) 均匀分布,形状 (2,3)
np.random.rand(2, 3)

# 整数随机,区间 [low, high)
np.random.randint(0, 10, size=(2, 3))

# 标准正态分布
np.random.randn(2, 3)

4. 形状操作

4.1 改变形状(reshaperesize

  • reshape:返回新视图(尽可能不复制),不改变原数组。
  • resize:修改原数组,大小不足时可重复填充。
python 复制代码
arr = np.arange(6)        # [0,1,2,3,4,5]
reshaped = arr.reshape(2, 3)
print(reshaped)
# [[0 1 2]
#  [3 4 5]]

# resize 直接修改原数组
arr.resize(2, 3)   # arr 变为 2x3

4.2 转置

python 复制代码
arr = np.array([[1,2], [3,4]])
print(arr.T)       # 转置
# [[1 3]
#  [2 4]]

4.3 强制最小维度

python 复制代码
arr = np.array([1,2,3], ndmin=2)   # 变成 (1,3) 二维
print(arr.shape)   # (1, 3)

5. 索引与切片

5.1 基本索引

一维数组类似列表:

python 复制代码
arr = np.array([10, 20, 30, 40])
print(arr[0])      # 10
print(arr[-1])     # 40

二维数组:arr[行, 列]

python 复制代码
arr2 = np.array([[1,2,3], [4,5,6], [7,8,9]])
print(arr2[0, 1])    # 2(第0行第1列)
print(arr2[1])       # [4,5,6](第1行所有列)

5.2 切片

语法 start:stop:step,每个维度可独立切片。

python 复制代码
arr2 = np.arange(12).reshape(3, 4)
print(arr2)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

# 取前两行,后两列
sub = arr2[:2, 2:]   # [[2,3], [6,7]]

三维数组切片:arr[层, 行, 列]

python 复制代码
arr3 = np.arange(24).reshape(2, 3, 4)  # 2层,每层3行4列
print(arr3[0, 1:, 2])   # 第0层,第1行及以后,第2列

5.3 布尔索引

使用布尔数组进行条件筛选,非常强大。

python 复制代码
arr = np.array([10, 25, 30, 45, 50])
mask = arr > 30
print(mask)          # [False False False  True  True]
print(arr[mask])     # [45 50]

# 直接写入条件
print(arr[arr % 2 == 0])   # [10,30,50]

布尔索引也可用于赋值:

python 复制代码
arr[arr > 30] = 99
print(arr)   # [10 25 30 99 99]

6. 数值运算与通用函数(ufunc)

通用函数(universal function)是对数组进行逐元素运算的函数。

6.1 算术运算

+, -, *, /, **, % 等均支持逐元素运算(配合广播机制)。

python 复制代码
a = np.array([1,2,3])
b = np.array([4,5,6])
print(a + b)   # [5 7 9]
print(a * b)   # [4 10 18]
print(a ** 2)  # [1 4 9]

6.2 常用数学函数

python 复制代码
arr = np.array([-1, 0, 1, 2])
np.abs(arr)        # 绝对值
np.sqrt(arr)       # 平方根(nan 对负数)
np.exp(arr)        # 指数
np.sin(arr)        # 三角函数

7. 统计方法与逻辑判断

7.1 统计函数

可以指定 axis 按行或按列计算。

函数 说明 示例
arr.max() 最大值 arr.max(axis=0) 每列最大值
arr.min() 最小值
arr.mean() 均值
arr.median() 中位数(需导入) np.median(arr)
arr.std() 标准差
arr.var() 方差
arr.sum() 求和
arr.argmax() 最大值的索引
arr.argmin() 最小值的索引
python 复制代码
arr = np.array([[1,2,3], [4,5,6]])
print(arr.sum())           # 21
print(arr.sum(axis=0))     # 每列求和 -> [5,7,9]
print(arr.mean(axis=1))    # 每行均值 -> [2.,5.]

7.2 逻辑判断

python 复制代码
arr = np.array([1, 2, 3, 4])
print(np.all(arr > 0))     # True,所有元素大于0
print(np.any(arr > 3))     # True,存在大于3的元素

8. 广播机制

广播 允许不同形状的数组进行算术运算。规则:从尾部维度开始比较,如果两个数组的维度大小相等或其中一个为 1,则兼容;否则无法广播。

python 复制代码
# 一维 + 标量
arr = np.array([1,2,3])
print(arr + 10)   # [11 12 13]  标量扩展为 [10,10,10]

# 二维 + 一维
A = np.ones((3, 4))
B = np.array([1,2,3,4])
print(A + B)      # B 广播为 (3,4)

# 二维 + 列向量
C = np.array([[1],[2],[3]])   # (3,1)
print(A + C)      # 广播为 (3,4)

9. 高级技巧

9.1 条件赋值 np.where

python 复制代码
arr = np.array([10, 20, 30, 40])
result = np.where(arr > 25, 100, 0)
print(result)   # [0 0 100 100]

9.2 掩码数组

掩码数组用于标记无效或缺失数据。

python 复制代码
data = np.array([1, 2, np.nan, 4])
mask = np.isnan(data)
data[mask] = 0   # 将缺失值替换为0

9.3 去重 np.unique

python 复制代码
arr = np.array([2, 1, 3, 2, 1])
uniq = np.unique(arr)   # [1,2,3] 自动排序

9.4 内存视图:asarray vs array

  • np.array() 总是复制数据(除非指定 copy=False 且输入已是数组)。
  • np.asarray() 尽可能不复制,输入是数组时直接返回原视图,节省内存。
python 复制代码
a = np.arange(5)
b = np.asarray(a)   # b 是 a 的视图
b[0] = 99
print(a[0])         # 99,原数组被修改

9.5 批量条件赋值(结合布尔索引)

python 复制代码
arr = np.random.randint(0, 100, size=10)
arr[arr < 50] = 0
arr[arr >= 50] = 1

10. 应用场景与补充

  • 数据加载与转换:从 CSV 或二进制文件读入数据,转换为 ndarray。
  • 随机数据生成:模拟实验数据。
  • 机器学习:特征矩阵、权重矩阵运算。
  • 深度学习底层计算 :例如 LoRA 微调中的低秩矩阵乘法 A @ B

矩阵乘法(点积):

python 复制代码
A = np.random.rand(3, 4)
B = np.random.rand(4, 5)
C = np.dot(A, B)   # 或 C = A @ B
print(C.shape)     # (3, 5)

小结

  • NumPy 的核心是 ndarray,支持高效的向量化运算。
  • 掌握创建数组的方法:arrayzerosonesarangelinspacerandom
  • 熟悉数组属性:shapedtypendimsize
  • 索引和切片强大且灵活,包括布尔索引。
  • 通用函数(ufunc)和统计函数让数值计算简洁。
  • 广播机制避免了不必要的数据复制。
  • 高级技巧如 whereuniqueasarray 可提升代码效率。

NumPy 是学习 Pandas、Matplotlib、Scikit-learn 乃至深度学习框架的基础。建议读者多动手练习,将本文示例逐一运行并尝试修改参数,以加深理解。

相关推荐
夏日听雨眠12 小时前
排序(直接插入排序,希尔排序)
数据结构·算法·排序算法
Hesionberger13 小时前
LeetCode105:前序中序构建二叉树(三解法)
java·数据结构·python·算法·leetcode·深度优先
@小柯555m13 小时前
算法(移动零)
数据结构·算法·leetcode
小江的记录本13 小时前
【Java基础】Java 8-21新特性 :JDK17:密封类、模式匹配、Record类(附《思维导图》+《面试高频考点清单》)
java·数据结构·后端·python·mysql·面试·职场和发展
枕星而眠13 小时前
数据结构哈希表(散列表)超详细总结
c语言·数据结构·后端·散列表
一条泥憨鱼13 小时前
【Java 进阶】LinkedHashMap 与 TreeMap
java·开发语言·数据结构·笔记·后端·学习
小江的记录本1 天前
【Java基础】泛型:泛型擦除、通配符、上下界限定(附《思维导图》+《面试高频考点清单》)
java·数据结构·后端·mysql·spring·面试·职场和发展
落羽的落羽1 天前
【算法札记】练习 | Week4
linux·服务器·数据结构·c++·人工智能·算法·动态规划
萑澈1 天前
算法竞赛入门:C++ STL核心用法与时空复杂度速查手册
数据结构·c++·算法·stl