【人工智能】(二)人工智能应用入门: NumPy详解人工智能的第一块基石
文章目录
前言
在人工智能飞速发展的今天,数据早已成为驱动算法的“燃料”。不论是训练一个图像识别模型、构建一个预测系统,还是进行大规模数据分析,背后都离不开高效的数值计算能力。这也是为什么我们在学习人工智能的过程中,总是会从 NumPy 开始。
NumPy(Numerical Python)是 Python 最基础也是最重要的科学计算库之一。它提供了一个强大且灵活的多维数组对象 ndarray,并支持向量化运算、广播机制、线性代数、随机数生成等丰富功能,这些正是现代人工智能算法的计算核心所在。
虽然在实际项目中我们可能会使用更高级的框架如 TensorFlow、PyTorch 等进行 AI 开发,但这些框架的底层实现几乎都与 NumPy 拥有类似的张量运算逻辑。可以说,理解 NumPy,不仅能够打牢数值计算的基础,也能为日后学习深度学习和机器学习模型打下坚实的地基。
本篇文章将作为《人工智能应用系列博文》的第一篇,带你系统了解 NumPy 的核心概念、常用操作、统计分析能力及其在 AI 中的典型应用场景。无论你是数据科学初学者,还是人工智能方向的在读研究生,相信这篇文章都能帮你从数据处理的第一步走得更稳、更扎实。
第 1 章:什么是numpy?
NumPy(Numerical Python 的缩写)是 Python 语言中用于数值计算的核心库之一,专为处理大型多维数组与矩阵数据而设计,并提供了丰富的数学函数库来执行各种数组运算。
如果你正在学习数据分析、机器学习或人工智能,NumPy 是你必须掌握的第一块积木。它的高性能数组对象 ndarray 提供了一个统一、高效的数据结构,可以替代 Python 原生的列表进行更快、更简洁的计算。
NumPy 的核心功能包括:
多维数组对象 ndarray:支持任意维度、任意数据类型的高效数组存储。
广播机制:可在不同形状的数组之间执行数学运算。
向量化操作:用数组代替显式循环,提升运算速度和简洁度。
线性代数、傅里叶变换、统计、随机数等数学函数库。
与 Python 生态的完美配合(如 Pandas、Matplotlib、Scikit-learn、TensorFlow 等)。
第 2 章:NumPy 基础入门
2.1 数组的创建与属性
(1)创建数组
NumPy 中最核心的数据结构是 ndarray,可以通过多种方式创建数组:
- np.array() 函数说明
numpy.array(object, dtype=None, copy=True, order=‘K’, subok=False, ndmin=0)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
object | array-like | 必填 | 输入数据,可以是列表、元组、嵌套列表、其他数组对象等 |
dtype | 数据类型 | None | 指定数组中元素的数据类型,如 np.int32, np.float64, 'i2', 'f4' |
copy | bool | True | 是否复制对象数据,若为 False 且输入已是 ndarray,可能直接返回原对象 |
order | 'K'/'C'/'F' | 'K' | 内存布局:C 表示行优先(默认),F 表示列优先,K 表示与原对象一致 |
subok | bool | False | 若为 True,返回子类数组;False 时返回 base ndarray |
ndmin | int | 0 | 指定返回数组的最小维度数,常用于添加维度 |
- np.zeros() 函数说明
创建一个指定形状、指定数据类型的数组,数组中的所有元素都初始化为 0。
numpy.zeros(shape, dtype=float, order=‘C’)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
shape | int 或 tuple of int | 必填 | 指定数组的形状,例如 3 表示一维长度为 3,(2, 3) 表示 2 行 3 列 |
dtype | 数据类型 | float | 数组中元素的数据类型,如 np.int32、np.float64 等 |
order | 'C' 或 'F' | 'C' | 数组的内存布局:'C' 表示按行存储(C风格),'F' 表示按列存储(Fortran风格) |
- np.ones() 函数说明
创建一个指定形状的数组,所有元素初始化为 1。
numpy.ones(shape, dtype=None, order=‘C’)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
shape | int 或 tuple of int | 必填 | 指定数组形状,例如 3 表示长度为 3 的一维数组,(2, 3) 表示 2 行 3 列 |
dtype | 数据类型 | None | 元素数据类型,如 np.int32、np.float64 等,默认推断为 float64 |
order | 'C' 或 'F' | 'C' | 数组内存布局:'C' 为行优先,'F' 为列优先 |
- np.arange() 函数说明
生成一个从 start 到 stop(不包含)的等差数列数组。
numpy.arange([start,] stop[, step], dtype=None)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
start | 数值 | 0 | 起始值,默认从 0 开始 |
stop | 数值 | 必填 | 结束值(不包含) |
step | 数值 | 1 | 步长,指定数值之间的间隔 |
dtype | 数据类型 | None | 输出数组元素的数据类型,默认自动推断 |
- np.arange() 函数说明
生成一个从 start 到 stop(不包含)的等差数列数组。
numpy.arange([start,] stop[, step], dtype=None)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
start | 数值 | 0 | 起始值,默认从 0 开始 |
stop | 数值 | 必填 | 结束值(不包含) |
step | 数值 | 1 | 步长,指定数值之间的间隔 |
dtype | 数据类型 | None | 输出数组元素的数据类型,默认自动推断 |
- np.linspace() 函数说明
在线性区间 [start, stop] 上生成 num 个均匀间隔的数值数组。
numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
start | 数值 | 必填 | 起始值 |
stop | 数值 | 必填 | 结束值 |
num | int | 50 | 要生成的样本数量 |
endpoint | bool | True | 是否包含终点值 stop |
retstep | bool | False | 若为 True,返回间隔值 step 与数组 |
dtype | 数据类型 | None | 输出数组数据类型,默认自动推断 |
axis | int | 0 | 放置样本的轴(适用于多维数组生成) |
示例
import numpy as np
# 从列表创建数组
a = np.array([1, 2, 3])
# 创建全 0 数组
b = np.zeros((2, 3))
# 创建全 1 数组
c = np.ones((3, 3))
# 创建等差数组
d = np.arange(0, 10, 2) # [0 2 4 6 8]
# 创建等间隔数值
e = np.linspace(0, 1, 5) # [0. 0.25 0.5 0.75 1. ]
# 创建随机数组
f = np.random.rand(2, 2)
你可以根据需求选择不同的方式生成初始化数据,尤其在神经网络初始化权重时经常用到 np.random 系列函数。
我们可以使用jupyter notebook按步进行学习

