Skip to main content

numpy

1. 什么是 NumPy?

NumPy(Numerical Python)是 Python 中最基础的数值计算库。它提供了高性能的多维数组对象(ndarray)以及丰富的数学函数。几乎所有的数据科学、机器学习、科学计算库都基于 NumPy。

为什么要用 NumPy?

想象一下,如果你想计算一个包含 100 万个数字的列表的每个元素的平方。使用 Python 的普通列表需要逐个处理,非常慢。但使用 NumPy 数组,一行代码就能完成,速度可以提升几十倍甚至上百倍。

NumPy 的优势

  • 速度快 :使用 C 语言实现,比 Python 原生列表快得多
  • 向量化计算 :可以对整个数组进行数学运算,无需循环
  • 内存高效 :存储相同的数据,NumPy 数组比 Python 列表占用更少内存
  • 丰富的功能 :提供大量的数学、统计、线性代数函数
  • 生态基础 :Pandas、Matplotlib、Scikit-learn 等都依赖 NumPy

前置知识补充

  • 数组 :数组是一个包含多个元素的数据结构,元素通常是同类型的(比如都是整数或都是浮点数)。一维数组就像一行数字,二维数组像表格,三维数组像立方体。
  • 向量 :一维数组可以称为向量,比如 [1, 2, 3]
  • 矩阵 :二维数组可以称为矩阵,比如 [[1, 2], [3, 4]]
  • 向量化计算 :对数组中的每个元素同时执行相同的操作,比如对数组 [1, 2, 3] 的每个元素加 1,得到 [2, 3, 4]

2. 环境准备

在学习 NumPy 之前,需要确保你的 Python 环境已经准备好。NumPy 支持 Python 3.8 及以上版本。

2.1 检查 Python 版本

在安装之前,先检查一下你的 Python 版本是否符合要求。

# Windows PowerShell:查看 Python 版本
python --version


# macOS 终端:查看 Python 版本
python3 --version

2.2 安装 NumPy

NumPy 可以直接通过 pip 安装。安装过程会自动下载所需的依赖包。

# 说明:Windows PowerShell 安装 NumPy
# 先升级 pip 到最新版本,确保能正常安装依赖
python -m pip install --upgrade pip
# 安装 NumPy 库
python -m pip install numpy


# 说明:macOS / Linux 终端安装 NumPy
# 先升级 pip 到最新版本
python3 -m pip install --upgrade pip
# 安装 NumPy 库
python3 -m pip install numpy

网络加速提示 :如果从 PyPI 下载较慢,可以使用国内镜像:

  • Windows: python -m pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple
  • macOS: python3 -m pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple

安装问题提示 :在某些旧环境中可能遇到二进制轮子缺失的问题,可以尝试:

  • Windows: python -m pip install numpy --prefer-binary
  • macOS: python3 -m pip install numpy --prefer-binary 或者直接安装 Anaconda/Miniconda,它们自带 NumPy。

2.3 验证安装

安装完成后,验证一下是否安装成功。

方法/属性功能说明常用参数返回值
np.array()将 Python 列表转换为 NumPy 数组object:要转换的列表或可迭代对象ndarray 数组对象
ndarray 属性数组的各种属性(如 shape、dtype 等)对应属性值
# -*- coding: utf-8 -*-
# 说明:验证 NumPy 是否安装成功

# 说明:导入 NumPy 库
# 通常使用 np 作为 NumPy 的别名,这是约定俗成的做法
import numpy as np

# 说明:创建一个简单的数组进行测试
# array() 函数可以将 Python 列表转换为 NumPy 数组
test_array = np.array([1, 2, 3, 4, 5])

# 说明:打印数组,验证安装是否成功
print("安装成功!测试数组:", test_array)

# 说明:打印 NumPy 版本信息
print(f"NumPy 版本:{np.__version__}")

# 说明:如果没有报错并输出了数组,说明安装成功

3. 核心概念

在使用 NumPy 之前,需要理解几个核心概念。这些概念是理解 NumPy 的基础。

3.1 ndarray(数组对象)

ndarray 是 NumPy 的核心,它是一个多维数组对象。所有元素必须是相同类型(比如都是整数或都是浮点数)。

3.2 维度(Dimensions)

  • 0 维 :标量(单个数字),如 42
  • 1 维 :向量(一行数字),如 [1, 2, 3]
  • 2 维 :矩阵(表格),如 [[1, 2], [3, 4]]
  • 3 维及以上 :多维数组

3.3 形状(Shape)

形状描述数组在每个维度上的大小。例如:

  • [1, 2, 3] 的形状是 (3,),表示有 3 个元素
  • [[1, 2], [3, 4]] 的形状是 (2, 2),表示有 2 行 2 列

3.4 数据类型(dtype)

NumPy 数组中的元素必须是相同类型,比如:

  • int32:32 位整数
  • float64:64 位浮点数(小数)
  • bool:布尔值(True/False)

4. 创建数组

NumPy 提供了多种创建数组的方法,从 Python 列表转换是最常用的方式。

4.1 从 Python 列表创建

方法/属性功能说明常用参数返回值
np.array()将 Python 列表转换为 NumPy 数组object:要转换的列表或可迭代对象ndarray 数组对象
.shape获取数组的形状(每个维度的大小)无(属性)元组,表示数组形状
# -*- coding: utf-8 -*-
# 说明:演示如何从 Python 列表创建 NumPy 数组

# 说明:导入 NumPy 库
import numpy as np

# 说明:从 Python 列表创建一维数组
# array() 函数将 Python 列表转换为 NumPy 数组
arr1 = np.array([1, 2, 3, 4, 5])
print("一维数组:", arr1)