(2)查看数组属性
NumPy 数组对象拥有多个属性,帮助我们理解数据结构和维度信息:
arr = np.array([[1, 2, 3], [4, 5, 6]])
print("数组维度数 ndim:", arr.ndim) # 2
print("数组形状 shape:", arr.shape) # (2, 3)
print("数组元素总数 size:", arr.size) # 6
print("数组数据类型 dtype:", arr.dtype) # int64
print("每个元素字节数 itemsize:", arr.itemsize) # 8

| 属性 | 含义 |
|---|---|
ndim | 数组的维度数 |
shape | 数组的形状(各轴大小) |
size | 元素总数 |
dtype | 每个元素的数据类型 |
itemsize | 单个元素占用的字节数 |
这些属性对于调试维度不匹配问题、进行广播运算和矩阵变换非常有用。
2.2 数据类型与类型转换
(1)数据类型
| 类型 | 描述 | 示例代码 | 简写 |
|---|---|---|---|
| bool_ | 布尔类型(True 或 False) | np.bool_ | ? |
| int8 | 8 位有符号整数(-128 到 127) | np.int8 | i1 |
| int16 | 16 位有符号整数 | np.int16 | i2 |
| int32 | 32 位有符号整数 | np.int32 | i4 |
| int64 | 64 位有符号整数 | np.int64 | i8 |
| uint8 | 8 位无符号整数(0 到 255) | np.uint8 | u1 |
| uint16 | 16 位无符号整数 | np.uint16 | u2 |
| uint32 | 32 位无符号整数 | np.uint32 | u4 |
| uint64 | 64 位无符号整数 | np.uint64 | u8 |
| float16 | 16 位浮点数(半精度) | np.float16 | f2 |
| float32 | 32 位浮点数(单精度) | np.float32 | f4 |
| float64 | 64 位浮点数(双精度,默认) | np.float64 | f8 |
| complex64 | 复数(两个 float32) | np.complex64 | c8 |
| complex128 | 复数(两个 float64) | np.complex128 | c16 |
| str_ | Unicode 字符串(定长) | np.str_ | U + 字符长度 |
| bytes_ | 字节串(定长) | np.bytes_ | S + 字节长度 |
| object_ | 任意 Python 对象(性能较低) | np.object_ | O |
(2)数据类型的操作
- 指定创建数组数据类型
a = np.array([1,0,1,0],dtype=np.bool) #或者使用dtype='?'
print(a)
print("数组数据类型 dtype:", a.dtype)

- 修改数组数据类型
ndarray.astype() 函数说明
a.astype() 是 NumPy 中用于将数组 a 的元素转换为指定数据类型的方法。它会返回一个新的数组,原始数组不会被修改。这是处理模型输入、内存压缩、图像处理、类型安全等场景中非常常用的方法。
new_array = a.astype(dtype, order=‘K’, casting=‘unsafe’, subok=True, copy=True)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
dtype | str 或类型 | 必填 | 要转换成的目标数据类型,如 'int32', np.float64, 'f2', 'u1' 等 |
order | 'C', 'F', 'A', 'K' | 'K' | 内存布局:C 表示行优先,F 表示列优先,K 表示尽量保持原布局 |
casting | 'no', 'equiv', 'safe', 'same_kind', 'unsafe' | 'unsafe' | 控制是否允许不同类型间的强制转换 |
subok | bool | True | 是否允许子类返回,True 则保留原始子类 |
copy | bool | True | 是否始终返回新数组(即使类型相同) |
a.astype("i1") #或者使用a.astype(np.int8)
print(a)
print("数组数据类型 dtype:", a.dtype)

注意:我们可以发现数据类型并没有被更改掉,这是 NumPy 中非常重要的一个行为特性:astype() 不会修改原数组,而是返回一个新数组
也就是说:
a_int = a.astype("i1")
print(a_int)
print("数组数据类型 dtype:", a_int.dtype)
返回的是新的 int8 类型数组,原数组 a 的类型保持不变。

- 修改浮点数的小数位数
np.round() 函数说明
np.round() 用于对数组中的每个元素进行四舍五入操作。你可以指定保留的小数位数(默认为整数),常用于模型预测结果处理、数值展示、数据归一化后的格式化输出等场景。
numpy.round(a, decimals=0, out=None)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
a | array-like | 必需 | 输入数组或数值,支持 Python 数、列表、ndarray 等 |
decimals | int | 0 | 保留的小数位数。正数表示保留的小数位,负数表示四舍五入到十位、百位等 |
out | ndarray | None | 可选输出数组,用于存放结果,节省内存 |
arr = np.random.rand(2, 5)
print(arr)
arr = np.round(arr,2)
print(arr)

2.3 数组形状操作
(1) 查看数组情况
arr = np.array([[3,4,5,6,7,8],[4,5,6,7,8,9]])
print("数组形状 shape:", arr.shape)

(2) 修改数组形状
| 函数名 | 作用 | 是否修改原数组 | 是否返回新数组 | 支持维度自动推导 -1 | 报错条件 |
|---|---|---|---|---|---|
reshape() | 返回一个新形状的数组,不改变原数组 | ❌ 否 | ✅ 是 | ✅ 支持 | 元素数量不匹配时报错 |
resize() | 直接修改原数组形状 | ✅ 是 | ❌ 否(原地操作) | ❌ 不支持 | 元素不足会补零,过多则截断 |
a = np.array([1, 2, 3, 4, 5, 6])
# reshape
b = a.reshape((2, 3))
# b: [[1 2 3]
# [4 5 6]]
# resize
a.resize((3, 2))
# a: [[1 2]
# [3 4]
# [5 6]]
(3) 数组扁平化
| 函数名 | 作用 | 是否复制数据 | 是否修改原数组 | 返回值类型 |
|---|---|---|---|---|
flatten() | 返回复制后的扁平数组 | ✅ 是 | ❌ 否 | 一维 ndarray |
ravel() | 返回视图或复制(尽量视图) | ❌ 视图优先 | ❌ 否 | 一维 ndarray |
a = np.array([[1, 2], [3, 4]])
# flatten
b = a.flatten()
b[0] = 100
# a 不变
# ravel
c = a.ravel()
c[0] = 200
# a 被修改
(4) 维度扩展与压缩
| 函数名 | 作用 | 说明 |
|---|---|---|
expand_dims() | 在指定位置插入新轴(增加维度) | 可用于从 (3,) 变为 (1, 3) 或 (3, 1) 等 |
squeeze() | 移除数组中维度为 1 的维度 | 常用于去除多余维度,如从 (1, 3, 1) 变为 (3,) |
a = np.array([1, 2, 3])
# expand_dims
b = np.expand_dims(a, axis=0) # shape: (1, 3)
c = np.expand_dims(a, axis=1) # shape: (3, 1)
# squeeze
d = np.array([[[1], [2], [3]]]) # shape: (1, 3, 1)
e = np.squeeze(d) # shape: (3,)
第 3 章:数组运算与广播机制
3.1 数组运算
(1) 加法减法
NumPy 支持数组与数值(标量)之间的逐元素运算:
import numpy as np
arr = np.array([1, 2, 3])
print(arr + 5) # [6 7 8]
print(arr - 1) # [0 1 2]
说明:每个元素都执行相同的加减操作。
(2) 乘法除法
arr = np.array([2, 4, 6])
print(arr * 2) # [ 4 8 12]
print(arr / 2) # [1. 2. 3.]
说明:输出结果中如果涉及除法,NumPy 会自动转换为 float 类型。
(3) 数组和数组的加减法
数组之间可以直接进行逐元素的加减运算(要求形状一致或可广播):
a = np.array([1, 2, 3])
b = np.array([10, 20, 30])
print(a + b) # [11 22 33]
print(b - a) # [9 18 27]
(4) 数组和数组的乘除法
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(a * b) # [4 10 18] ← 逐元素乘法(不是矩阵乘法)
print(b / a) # [4.0 2.5 2.0]
注意:这不是矩阵乘法,是逐元素乘法,称为 element-wise operation。
如果你想进行矩阵乘法,请使用:
np.dot(a, b) # 向量点积
a @ b # Python 3.5+ 支持的矩阵乘号
(5) 不同维度的数组计算(广播机制)
NumPy 的 广播(broadcasting)机制 允许不同形状的数组自动对齐进行运算。
广播原则:如果两个数组的后缘维度(trailing dimension,即从末尾开始算起的维度)的轴长度相符或其中一方的长度为1,则认为它们是广播兼容的。广播会在缺失和长度为1的维度上进行。
广播规则总结:
- 如果两个数组的维度数不同,较小维度的数组会在最左边自动补 1。
- 若某个维度不匹配但其中一个是 1,可以广播。
- 否则报错:ValueError: operands could not be broadcast together
| 类型 | 操作 | 示例 |
|---|---|---|
| 数组 + 标量 | 加/减 | a + 1, a * 10 |
| 数组 + 数组(形状一致) | 加/减/乘/除 | a + b, a * b |
| 数组 + 数组(可广播) | 自动扩展 | A + b(维度不同时广播) |
| 向量点积 | 点积 | np.dot(a, b) 或 a @ b |
| 矩阵乘法 | 多维乘法 | A @ B 或 np.matmul(A, B) |
示例 1:1D 和 2D 相加
A = np.array([[1, 2, 3],
[4, 5, 6]])
B = np.array([10, 20, 30])
print(A + B)
# 输出:
# [[11 22 33]
# [14 25 36]]
示例 2:列向量与矩阵相加
A = np.array([[1, 2, 3],
[4, 5, 6]])
B = np.array([[10],
[20]])
print(A + B)
# 输出:
# [[11 12 13]
# [24 25 26]]
3.2 关于轴(axis)的补充说明
在 NumPy 中,axis 表示 沿着哪个维度进行操作。
axis=0:沿着第 0 维(即跨行),操作的是列
axis=1:沿着第 1 维(即跨列),操作的是行
axis=2:在 3D 数组中,表示跨页(最里层元素)
| 维度 | 数组形状 | 可选 axis 值 | 含义简述 |
|---|---|---|---|
| 1D 向量 | (n,) | 0 | 对整个向量进行操作 |
| 2D 矩阵 | (m, n) | 0 或 1 | 0:跨行(列间聚合) 1:跨列(行间聚合) |
| 3D 张量 | (a, b, c) | 0 / 1 / 2 | 0:跨块;1:跨行;2:跨列 |
-
二维数组的轴

-
三维数组的轴