# 说明:创建二维数组(矩阵形式)
# 传入一个嵌套列表,外层列表的每个元素是一行
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print("二维数组(2行3列):")
print(arr2)

# 说明:创建三维数组(较少使用,但了解即可)
# 三层嵌套列表
arr3 = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print("三维数组:")
print(arr3)
print(f"形状:{arr3.shape}") # 形状是 (2, 2, 2)

4.2 创建特殊数组

NumPy 提供了许多函数来创建常用的特殊数组。

方法/属性功能说明常用参数返回值
np.zeros()创建全零数组shape:数组形状,如 (2, 3)全零数组
np.ones()创建全一数组shape:数组形状,如 (3, 2)全一数组
np.eye()创建单位矩阵(对角线为1,其他为0)N:矩阵大小单位矩阵
np.arange()创建等差数列start:起始值,stop:结束值(不包含),step:步长等差数列
np.linspace()创建等间隔数组start:起始值,stop:结束值(包含),num:元素个数等间隔数组
np.empty()创建空数组(值未初始化)shape:数组形状空数组(值随机)
# -*- coding: utf-8 -*-
# 说明:演示如何创建特殊的数组

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建全零数组
# zeros() 函数创建一个全为 0 的数组
# 参数 (2, 3) 表示创建一个 2 行 3 列的数组
zeros = np.zeros((2, 3))
print("全零数组(2行3列):")
print(zeros)

# 说明:创建全一数组
# ones() 函数创建一个全为 1 的数组
# 参数 (3, 2) 表示创建一个 3 行 2 列的数组
ones = np.ones((3, 2))
print("\n全一数组(3行2列):")
print(ones)

# 说明:创建单位矩阵(对角线为 1,其他为 0)
# eye() 函数创建单位矩阵
# 参数 3 表示创建一个 3x3 的单位矩阵
identity = np.eye(3)
print("\n单位矩阵(3x3):")
print(identity)

# 说明:创建等差数列
# arange() 函数创建一个等差数列
# 参数:起始值、结束值(不包含)、步长
# 这里从 0 开始,到 10(不包含),步长为 2
range_arr = np.arange(0, 10, 2)
print("\n等差数列(0到10,步长2):", range_arr)

# 说明:创建等间隔数组
# linspace() 函数创建一个等间隔的数组
# 参数:起始值、结束值(包含)、元素个数
# 这里从 0 到 1(包含),创建 5 个等间隔的数
linspace_arr = np.linspace(0, 1, 5)
print("\n等间隔数组(0到1,5个数):", linspace_arr)

# 说明:创建空数组(未初始化,值是随机的)
# empty() 函数创建一个空数组(不初始化值,速度更快)
# 参数 (2, 3) 表示创建一个 2 行 3 列的数组
empty = np.empty((2, 3))
print("\n空数组(值未初始化):")
print(empty)

4.3 查看数组属性

了解数组的属性有助于更好地使用 NumPy。

本代码块中使用的 NumPy 属性:

属性功能说明返回值
.ndim数组的维度数整数(如 1 表示一维,2 表示二维)
.shape数组的形状(每个维度的大小)元组(如 (2, 3) 表示 2 行 3 列)
.size数组中元素的总数整数
.dtype数组元素的数据类型数据类型(如 int64float64
.itemsize每个元素占用的字节数整数(字节数)
.nbytes数组占用的总字节数整数(总字节数 = size × itemsize)
# -*- coding: utf-8 -*-
# 说明:演示如何查看数组的属性

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建一个示例数组
arr = np.array([[1, 2, 3], [4, 5, 6]])

# 说明:查看数组的维度(维度数)
# ndim 属性返回数组的维度数
print("维度数:", arr.ndim) # 2 维

# 说明:查看数组的形状(每个维度的大小)
# shape 属性返回一个元组,表示数组的形状
print("形状:", arr.shape) # (2, 3) 表示 2 行 3 列

# 说明:查看数组的元素总数
# size 属性返回数组中元素的总数
print("元素总数:", arr.size) # 2 * 3 = 6

# 说明:查看数组的数据类型
# dtype 属性返回数组中元素的数据类型
print("数据类型:", arr.dtype) # int64(整数)

# 说明:查看数组的大小(字节数)
# itemsize 属性返回每个元素占用的字节数
print("每个元素的字节数:", arr.itemsize) # 8 字节(int64)

# 说明:查看数组的总字节数
# nbytes 属性返回数组占用的总字节数
print("总字节数:", arr.nbytes) # 6 * 8 = 48 字节

5. 索引与切片

索引和切片是访问和修改数组元素的重要方式。NumPy 的索引方式与 Python 列表类似,但支持多维索引。

5.1 基本索引

方法/操作功能说明常用参数返回值
np.arange()创建等差数列start:起始值,stop:结束值(不包含)等差数列
.reshape()改变数组形状shape:新形状,如 (3, 3)重塑后的数组(视图)
arr[i, j]访问数组中的单个元素i:行索引,j:列索引单个元素值
arr[i]访问数组的第 i 行i:行索引第 i 行的数组
arr[:, j]访问数组的第 j 列j:列索引第 j 列的数组
# -*- coding: utf-8 -*-
# 说明:演示基本的索引操作

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建一个 3x3 的数组作为示例
# arange(1, 10) 创建 [1, 2, 3, 4, 5, 6, 7, 8, 9]
# reshape(3, 3) 将其重塑为 3 行 3 列
arr = np.arange(1, 10).reshape(3, 3)
print("原始数组:")
print(arr)

# 说明:访问单个元素
# 使用 [行索引, 列索引] 的方式访问
# 索引从 0 开始,第一个元素的索引是 0
element = arr[1, 1] # 访问第 2 行第 2 列的元素
print(f"\n第2行第2列的元素:{element}")

# 说明:访问整行
# 只指定行索引,不指定列索引,返回整行
row = arr[0] # 访问第 1 行
print(f"第1行:{row}")

# 说明:访问整列
# 使用 [:, 列索引] 的方式访问整列
# : 表示所有行
col = arr[:, 0] # 访问第 1 列
print(f"第1列:{col}")

5.2 切片操作

切片可以获取数组的子集。

方法/操作功能说明常用参数返回值
arr[start:end, start:end]切片获取子数组start:起始索引,end:结束索引(不包含)子数组
arr[-1]使用负数索引(从末尾开始)-1 表示最后一个元素最后一个元素或行
arr[:, :]获取所有行和所有列完整的数组
# -*- coding: utf-8 -*-
# 说明:演示切片操作

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建一个 3x3 的数组
arr = np.arange(1, 10).reshape(3, 3)
print("原始数组:")
print(arr)

# 说明:切片获取子数组
# 语法:arr[行起始:行结束, 列起始:列结束]
# 注意:结束索引不包含在结果中
# arr[0:2, 1:3] 表示第 1-2 行(索引 0-1),第 2-3 列(索引 1-2)
sub_arr = arr[0:2, 1:3]
print("\n子数组(第1-2行,第2-3列):")
print(sub_arr)

# 说明:使用负数索引(从末尾开始)
# -1 表示最后一个元素,-2 表示倒数第二个
last_row = arr[-1] # 最后一行
print(f"\n最后一行:{last_row}")

# 说明:省略所有索引(获取所有行/列)
all_rows = arr[:, :] # 获取所有行和所有列(等同于 arr)
print(f"\n所有行:")
print(all_rows)

5.3 布尔索引

布尔索引可以根据条件筛选数组元素。

方法/操作功能说明常用参数返回值
arr > value比较运算,返回布尔数组value:比较值布尔数组(True/False)
arr[mask]使用布尔掩码筛选元素mask:布尔数组满足条件的元素数组
(条件1) & (条件2)组合多个条件(且)两个布尔条件组合后的布尔数组
arr[condition] = value根据条件修改元素condition:布尔条件,value:新值无(修改原数组)
# -*- coding: utf-8 -*-
# 说明:演示布尔索引(根据条件筛选元素)

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建一个示例数组
arr = np.arange(1, 10).reshape(3, 3)
print("原始数组:")
print(arr)

# 说明:创建布尔掩码(条件)
# 比较运算返回一个布尔数组,其中 True 表示满足条件,False 表示不满足
mask = arr > 5
print("\n布尔掩码(大于5的元素为True):")
print(mask)

# 说明:使用布尔掩码筛选元素
# 只返回掩码中为 True 的位置对应的元素
filtered = arr[mask]
print("\n满足条件(大于5)的元素:", filtered)

# 说明:更复杂的条件
# 可以使用 &(且)、|(或)、~(非)组合多个条件
# 注意:必须使用括号
condition = (arr > 3) & (arr < 7)
result = arr[condition]
print("\n大于3且小于7的元素:", result)

# 说明:修改满足条件的元素
arr[arr > 5] = 0 # 将所有大于 5 的元素设置为 0
print("\n修改后(大于5的元素变为0):")
print(arr)

5.4 花式索引

花式索引可以根据索引列表选择元素。

方法/操作功能说明常用参数返回值
arr[rows]使用索引列表选择行rows:行索引列表选中的行数组
arr[rows, cols]使用索引列表选择元素rows:行索引列表,cols:列索引列表选中的元素数组
np.ix_()创建索引网格(用于矩形区域选择)rows:行索引列表,cols:列索引列表索引网格元组
# -*- coding: utf-8 -*-
# 说明:演示花式索引(使用索引列表选择元素)

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建一个示例数组
arr = np.arange(1, 10).reshape(3, 3)
print("原始数组:")
print(arr)

# 说明:使用索引列表选择特定行
# [0, 2] 表示选择第 1 行和第 3 行(索引 0 和 2)
rows = [0, 2]
selected_rows = arr[rows]
print("\n选择的第1行和第3行:")
print(selected_rows)

# 说明:使用索引列表选择特定元素
# 同时指定行索引和列索引
rows = [0, 2] # 选择第 1 行和第 3 行
cols = [2, 0] # 分别选择第 3 列和第 1 列
selected = arr[rows, cols] # 选择 (0,2) 和 (2,0) 位置的元素
print("\n花式索引结果((0,2) 和 (2,0)):", selected)

# 说明:选择矩形区域
# 使用 np.ix_() 函数创建索引网格
rows = [0, 2]
cols = [0, 2]
grid = arr[np.ix_(rows, cols)] # 选择 (0,0), (0,2), (2,0), (2,2)
print("\n使用 np.ix_() 选择的矩形区域:")
print(grid)

6. 数组操作

数组操作包括形状改变、拼接、拆分等,这些是数据预处理中常用的操作。

6.1 改变数组形状

方法功能说明常用参数返回值
.reshape()改变数组形状(返回视图)shape:新形状,如 (3, 4)重塑后的数组
.flatten()展平数组(返回副本)一维数组(副本)
.ravel()展平数组(返回视图)一维数组(通常是视图)
arr[:, None]增加维度(将行向量变为列向量)None:在指定位置添加新维度增加维度后的数组
# -*- coding: utf-8 -*-
# 说明:演示如何改变数组的形状

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建一维数组
vector = np.arange(12)
print("原始一维数组:", vector)
print(f"形状:{vector.shape}")

# 说明:重塑为二维数组
# reshape() 方法改变数组的形状
# 参数 (3, 4) 表示重塑为 3 行 4 列
# 注意:新形状的元素总数必须与原数组相同(12 = 3 * 4)
matrix = vector.reshape(3, 4)
print("\n重塑为 3x4 矩阵:")
print(matrix)
print(f"形状:{matrix.shape}")

# 说明:展平数组(变回一维)
# flatten() 方法返回一个展平后的副本(不影响原数组)
flat1 = matrix.flatten()
print("\nflatten() 展平(返回副本):", flat1)

# 说明:ravel() 方法也可以展平(通常返回视图,可能影响原数组)
flat2 = matrix.ravel()
print("ravel() 展平(可能返回视图):", flat2)

# 说明:改变数组的维度数
# 使用 None 或 np.newaxis 增加维度
row_vec = np.array([1, 2, 3])
col_vec = row_vec[:, None] # 变为列向量(2 维)
print(f"\n原数组:{row_vec}, 形状:{row_vec.shape}")
print(f"列向量:\n{col_vec}, 形状:{col_vec.shape}")

6.2 拼接数组

方法功能说明常用参数返回值
np.vstack()垂直拼接(按行拼接,行数增加)tup:要拼接的数组元组或列表垂直拼接后的数组
np.hstack()水平拼接(按列拼接,列数增加)tup:要拼接的数组元组或列表水平拼接后的数组
np.concatenate()通用拼接函数arrays:要拼接的数组列表,axis:拼接的轴(0=行,1=列)拼接后的数组
# -*- coding: utf-8 -*-
# 说明:演示如何拼接数组

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建两个示例数组
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
print("数组 a:")
print(a)
print("\n数组 b:")
print(b)

# 说明:垂直拼接(按行拼接)
# vstack() 函数将数组垂直堆叠
# 结果的行数增加
vertical = np.vstack([a, b])
print("\n垂直拼接(按行):")
print(vertical)

# 说明:水平拼接(按列拼接)
# hstack() 函数将数组水平堆叠
# 结果的列数增加
horizontal = np.hstack([a, b])
print("\n水平拼接(按列):")
print(horizontal)

# 说明:通用拼接函数
# concatenate() 函数可以指定拼接的轴(axis)
# axis=0 表示按行拼接(垂直),axis=1 表示按列拼接(水平)
concatenated = np.concatenate([a, b], axis=0)
print("\n使用 concatenate() 垂直拼接:")
print(concatenated)

6.3 拆分数组

方法功能说明常用参数返回值
np.hsplit()水平拆分(按列拆分)ary:要拆分的数组,indices:拆分点或部分数拆分后的数组列表
np.vsplit()垂直拆分(按行拆分)ary:要拆分的数组,indices:拆分点或部分数拆分后的数组列表
np.split()通用拆分函数ary:要拆分的数组,indices_or_sections:拆分点,axis:拆分的轴拆分后的数组列表
# -*- coding: utf-8 -*-
# 说明:演示如何拆分数组

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建一个示例数组
arr = np.arange(12).reshape(3, 4)
print("原始数组:")
print(arr)

# 说明:水平拆分(按列拆分)
# hsplit() 函数将数组水平拆分成多个子数组
# 参数 2 表示拆分成 2 个部分
parts = np.hsplit(arr, 2)
print("\n水平拆分成 2 部分:")
for i, part in enumerate(parts):
print(f"第 {i+1} 部分:")
print(part)

# 说明:垂直拆分(按行拆分)
# vsplit() 函数将数组垂直拆分成多个子数组
parts = np.vsplit(arr, 3)
print("\n垂直拆分成 3 部分:")
for i, part in enumerate(parts):
print(f"第 {i+1} 部分:")
print(part)

# 说明:通用拆分函数
# split() 函数可以指定拆分的轴
parts = np.split(arr, 3, axis=0) # 按行拆分
print("\n使用 split() 按行拆分:")
for i, part in enumerate(parts):
print(f"第 {i+1} 部分:")
print(part)

7. 数学运算

NumPy 提供了丰富的数学运算函数,支持向量化计算(对整个数组进行计算)。

7.1 基本运算

本代码块中使用的 NumPy 操作:

操作功能说明示例返回值
arr1 + arr2向量化加法(对应元素相加)a + b相加后的数组
arr1 - arr2向量化减法(对应元素相减)b - a相减后的数组
arr1 * arr2向量化乘法(对应元素相乘,不是矩阵乘法)a * b相乘后的数组
arr1 / arr2向量化除法(对应元素相除)b / a相除后的数组
arr ** n幂运算(每个元素的 n 次方)a ** 2幂运算后的数组
arr + scalar标量与数组运算(广播)a + 10每个元素都加上标量的数组
arr * scalar标量与数组运算(广播)a * 2每个元素都乘以标量的数组
# -*- coding: utf-8 -*-
# 说明:演示基本的数学运算

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建两个示例数组
a = np.array([1, 2, 3, 4])
b = np.array([5, 6, 7, 8])

print("数组 a:", a)
print("数组 b:", b)

# 说明:向量化加法(对应元素相加)
# NumPy 可以直接对数组进行数学运算,不需要循环
add_result = a + b
print("\n加法(a + b):", add_result)

# 说明:向量化减法
sub_result = b - a
print("减法(b - a):", sub_result)

# 说明:向量化乘法(对应元素相乘,不是矩阵乘法)
mult_result = a * b
print("乘法(a * b,对应元素相乘):", mult_result)

# 说明:向量化除法
div_result = b / a
print("除法(b / a):", div_result)

# 说明:幂运算
power_result = a ** 2
print("幂运算(a 的平方):", power_result)

# 说明:标量与数组的运算(广播)
# NumPy 会自动将标量广播到数组的每个元素
scalar_add = a + 10
print("\n标量加法(a + 10):", scalar_add)

scalar_mult = a * 2
print("标量乘法(a * 2):", scalar_mult)

7.2 数学函数

NumPy 提供了丰富的数学函数。

方法功能说明常用参数返回值
np.sin()计算正弦值x:角度(弧度)正弦值数组
np.cos()计算余弦值x:角度(弧度)余弦值数组
np.tan()计算正切值x:角度(弧度)正切值数组
np.exp()计算 e 的 x 次方x:指数e^x 数组
np.log()计算自然对数(以 e 为底)x:真数自然对数数组
np.log10()计算以 10 为底的对数x:真数常用对数数组
np.sqrt()计算平方根x:被开方数平方根数组
np.cbrt()计算立方根x:被开方数立方根数组
np.abs()计算绝对值x:数值绝对值数组
np.floor()向下取整x:浮点数向下取整后的数组
np.ceil()向上取整x:浮点数向上取整后的数组
np.round()四舍五入x:浮点数四舍五入后的数组
np.pi圆周率常量无(常量)3.14159...
# -*- coding: utf-8 -*-
# 说明:演示 NumPy 的数学函数

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建示例数组
arr = np.array([1, 2, 3, 4])

# 说明:三角函数
angles = np.array([0, np.pi/4, np.pi/2])
print("角度(弧度):", angles)
print("sin值:", np.sin(angles))
print("cos值:", np.cos(angles))
print("tan值:", np.tan(angles))

# 说明:指数和对数
print("\n指数运算(e的x次方):", np.exp(arr))
print("自然对数:", np.log(arr))
print("以10为底的对数:", np.log10(arr))

# 说明:开方和幂
print("\n平方根:", np.sqrt(arr))
print("立方根:", np.cbrt(arr))

# 说明:绝对值
neg_arr = np.array([-1, -2, 3, -4])
print("\n绝对值:", np.abs(neg_arr))

# 说明:向上取整和向下取整
float_arr = np.array([1.2, 2.7, 3.5, 4.1])
print("\n向下取整:", np.floor(float_arr))
print("向上取整:", np.ceil(float_arr))
print("四舍五入:", np.round(float_arr))

8. 统计函数

NumPy 提供了丰富的统计函数,可以计算均值、标准差、最大值、最小值等。

8.1 基本统计

方法功能说明常用参数返回值
np.sum()计算所有元素的总和a:数组,axis:统计的轴(可选)总和值
np.mean()计算所有元素的平均值a:数组,axis:统计的轴(可选)平均值
np.std()计算标准差(衡量数据离散程度)a:数组,axis:统计的轴(可选)标准差
np.var()计算方差(标准差的平方)a:数组,axis:统计的轴(可选)方差
np.max()找出最大值a:数组,axis:统计的轴(可选)最大值
np.min()找出最小值a:数组,axis:统计的轴(可选)最小值
np.argmax()找出最大值的索引a:数组,axis:统计的轴(可选)最大值的索引
np.argmin()找出最小值的索引a:数组,axis:统计的轴(可选)最小值的索引
# -*- coding: utf-8 -*-
# 说明:演示 NumPy 的统计函数

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建一个示例矩阵
matrix = np.arange(1, 10).reshape(3, 3)
print("示例矩阵:")
print(matrix)

# 说明:计算总和
# sum() 函数计算所有元素的总和
total = np.sum(matrix)
print(f"\n总和:{total}")

# 说明:计算均值
# mean() 函数计算所有元素的平均值
average = np.mean(matrix)
print(f"均值:{average:.2f}")

# 说明:计算标准差
# std() 函数计算标准差(衡量数据的离散程度)
std_dev = np.std(matrix)
print(f"标准差:{std_dev:.2f}")

# 说明:计算方差
# var() 函数计算方差(标准差的平方)
variance = np.var(matrix)
print(f"方差:{variance:.2f}")

# 说明:找出最大值和最小值
max_value = np.max(matrix)
min_value = np.min(matrix)
print(f"\n最大值:{max_value}")
print(f"最小值:{min_value}")

# 说明:找出最大值和最小值的索引
max_index = np.argmax(matrix)
min_index = np.argmin(matrix)
print(f"最大值的索引(展平后):{max_index}")
print(f"最小值的索引(展平后):{min_index}")

8.2 按轴统计

在多维数组中,可以指定统计的轴(维度)。

方法功能说明参数说明返回值
np.mean(axis=0)沿行方向统计(计算每列的均值)axis=0:沿行方向每列均值的数组
np.mean(axis=1)沿列方向统计(计算每行的均值)axis=1:沿列方向每行均值的数组
np.sum(axis=0)沿行方向统计(计算每列的总和)axis=0:沿行方向每列总和的数组
np.sum(axis=1)沿列方向统计(计算每行的总和)axis=1:沿列方向每行总和的数组
# -*- coding: utf-8 -*-
# 说明:演示按轴进行统计(沿特定维度)

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建一个 3x4 的矩阵
matrix = np.arange(12).reshape(3, 4)
print("示例矩阵(3行4列):")
print(matrix)

# 说明:按行统计(axis=0,计算每列)
# axis=0 表示沿着行方向(垂直方向)统计
column_mean = np.mean(matrix, axis=0)
print("\n每列的平均值(axis=0):", column_mean)

column_sum = np.sum(matrix, axis=0)
print("每列的总和(axis=0):", column_sum)

# 说明:按列统计(axis=1,计算每行)
# axis=1 表示沿着列方向(水平方向)统计
row_mean = np.mean(matrix, axis=1)
print("\n每行的平均值(axis=1):", row_mean)

row_sum = np.sum(matrix, axis=1)
print("每行的总和(axis=1):", row_sum)

# 说明:不指定轴(计算所有元素)
all_mean = np.mean(matrix)
print(f"\n所有元素的平均值(不指定轴):{all_mean}")

9. 随机数

NumPy 的 random 模块提供了生成随机数的功能,常用于模拟、采样、数据增强等场景。

9.1 基本随机数生成

方法功能说明常用参数返回值
np.random.seed()设置随机种子(确保结果可复现)seed:种子值
np.random.rand()生成 [0, 1) 区间的均匀分布随机数*d0, d1, ...:各维度大小均匀分布随机数组
np.random.randn()生成标准正态分布随机数(均值0,标准差1)*d0, d1, ...:各维度大小标准正态分布随机数组
np.random.randint()生成指定区间的整数随机数low:最小值,high:最大值(不包含),size:大小整数随机数组
np.random.normal()生成正态分布随机数loc:均值,scale:标准差,size:大小正态分布随机数组
# -*- coding: utf-8 -*-
# 说明:演示 NumPy 的随机数生成

# 说明:导入 NumPy 库
import numpy as np

# 说明:设置随机种子(确保结果可复现)
# 设置相同的种子,每次运行会得到相同的随机数
np.random.seed(42)

# 说明:生成均匀分布的随机数
# rand() 函数生成 [0, 1) 区间的均匀分布随机数
# 参数 (2, 3) 表示生成一个 2 行 3 列的数组
uniform = np.random.rand(2, 3)
print("均匀分布随机数([0, 1) 区间):")
print(uniform)

# 说明:生成标准正态分布的随机数
# randn() 函数生成标准正态分布(均值为0,标准差为1)的随机数
normal = np.random.randn(2, 3)
print("\n标准正态分布随机数:")
print(normal)

# 说明:生成指定区间的整数随机数
# randint() 函数生成指定区间的整数随机数
# 参数:最小值(包含)、最大值(不包含)、大小
integers = np.random.randint(0, 10, size=(2, 3))
print("\n整数随机数(0-9):")
print(integers)

# 说明:生成指定分布和参数的随机数
# normal() 函数生成正态分布随机数
# 参数:均值、标准差、大小
custom_normal = np.random.normal(loc=100, scale=15, size=(2, 3))
print("\n自定义正态分布(均值100,标准差15):")
print(custom_normal)

9.2 随机选择与打乱

方法功能说明常用参数返回值
np.random.choice()从数组中随机选择元素a:数组,size:选择数量,replace:是否允许重复随机选择的元素数组
np.random.shuffle()原地打乱数组(修改原数组)x:要打乱的数组无(修改原数组)
np.random.permutation()返回打乱后的新数组(不修改原数组)x:要打乱的数组打乱后的新数组
# -*- coding: utf-8 -*-
# 说明:演示随机选择和打乱操作

# 说明:导入 NumPy 库
import numpy as np

# 说明:设置随机种子
np.random.seed(42)

# 说明:从数组中选择随机元素
# choice() 函数从数组中随机选择元素
# 参数:数组、选择数量、是否允许重复
choices = np.array(["A", "B", "C", "D"])
selected = np.random.choice(choices, size=5, replace=True)
print("从数组中选择 5 个元素(允许重复):", selected)

# 说明:随机打乱数组
# shuffle() 函数原地打乱数组(修改原数组)
arr = np.arange(10)
print("\n原始数组:", arr)
np.random.shuffle(arr)
print("打乱后:", arr)

# 说明:返回打乱后的新数组(不修改原数组)
arr2 = np.arange(10)
print("\n原始数组:", arr2)
shuffled = np.random.permutation(arr2)
print("打乱后的新数组:", shuffled)
print("原数组未改变:", arr2)

10. 文件操作

NumPy 可以方便地将数组保存到文件或从文件加载数组。

10.1 保存和加载

方法功能说明常用参数返回值
np.random.randn()生成标准正态分布随机数*d0, d1, ...:各维度大小标准正态分布随机数组
np.savetxt()将数组保存为文本文件fname:文件名,X:数组,fmt:格式,delimiter:分隔符
np.loadtxt()从文本文件加载数组fname:文件名,delimiter:分隔符加载的数组
np.save()将数组保存为二进制文件(.npy 格式)file:文件名,arr:数组
np.load()从二进制文件加载数组(.npy 或 .npz 格式)file:文件名加载的数组或字典
np.allclose()检查两个数组是否近似相等a:数组1,b:数组2布尔值(True/False)
# -*- coding: utf-8 -*-
# 说明:演示如何保存和加载 NumPy 数组

# 说明:导入 NumPy 库
import numpy as np
import os

# 说明:创建示例数据
data = np.random.randn(5, 3)
print("原始数据:")
print(data)

# 说明:保存为文本文件
# savetxt() 函数将数组保存为文本文件
# 参数:文件名、数据、格式、分隔符
np.savetxt("data.txt", data, fmt="%.4f", delimiter=",")
print("\n数据已保存到 data.txt")

# 说明:从文本文件加载
# loadtxt() 函数从文本文件加载数组
loaded_txt = np.loadtxt("data.txt", delimiter=",")
print("\n从文本文件加载的数据:")
print(loaded_txt)

# 说明:保存为二进制文件(推荐,更快更小)
# save() 函数将数组保存为 .npy 格式(NumPy 二进制格式)
np.save("data.npy", data)
print("\n数据已保存到 data.npy")

# 说明:从二进制文件加载
# load() 函数从 .npy 文件加载数组
loaded_npy = np.load("data.npy")
print("\n从二进制文件加载的数据:")
print(loaded_npy)

# 说明:验证数据是否一致
if np.allclose(data, loaded_npy):
print("\n✓ 数据加载成功,与原始数据一致")

# 说明:清理临时文件(可选)
if os.path.exists("data.txt"):
os.remove("data.txt")
if os.path.exists("data.npy"):
os.remove("data.npy")

10.2 批量保存和加载

方法功能说明常用参数返回值
np.savez()将多个数组保存到一个压缩文件(.npz 格式)file:文件名,**kwds:关键字参数(数组名称=数组)
np.load()加载 .npz 文件,返回类似字典的对象file:文件名类似字典的对象,可用键访问数组
# -*- coding: utf-8 -*-
# 说明:演示如何批量保存和加载多个数组

# 说明:导入 NumPy 库
import numpy as np
import os

# 说明:创建多个数组
arr1 = np.array([1, 2, 3])
arr2 = np.array([[4, 5], [6, 7]])
arr3 = np.array([8, 9, 10])

# 说明:批量保存多个数组
# savez() 函数将多个数组保存到一个压缩文件
# 使用关键字参数指定每个数组的名称
np.savez("multiple_arrays.npz", array1=arr1, array2=arr2, array3=arr3)
print("多个数组已保存到 multiple_arrays.npz")

# 说明:从压缩文件加载
# load() 函数加载 .npz 文件,返回一个类似字典的对象
loaded = np.load("multiple_arrays.npz")
print("\n加载的数组:")
print("array1:", loaded["array1"])
print("array2:")
print(loaded["array2"])
print("array3:", loaded["array3"])

# 说明:查看文件中包含的所有数组名称
print("\n文件中包含的数组名称:", list(loaded.keys()))

# 说明:清理临时文件(可选)
if os.path.exists("multiple_arrays.npz"):
os.remove("multiple_arrays.npz")

11. 实战案例:销售数据分析

下面是一个完整的实战案例,展示如何使用 NumPy 分析销售数据。

方法功能说明常用参数返回值
np.random.normal()生成正态分布随机数loc:均值,scale:标准差,size:大小正态分布随机数组
.astype()转换数组的数据类型dtype:目标数据类型,如 int转换类型后的数组
.sum(axis=0)沿行方向求和(计算每列总和)axis=0:沿行方向每列总和的数组
.sum(axis=1)沿列方向求和(计算每行总和)axis=1:沿列方向每行总和的数组
.mean(axis=0)沿行方向求均值(计算每列均值)axis=0:沿行方向每列均值的数组
np.diff()计算相邻元素的差值a:数组差值数组(长度比原数组少1)
np.argmax()找出最大值的索引a:数组,axis:统计的轴(可选)最大值的索引
# -*- coding: utf-8 -*-
# 说明:实战案例 - 销售数据分析
# 演示如何使用 NumPy 分析模拟的销售数据

# 说明:导入 NumPy 库
import numpy as np

# 说明:设置随机种子,确保结果可复现
np.random.seed(0)

# 说明:生成模拟的销售数据
# 生成 12 个月 × 4 个产品的销售数据
# normal() 生成正态分布随机数:均值 1000,标准差 200
# astype(int) 将浮点数转换为整数
sales = np.random.normal(loc=1000, scale=200, size=(12, 4)).astype(int)
products = np.array(["产品A", "产品B", "产品C", "产品D"])

# 说明:打印原始数据
print("月度销量矩阵(12个月 × 4个产品):")
print(sales)
print(f"形状:{sales.shape}\n")

# 说明:计算每个产品的总销售额
# sum(axis=0) 计算每列的总和(每个产品的全年总销售额)
total_by_product = sales.sum(axis=0)
print("每个产品的全年总销售额:")
for prod, total in zip(products, total_by_product):
print(f" {prod}:{total:,}")

# 说明:计算每个产品的平均月销售额
avg_by_product = sales.mean(axis=0)
print("\n每个产品的平均月销售额:")
for prod, avg in zip(products, avg_by_product):
print(f" {prod}:{avg:.2f}")

# 说明:计算每个月的总销售额
# sum(axis=1) 计算每行的总和(每个月的总销售额)
monthly_total = sales.sum(axis=1)
print(f"\n每个月的总销售额:{monthly_total}")

# 说明:计算月度增长率
# diff() 函数计算相邻元素的差值
# 计算增长率:差值 / 上月的销售额 * 100
growth = np.diff(monthly_total) / monthly_total[:-1] * 100
print("\n月度增长率(%):")
for i, g in enumerate(growth, 1):
print(f" 第{i}月到第{i+1}月:{g:.2f}%")

# 说明:找出销售最好的月份和产品
best_month_idx = np.argmax(monthly_total)
best_month_sales = monthly_total[best_month_idx]
print(f"\n销售最好的月份:第{best_month_idx + 1}月,销售额:{best_month_sales:,}")

# 说明:找出每个产品销量最好的月份
print("\n每个产品销量最好的月份:")
for i, prod in enumerate(products):
best_month = np.argmax(sales[:, i]) + 1 # +1 因为月份从1开始
best_sales = sales[best_month - 1, i]
print(f" {prod}:第{best_month}月,销量:{best_sales:,}")

12. 性能优化与常见问题

在使用 NumPy 时,了解一些优化技巧和常见问题有助于提高代码效率。

12.1 向量化 vs 循环

NumPy 的向量化计算比 Python 循环快得多。

方法功能说明常用参数返回值
np.random.rand()生成 [0, 1) 区间的均匀分布随机数*d0, d1, ...:各维度大小均匀分布随机数组
arr * arr向量化乘法(对应元素相乘)两个数组相乘后的数组
np.allclose()检查两个数组是否近似相等a:数组1,b:数组2布尔值(True/False)
# -*- coding: utf-8 -*-
# 说明:演示向量化计算与循环的性能对比

# 说明:导入必要的库
import numpy as np
import time

# 说明:创建一个大型数组
arr = np.random.rand(1_000_000) # 100 万个元素

# 说明:方法1:使用 Python 循环
# 这是慢的方法,逐个元素计算
start = time.time()
loop_result = np.array([x * x for x in arr])
loop_time = time.time() - start

# 说明:方法2:使用 NumPy 向量化
# 这是快的方法,对整个数组进行运算
start = time.time()
np_result = arr * arr
np_time = time.time() - start

# 说明:比较结果
print(f"Python 循环耗时:{loop_time:.4f} 秒")
print(f"NumPy 向量化耗时:{np_time:.4f} 秒")
print(f"速度提升:{loop_time / np_time:.1f} 倍")

# 说明:验证结果是否一致
if np.allclose(loop_result, np_result):
print("\n✓ 两种方法结果一致,但向量化更快")

12.2 数据类型选择

合理选择数据类型可以节省内存。

本代码块中使用的 NumPy 方法和属性:

方法/属性功能说明常用参数返回值
np.array(..., dtype=...)创建指定数据类型的数组object:数据,dtype:数据类型指定类型的数组
.dtype获取数组的数据类型无(属性)数据类型对象
.nbytes获取数组占用的总字节数无(属性)总字节数(整数)
.astype()转换数组的数据类型dtype:目标数据类型转换类型后的数组
# -*- coding: utf-8 -*-
# 说明:演示数据类型对内存的影响

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建相同数据的数组,但使用不同的数据类型
arr_int32 = np.array([1, 2, 3, 4], dtype=np.int32)
arr_int64 = np.array([1, 2, 3, 4], dtype=np.int64)
arr_float64 = np.array([1, 2, 3, 4], dtype=np.float64)

# 说明:查看每个数组的内存占用
print(f"int32 数组大小:{arr_int32.nbytes} 字节")
print(f"int64 数组大小:{arr_int64.nbytes} 字节")
print(f"float64 数组大小:{arr_float64.nbytes} 字节")

# 说明:查看数据类型
print(f"\nint32 数据类型:{arr_int32.dtype}")
print(f"int64 数据类型:{arr_int64.dtype}")
print(f"float64 数据类型:{arr_float64.dtype}")

# 说明:转换数据类型
# astype() 方法可以转换数组的数据类型
arr_float = arr_int32.astype(np.float32)
print(f"\n转换为 float32:{arr_float.dtype}")

12.3 广播机制

广播机制允许不同形状的数组进行运算。

本代码块中使用的 NumPy 方法和操作:

方法/操作功能说明常用参数返回值
np.arange()创建等差数列start:起始值,stop:结束值(不包含)等差数列
.reshape()改变数组形状shape:新形状重塑后的数组
arr1 + arr2数组加法(支持广播)两个数组(形状可不同,但需兼容)相加后的数组
arr + scalar数组与标量相加(广播)arr:数组,scalar:标量每个元素都加上标量的数组
# -*- coding: utf-8 -*-
# 说明:演示 NumPy 的广播机制

# 说明:导入 NumPy 库
import numpy as np

# 说明:创建一个矩阵和一个向量
matrix = np.arange(12).reshape(3, 4)
vector = np.array([10, 20, 30, 40])

print("矩阵:")
print(matrix)
print(f"\n向量:{vector}")
print(f"向量形状:{vector.shape}")

# 说明:广播:向量会自动扩展以匹配矩阵的形状
# 这里向量会扩展为 3x4 矩阵,每一行都是 [10, 20, 30, 40]
result = matrix + vector
print("\n矩阵 + 向量(广播):")
print(result)

# 说明:标量广播
scalar = 100
result2 = matrix + scalar
print("\n矩阵 + 标量(广播):")
print(result2)

12.4 常见问题

本代码块中使用的 NumPy 方法和操作:

方法/操作功能说明常用参数返回值
arr[start:end]切片操作(返回视图)start:起始索引,end:结束索引切片数组(视图)
.copy()创建数组的副本数组的独立副本
arr1 + arr2数组加法(广播)两个数组相加后的数组
arr / scalar数组除法(自动转换为浮点数)arr:数组,scalar:标量相除后的数组(浮点型)
# -*- coding: utf-8 -*-
# 说明:常见问题和解决方案

# 说明:导入 NumPy 库
import numpy as np

# 说明:问题1:修改数组时的视图 vs 副本
print("问题1:视图 vs 副本")
arr = np.array([1, 2, 3, 4, 5])
view = arr[1:4] # 这是视图(引用)
view[0] = 999 # 修改视图会影响原数组
print(f"原数组被修改:{arr}")

arr2 = np.array([1, 2, 3, 4, 5])
copy = arr2[1:4].copy() # 这是副本(独立)
copy[0] = 999
print(f"原数组未改变:{arr2}")

# 说明:问题2:数组形状不匹配
print("\n问题2:形状不匹配时的处理")
a = np.array([[1, 2], [3, 4]])
b = np.array([5, 6])
try:
# 这可能会出错,因为形状不匹配
result = a + b
print("运算成功(广播):")
print(result)
except Exception as e:
print(f"错误:{e}")

# 说明:问题3:整数除法的陷阱
print("\n问题3:整数除法的结果")
arr = np.array([1, 2, 3, 4])
result = arr / 2 # 即使原数组是整数,结果也是浮点数
print(f"整数数组除以2:{result}, 类型:{result.dtype}")

13. 学习资源