3.3 条件逻辑处理
| 方法 | 作用 | 用法示例 |
|---|---|---|
np.where() | 条件选择(类似三元运算) | np.where(x > 0, x, 0) |
clip() | 限制最小最大值 | np.clip(data, min_value, max_value) |
(1)np.where() — 三元选择(条件表达式)
numpy.where(condition, x, y)
相当于:x if condition else y(逐元素判断)
| 参数 | 说明 |
|---|---|
condition | 条件数组,结果为 True 的位置将选取 x 的值 |
x | 满足条件的位置所采用的值 |
y | 不满足条件的位置所采用的值 |
import numpy as np
a = np.array([10, 20, 30, 40])
b = np.array([1, 2, 3, 4])
# 如果 a > 25,则取 a,否则取 b
result = np.where(a > 25, a, b)
print(result)
# 输出: [ 1 2 30 40]
也可以只传 condition,返回满足条件的元素索引:
indices = np.where(a > 25)
print(indices)
# 输出: (array([2, 3]),)
(2)clip() — 限制数值范围
numpy.clip(array, min, max)
将数组中所有小于min的值变为min,大于max的变为max,中间值保持不变。
用途:
- 限制数据范围(如图像灰度值限制在 0~255)
- 防止异常值干扰分析
a = np.array([1, 5, 10, 15, 20])
# 将所有值限制在 [5, 15] 之间
clipped = np.clip(a, 5, 15)
print(clipped)
# 输出: [ 5 5 10 15 15]
第 4 章:数组索引与切片技巧
在人工智能项目中,我们经常需要对数组中的部分数据进行访问、修改、筛选。NumPy 提供了强大而灵活的索引与切片机制,使得对多维数组的操作变得简洁高效。
4.1 基本索引与切片
(1) 基本索引
类似 Python 的列表语法,NumPy 支持:
- 使用索引访问单个元素
- 使用冒号 : 对数组进行切片
- 支持多维数组的索引
| 表达式 | 含义 | 示例输出 |
|---|---|---|
a[i] | 第 i 行 | [5 6 7 8] |
a[:, j] | 第 j 列 | [3 7 11] |
a[i:j] | 第 i 到第 j-1 行 | [[5 6 7 8], [9 10 11 12]] |
a[:, j:k] | 所有行的第 j 到第 k-1 列 | [[3 4], [7 8], [11 12]] |
a = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]])
print(a[1]) #取一行
print(a[:,2]) #取一列
print(a[1:3]) #取多行
print(a[:,2:4]) #取多行

(2) 切片(Slicing)
array[start:stop:step]
- start:起始索引(包含)
- stop:终止索引(不包含)
- step:步长(可选)
arr = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]
print(arr[2:7]) # [2 3 4 5 6]
print(arr[::2]) # [0 2 4 6 8]
print(arr[::-1]) # [9 8 7 6 5 4 3 2 1 0] → 反转
(3) 二维数组切片
可以同时对行、列进行切片。
a = np.array([[11, 12, 13],
[21, 22, 23],
[31, 32, 33]])
print(a[0:2, 1:3])
说明:
- 取第 0~1 行、第 1~2 列
- 行是前两个,列是最后两列
4.2 高级索引
(1) 布尔索引(Boolean Indexing)
a = np.array([10, 20, 30, 40, 50])
mask = a > 25
print(mask) # [False False True True True]
print(a[mask]) # [30 40 50]
#也可简写成
print(a[a > 25]) # [30 40 50]
(2) 花式索引(Fancy Indexing)
使用整数列表或数组作为索引来访问多个非连续元素。
a = np.array([10, 20, 30, 40, 50])
idx = [1, 3, 4]
print(a[idx]) # [20 40 50]
二维数组也支持:
b = np.array([[1, 2], [3, 4], [5, 6]])
rows = [0, 2]
cols = [1, 0]
print(b[rows, cols]) # [2, 5]
4.3 注意事项
(1) 修改切片视图 vs 复制
切片得到的是视图(View),修改切片会影响原数组!
a = np.arange(6)
b = a[2:5]
b[0] = 99
print(a) # [0 1 99 3 4 5]
如果希望独立修改,需要用.copy():
b = a[2:5].copy()
(2) 多维数组取整列 / 整行
a = np.array([[10, 20, 30],
[40, 50, 60]])
print(a[:, 0]) # 所有行的第 0 列 → [10 40]
print(a[1, :]) # 第 1 行的所有列 → [40 50 60]
小结
| 类型 | 说明 | 示例 |
|---|---|---|
| 基本索引 | 单个元素访问 | a[1, 2] |
| 切片 | 连续子集访问 | a[1:3, 0:2] |
| 步长切片 | 跳跃取值或反转 | a[::-1] |
| 布尔索引 | 通过条件表达式筛选 | a[a > 10] |
| 花式索引 | 通过索引数组访问非连续元素 | a[[1, 3, 5]] |
| 切片是视图 | 修改切片会影响原数组 | a[2:4] = ... |
第 5 章:数组结构操作进阶
5.1 转置与轴交换
(1)转置的基本概念
转置是指交换数组的轴(维度),对于numpy中的数组来说,就是在对角线方向交换数据,最常见的是 二维数组的行列互换:如果有一个形状为 (m, n) 的数组,转置后变成 (n, m)。
(2) .T 属性:快速二维转置
import numpy as np
a = np.array([[1, 2],
[3, 4],
[5, 6]])
print("原数组形状:", a.shape) # (3, 2)
print("转置后形状:", a.T.shape) # (2, 3)
print(a.T)

(3) np.transpose() 函数:通用多维转置
numpy.transpose() 是用于 交换数组的维度顺序(轴) 的函数。它适用于任意维度的数组,能够实现灵活的张量转置操作,是多维数组处理和深度学习数据预处理的重要工具。
numpy.transpose(a, axes=None)
参数说明:
- a:输入数组(可以是 1D、2D、3D 或更高维)
- axes:指定新的维度顺序,是一个元组或列表(默认是反转所有轴)
a = np.array([[1, 2], [3, 4], [5, 6]])
print(np.transpose(a)) # 或 a.T

(4) .swapaxes()
numpy.swapaxes()用于 交换数组中的两个轴(维度)。它是 np.transpose() 的简化形式,专门用于仅交换两个轴,而不是对所有轴重新排序。
np.swapaxes(a, axis1, axis2)
a.swapaxes(axis1, axis2)
参数说明:
- a:输入的数组
- axis1、axis2:要交换的两个轴的编号(从 0 开始)
a = np.array([[1, 2], [3, 4], [5, 6]])
print(a.swapaxes(1, 0)) # 或 a.T

(5) 二维 vs 多维数组转置差异总结
| 操作 | 适用于 | 功能 |
|---|---|---|
.T | 2D、3D 等 | 默认反转所有轴(例如 2D 行列互换) |
np.transpose() | 任意维度数组 | 显式指定维度顺序 |
np.swapaxes() | 任意维度数组 | 仅交换指定的两个轴 |
(6) 常见使用场景
| 应用场景 | 示例 |
|---|---|
| 矩阵行列转置 | a.T |
| 图像维度转换(HWC → CHW) | np.transpose(img, (2, 0, 1)) |
| 批量数据转置 | (batch_size, time_steps, features) → (time_steps, batch_size, features) |
| RNN 数据准备 | PyTorch 中常将输入维度调换以适配模型 |
5.2 数组合并与分割
(1)np.concatenate()
沿指定轴拼接数组
np.concatenate((a1, a2, …), axis=0)
| 参数 | 说明 |
|---|---|
a1, a2 | 需要拼接的数组序列,形状需匹配(除了拼接轴) |
axis | 沿哪个轴拼接,默认是 0 |
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
result = np.concatenate((a, b), axis=0)
print(result)
# 输出:
# [[1 2]
# [3 4]
# [5 6]]
(2)np.stack()
沿新轴堆叠数组
np.stack((a1, a2, …), axis=0)
| 参数 | 说明 |
|---|---|
a1, a2 | 数组形状必须完全一致 |
axis | 堆叠时创建的新轴位置 |
与concatenate不同的是,stack增加一个新维度。
a = np.array([1, 2])
b = np.array([3, 4])
result = np.stack((a, b), axis=0)
print(result)
# 输出:
# [[1 2]
# [3 4]]
result = np.stack((a, b), axis=1)
print(result)
# 输出:
# [[1 3]
# [2 4]]
(3)np.split()
将数组拆分成多个子数组
np.split(array, indices_or_sections, axis=0)
| 参数 | 说明 |
|---|---|
array | 被拆分的数组 |
indices_or_sections | 拆分方式,可以是整数或索引列表 |
axis | 沿哪个轴进行拆分 |
- 如果是整数
n,则平均分成n份(必须能整除) - 如果是列表
[i1, i2],则在指定索引处分段
示例:整数拆分
#你这段代码的作用是将二维数组 a 沿 行方向(axis=0) 平均分成 2 个子数组。
a = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
parts = np.split(a, 2, axis=0)
for p in parts:
print(p)
输出:
[[1 2]
[3 4]]
[[5 6]
[7 8]]
示例:索引拆分
#分割点索引 [2, 4] 表示:
#第一个子数组:a[0:2] = [1, 2]
#第二个子数组:a[2:4] = [3, 4]
#第三个子数组:a[4:] = [5, 6]
a = np.array([1, 2, 3, 4, 5, 6])
parts = np.split(a, [2, 4])
print(parts) # 输出: [array([1, 2]), array([3, 4]), array([5, 6])]
总结
| 函数名 | 功能 | 是否增加维度 | 备注说明 |
|---|---|---|---|
concatenate | 沿已有轴拼接 | 否 | 维度不变,拼接前维度需兼容 |
stack | 沿新轴堆叠 | 是 | 会新增一个维度 |
split | 沿指定轴拆分 | 否 | 平均拆分或在索引处分段 |
5.3 排序
(1)np.sort()
排序(返回排序后的数组)
np.sort(a, axis=-1)
| 参数 | 说明 |
|---|---|
a | 要排序的数组 |
axis | 指定排序的轴,默认按行排序(最后一维) |
示例:
a = np.array([[3, 1, 2], [6, 4, 5]])
sorted_a = np.sort(a, axis=1)
print(sorted_a)
输出:
[[1 2 3]
[4 5 6]]
(2)np.argsort()
返回排序后元素的索引
np.argsort(a, axis=-1)
返回的是排序后元素在原数组中的索引位置,常用于间接排序或提取 top-N 元素。
示例:
a = np.array([3, 1, 2])
index = np.argsort(a)
print(index) # [1 2 0]
print(a[index]) # [1 2 3]
二维数组示例:
a = np.array([[8, 2, 3], [4, 7, 6]])
idx = np.argsort(a, axis=1)
print(idx)
输出:
[[1 2 0]
[0 2 1]]
总结
| 方法 | 功能 | 结果类型 | 说明 |
|---|---|---|---|
.T / transpose() | 行列互换 | 数组 | 维度调换 |
sort() | 排序(返回排序后值) | 排序后的新数组 | 不改变原数组(除非指定 in-place) |
argsort() | 排序(返回索引) | 排序后索引数组 | 可用于间接排序 |
第 6 章:常用统计分析函数
6.1 均值、中位数、标准差、方差
| 函数 | 功能 | 示例 |
|---|---|---|
np.mean() | 求平均值 | np.mean(a) |
np.median() | 求中位数 | np.median(a) |
np.std() | 求标准差 | np.std(a) |
np.var() | 求方差 | np.var(a) |
可使用axis参数指定按行或按列:
import numpy as np
# 一维数组
a = np.array([1, 2, 3, 4, 5, 6])
print("一维数组:", a)
print("均值 mean:", np.mean(a)) # 输出: 3.5
print("中位数 median:", np.median(a)) # 输出: 3.5
print("标准差 std:", np.std(a)) # 输出: 1.707...
print("方差 var:", np.var(a)) # 输出: 2.916...
6.2 最大最小值与对应索引
| 函数 | 功能 |
|---|---|
np.max() | 最大值 |
np.min() | 最小值 |
np.argmax() | 最大值对应索引 |
np.argmin() | 最小值对应索引 |
a = np.array([1, 7, 3, 9, 5])
print(np.max(a)) # 9
print(np.argmax(a)) # 3(索引为 3 的位置是最大值 9)
print(np.min(a)) # 1
print(np.argmin(a)) # 0
二维数组可以加axis参数:
a = np.array([[1, 3, 2], [6, 5, 4]])
print(np.argmax(a, axis=1)) # 每行最大值的索引:[1 0]
6.3 缺失值处理技巧(NaN)
当数组中包含np.nan时,普通统计函数如np.mean()会返回nan,这时需要使用带nan前缀的函数进行处理。
| 函数 | 功能 |
|---|---|
np.nanmean() | 忽略 NaN 求均值 |
np.nanstd() | 忽略 NaN 求标准差 |
np.nanvar() | 忽略 NaN 求方差 |
np.nanmin() | 忽略 NaN 求最小值 |
np.nanmax() | 忽略 NaN 求最大值 |
示例:
import numpy as np
# 创建包含 NaN 的数组
a = np.array([1, 2, np.nan, 4, 5])
print("原始数组:", a)
mean_val = np.nanmean(a)
print("忽略 NaN 的均值:", mean_val) #
std_val = np.nanstd(a)
print("忽略 NaN 的标准差:", std_val)
var_val = np.nanvar(a)
print("忽略 NaN 的方差:", var_val)
min_val = np.nanmin(a)
print("忽略 NaN 的最小值:", min_val)
max_val = np.nanmax(a)
print("忽略 NaN 的最大值:", max_val)
结果:
原始数组: [ 1. 2. nan 4. 5.]
忽略 NaN 的均值: 3.0
忽略 NaN 的标准差: 1.5811388300841898
忽略 NaN 的方差: 2.5
忽略 NaN 的最小值: 1.0
忽略 NaN 的最大值: 5.0
判断和处理缺失值:
np.isnan(a) # 返回布尔数组:标识哪些是 NaN
a[np.isnan(a)] = 0 # 将 NaN 替换为 0
6.4 总结
| 功能 | 标准函数 | 忽略 NaN 函数 |
|---|---|---|
| 均值 | np.mean() | np.nanmean() |
| 中位数 | np.median() | np.nanmedian() |
| 标准差 | np.std() | np.nanstd() |
| 方差 | np.var() | np.nanvar() |
| 最大值 | np.max() | np.nanmax() |
| 最小值 | np.min() | np.nanmin() |
第 7 章:随机数与概率分布
7.1 基础随机数函数
| 函数 | 说明 | 示例结果 |
|---|---|---|
np.random.rand(d0, d1, ...) | 生成 [0, 1) 范围内的均匀分布随机数 | np.random.rand(2,3) |
np.random.randint(low, high, size) | 生成指定整数范围的随机整数 | np.random.randint(1, 10, size=5) |
np.random.choice(a, size) | 从一维数组中随机选取元素(可重复/不重复) | np.random.choice([1,2,3], 5) |
示例:
import numpy as np
print("rand:", np.random.rand(2, 3)) # 生成 2x3 的[0,1)均匀分布随机数
print("randint:", np.random.randint(5, 10, size=4)) # 生成4个[5,10)间整数
print("choice:", np.random.choice([10, 20, 30], size=5)) # 从数组中随机选
7.2 常见概率分布
(1)正态分布(高斯分布)
正态分布,也称为高斯分布,是一种连续概率分布,广泛用于自然科学、工程、金融建模等领域。其概率密度函数(PDF)为:

| 符号 | 含义 |
|---|---|
| μ \mu μ | 均值(位置中心) |
| σ \sigma σ | 标准差(控制分布的宽度) |
| σ 2 \sigma^2 σ2 | 方差 |

np.random.normal(loc=0.0, scale=1.0, size=None)
| 参数 | 说明 |
|---|---|
loc | 均值 μ |
scale | 标准差 σ |
size | 输出样本形状 |
samples = np.random.normal(loc=0, scale=1, size=1000)
(2)均匀分布(Uniform Distribution)
均匀分布是最简单、最基本的一种概率分布。它描述了在一定范围内,各个数值出现的概率相等。

np.random.uniform(low=0.0, high=1.0, size=None)
- 生成 [low, high) 区间内的随机样本
samples = np.random.uniform(5, 10, size=5)
print(samples)
(3)泊松分布(Poisson Distribution)

假设某事件在单位时间(或单位空间)内平均发生次数为𝜆>0,则事件在该单位时间内恰好发生𝑘次的概率为:

- 𝜆是事件的平均发生率(均值)
- 𝑘是事件发生的具体次数(非负整数)
np.random.poisson(lam=λ, size=None)
- 模拟事件在单位时间/空间内发生的次数(如服务器访问、电话呼叫)
samples = np.random.poisson(lam=5, size=10)
print(samples)
(4)其他分布(了解)
| 分布类型 | 函数 | 应用场景举例 |
|---|---|---|
| 二项分布 | np.random.binomial(n, p, size) | 抛硬币 n 次成功次数 |
| 指数分布 | np.random.exponential(scale, size) | 模拟等待时间 |
| β 分布 | np.random.beta(a, b, size) | 概率分布建模(贝叶斯) |
| γ 分布 | np.random.gamma(shape, scale, size) | 服务时间建模 |
总结
| 函数类型 | 函数名 | 描述 |
|---|---|---|
| 均匀分布 | rand(), uniform() | 均匀分布 |
| 正态分布 | normal() | 高斯分布 |
| 整数随机 | randint() | 指定范围内的整数 |
| 随机采样 | choice() | 从数组中随机采样 |
| 泊松分布 | poisson() | 模拟单位时间的事件次数 |
| 二项分布 | binomial() | 成功/失败型实验(伯努利试验) |
| 指数分布 | exponential() | 模拟等待时间 |
第 8 章:数据读写操作
在实际人工智能项目或数据分析工作中,最常见的操作之一就是从本地磁盘或网络加载数据。NumPy 提供了多种读取文本、CSV、二进制等格式的函数,使用方便、高效。
8.1 NumPy 支持的常见数据格式
(1)文本文件(Text)
特点:
- 数据以纯文本形式存储
- 可以用 空格、逗号、**制表符(Tab)**等作为分隔符
- 常见扩展名:.txt、.dat
优点:
- 易于查看、编辑、跨平台
- 可用 Excel、记事本等工具打开
缺点:
- 文件体积较大
- 加载速度慢于二进制格式
- 只能表示简单数值,不支持复杂结构
NumPy 函数:
- np.loadtxt():用于读取标准格式的数值文本
- np.genfromtxt():更宽容,支持缺失值和混合数据
(2)CSV 文件(Comma-Separated Values)
特点:
- 逗号分隔的文本格式
- 常用于 Excel 导出、表格型数据
- 扩展名通常是 .csv
优点:
- 通用性强,是很多数据平台的导入导出标准格式
- 一行一条记录,结构清晰
- 方便与 pandas 配合使用(pd.read_csv())
缺点:
- 与文本文件类似,纯文本不支持高效随机访问
- 字符串数据或缺失值需要特别处理
NumPy 函数:
- 同样使用 np.loadtxt() 或 np.genfromtxt(),指定 delimiter=‘,’
(3)二进制文件(NumPy 自有格式)
.npy 与 .npz 格式:
这是NumPy 专属的高性能存储格式,推荐用于 AI 项目中的中间数据或模型缓存。
- .npy:用于保存单个数组
- .npz:用于保存多个数组(字典形式)
优点:
- 读取速度快,效率高(可用于大数据集)
- 保存数据结构完整(包括 dtype、shape)
- 可与 PyTorch、TensorFlow 等无缝集成
缺点:
- 只能被 NumPy 加载,不适合数据共享给其他语言
- 不可读性强(是二进制文件)
NumPy 函数:
- np.save() / np.savez()
- np.load():读取 .npy 或 .npz
| 格式 | 文件类型 | 可读性 | 压缩性 | 速度 | 跨平台通用性 | NumPy读取方式 |
|---|---|---|---|---|---|---|
.txt | 文本 | ✅ 高 | ❌ 无 | ❌ 慢 | ✅ | loadtxt() / genfromtxt() |
.csv | 文本(逗号) | ✅ 高 | ❌ 无 | ❌ 慢 | ✅ | loadtxt() / genfromtxt() |
.npy | 二进制 | ❌ 无 | ✅ 高 | ✅ 快 | ⛔ 仅限 Python | save() / load() |
.npz | 二进制(多数组) | ❌ 无 | ✅ 高 | ✅ 快 | ⛔ 仅限 Python | savez() / load() |
8.2 np.loadtxt() — 读取文本/CSV 文件
numpy.loadtxt() 是 NumPy 中用于从文本文件中快速读取纯数值数据的函数,适合读取 .txt、.csv 等结构简单、格式统一的文件。
适用于绝大多数AI 项目的数据预加载阶段,如图像特征、标签、向量等。
numpy.loadtxt(fname, dtype=float, delimiter=None, skiprows=0, usecols=None, encoding=‘bytes’)
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
fname | str 或文件对象 | 要读取的文件路径 |
dtype | 数据类型 | 默认 float,可设置为 int、str 等 |
delimiter | 字符串 | 指定列之间的分隔符,如 ',' 或 '\t' |
skiprows | 整数 | 跳过文件开头的几行(常用于跳过标题) |
usecols | 元组/列表 | 指定读取的列(索引从 0 开始) |
encoding | 字符串 | 文件编码,如 'utf-8'(推荐) |
import numpy as np
data = np.loadtxt('data.txt', delimiter=',')
print(data)
参数说明:
| 参数 | 含义 |
|---|---|
fname | 文件路径(字符串) |
delimiter | 分隔符,如,、\t、空格 |
dtype | 数据类型(默认 float) |
skiprows | 跳过前几行 |
usecols | 指定读取哪些列(索引) |
encoding | 字符编码(推荐 utf-8) |
示例:读取csv文件
data = np.loadtxt('iris.csv', delimiter=',', usecols=(0, 1), skiprows=1)
8.3 np.genfromtxt() — 更强大的读取器
numpy.genfromtxt() 是一个功能更强大的数据读取函数,专用于读取结构复杂的文本数据,包括:
- 含有缺失值的表格
- 混合数据类型(数值 + 字符串)
- 有列名/表头的 CSV 文件等
可看作是 np.loadtxt() 的增强版本,适合处理实际 AI 项目中非标准化的数据集。
numpy.genfromtxt(fname,
dtype=float,
delimiter=None,
names=False,
skip_header=0,
usecols=None,
missing_values=None,
filling_values=None,
encoding=‘bytes’)
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
fname | 字符串/文件对象 | 文件路径或打开的文件对象 |
dtype | 数据类型/结构化类型 | 数据类型(可为 float, str, 或复合类型) |
delimiter | 字符串 | 分隔符,如 ',' 或 '\t' |
names | 布尔/字符串列表 | 是否读取第一行为字段名,或手动指定字段名 |
skip_header | 整数 | 跳过的开头行数 |
usecols | 元组/列表 | 读取指定的列(列索引) |
missing_values | 字符/列表 | 表示缺失值的字符串,如 "NA"、"?" |
filling_values | 单个值/列表 | 用于替换缺失值的默认值 |
encoding | 字符串 | 文件编码,推荐 'utf-8' |
它比loadtxt()更宽容,可以处理缺失值、混合数据等情况。
data = np.genfromtxt('data.csv', delimiter=',', skip_header=1)
特点:
- 支持 missing_values 与 filling_values
- 自动跳过缺失或不规则格式行
- 可读取字符串列(配合 dtype=None)
8.4 np.load() — 读取 .npy 或 .npz 文件(二进制)
numpy.load() 是用于从磁盘读取 NumPy 的二进制文件格式(.npy 和 .npz)的函数。相比文本文件,它具有更高的读取速度和更好的结构信息保存能力,适合用于中间数据缓存、模型处理、AI 项目数据存储等场景。
numpy.load(file, mmap_mode=None, allow_pickle=False, fix_imports=True, encoding=‘ASCII’)
参数说明:
| 参数 | 说明 |
|---|---|
file | 文件路径或类文件对象 |
mmap_mode | 是否使用内存映射读取文件,可设为 'r' 只读 |
allow_pickle | 是否允许加载对象(如果使用了 pickle 存储) |
fix_imports | 是否兼容 Python 2 的导入路径(不常用) |
encoding | 加载 pickle 对象时的编码(通常设为 'utf-8') |
NumPy 专有的高效格式,适合保存大规模数组/模型中间结果:
# 保存数组
np.save('array.npy', my_array)
# 读取数组
arr = np.load('array.npy')
# 保存多个数组
np.savez('data.npz', a=arr1, b=arr2)
# 读取
data = np.load('data.npz')
print(data['a']) # 访问 a
8.5 读取路径说明(相对/绝对)
'data/data.csv':相对路径,当前项目目录下的 data 文件夹'C:/Users/xxx/Desktop/file.csv':绝对路径(Windows)r'C:\path\to\file.csv':使用 原始字符串 规避反斜杠转义问题
8.6 处理中文路径(Windows)
如果路径中含有中文,建议加上 encoding='utf-8':
data = np.loadtxt('数据文件.csv', delimiter=',', encoding='utf-8')
8.7 小结:常用数据读取函数对比
| 函数 | 功能描述 | 支持缺失值 | 可读字符串列 | 推荐用途 |
|---|---|---|---|---|
loadtxt() | 快速读取纯数字文本 | ❌ | ❌ | 整洁数值表格 |
genfromtxt() | 读取带缺失值或复杂结构的文本 | ✅ | ✅ | CSV、混合数据 |
load() | 读取 .npy / .npz 二进制文件 | ✅ | ❌ | 模型中间数据存取 |
第 9 章:实用技巧与性能建议
9.1 拷贝 vs 视图(复制 vs 引用)
在 NumPy 中,大部分操作默认返回视图(View)而非拷贝(Copy),这能提升性能,但容易出错。

示例:
import numpy as np
a = np.array([1, 2, 3])
b = a # 共享内存
c = a.copy() # 深拷贝
a[0] = 99
print("b:", b) # 输出 b: [99 2 3](和 a 同变)
print("c:", c) # 输出 c: [1 2 3](独立副本)
| 操作 | 是否拷贝 | 是否共享内存 |
|---|---|---|
a[1:3] | 否 | 是 |
a.copy() | 是 | 否 |
reshape() | 否 | 是(如果连续) |
np.array(a) | 是 | 否(强拷贝) |
9.2 避免 Python 循环:使用向量化计算(Vectorization)
NumPy 的最大优势之一是用向量化操作代替 for 循环,更快更简洁。
❌ 低效做法(for 循环):
a = np.arange(1000000)
b = np.zeros_like(a)
for i in range(len(a)):
b[i] = a[i] * 2
✅ 高效做法(向量化):
b = a * 2
结果相同,速度差别可达几十倍甚至上百倍!
9.3 性能测试工具
(1)%timeit:测时间
在IPython或Jupyter中可使用:
import numpy as np
a = np.arange(1000000)
%timeit a * 2
(2)memory_profiler:测内存
安装:
pip install memory_profiler
使用示例(在.py脚本中):
from memory_profiler import profile
@profile
def test():
a = [i**2 for i in range(1000000)]
return a
test()
运行脚本时:
python -m memory_profiler yourscript.py
| 技巧类别 | 建议 |
|---|---|
| 内存拷贝 | 用 .copy() 显式深拷贝 |
| 数组切片 | 默认视图,避免误修改原数组 |
| 性能优化 | 避免 for 循环,使用广播/向量化 |
| 评估工具 | %timeit 测时、memory_profiler 测内存 |
第 10 章:numpy与人工智能的关系
人工智能中的许多核心操作——如矩阵乘法、激活函数、梯度更新、权重初始化等——都离不开大规模的数组和矩阵运算。现代深度学习框架(如 TensorFlow 和 PyTorch)底层实现与 NumPy 十分接近,甚至在早期版本中直接使用了 NumPy 结构。所以,掌握 NumPy,不仅是写出高效 Python 程序的基础,更是深入理解 AI 框架背后原理的关键。
| NumPy 在 AI 中的作用 | 说明 |
|---|---|
| 数值计算基础 | 高效处理向量、矩阵,是 AI 的数学地基 |
| 深度学习框架兼容接口 | 几乎所有 AI 框架都支持或使用 NumPy |
| 数据预处理 | 从图像、文本到结构化数据,处理都依赖 NumPy |
| 教学和原型验证工具 | 许多 AI 教材和实验用纯 NumPy 写小模型验证 |
后续文章预告
下一篇:《【人工智能】(二)人工智能应用入门:从 Pandas 开始掌握数据分析》
更多推荐
所有评论(0)