品牌建设的阶段和步骤是什么seo网络推广有哪些
1 为什么要学习 NumPy?
当我们在做科学计算、数据分析或机器学习时,经常需要处理大量的数字、矩阵或高维数组。如果只用 Python 内置的列表 (list) 或循环来做,速度会非常慢、代码也繁琐。NumPy(Numerical Python)就像一个“高速电梯”,让你能够在 Python 中进行快速、向量化的数值运算,避免写太多的循环,还能方便地调用各种数学函数、线性代数运算等。
在实际应用中:
- 图像处理:图像可以看作是一个三维数组(高度、宽度、通道),通过 NumPy 可以轻松读取、修改像素值。
- 机器学习预处理:特征数据、模型权重往往是矩阵或多维张量,需要用 NumPy 高效地读写和运算。
- 科学研究:物理、化学、生物、地理等领域都有海量的数值数据和公式,对计算性能和精度要求高。
因此,NumPy 是整个 Python 科学计算生态的基石,理解和熟练使用它,能让你事半功倍。
2 NumPy 的 ndarray 基础
NumPy 提供了一个核心数据结构,叫做 ndarray(N-dimensional array,多维数组)。它和 Python 内置的列表有以下关键区别:
- 元素类型统一:一个 ndarray 中所有元素类型相同(如全是 float32、int64),利于高效内存管理和快速计算。
- 向量化运算:对整个数组进行加减乘除等操作时,可以自动在底层进行优化,远比用纯 Python 循环快得多。
2.1 创建数组的多种方法
常见的创建方式包括:
import numpy as np# 1. 直接从 Python 列表或元组创建
arr1 = np.array([1, 2, 3, 4])
print("arr1:", arr1)# 2. 创建指定形状的全0数组,全1数组
arr2 = np.zeros((2, 3))
arr3 = np.ones((3, 2))
print("arr2:\n", arr2)
print("arr3:\n", arr3)# 3. 创建等差序列
arr4 = np.arange(5, 15, 2) # 步长为2, 从5到14
arr5 = np.linspace(0, 1, 5) # 在[0,1]区间等间隔生成5个数
print("arr4:", arr4)
print("arr5:", arr5)
示例输出:
arr1: [1 2 3 4]
arr2:[[0. 0. 0.][0. 0. 0.]]
arr3:[[1. 1.][1. 1.][1. 1.]]
arr4: [ 5 7 9 11 13]
arr5: [0. 0.25 0.5 0.75 1. ]
2.2 数组的属性与操作
- .shape:返回数组的形状(行数、列数等)。
- .dtype:返回数组中元素的数据类型(如 float64、int32)。
- .ndim:返回数组的维度个数(几维数组)。
示例:构造一个 3×3 的单位矩阵,并打印其属性
在数学里,单位矩阵是指对角线全为1,其余为0 的方阵。NumPy 提供了 np.eye()
可以直接生成单位矩阵。也可以自己“手动”实现,这里用内置函数最方便。
import numpy as npI = np.eye(3) # 3x3 单位矩阵
print("单位矩阵 I:\n", I)
print("I 的形状:", I.shape)
print("I 的数据类型:", I.dtype)
print("I 的维度:", I.ndim)
运行后可见:
单位矩阵 I:[[1. 0. 0.][0. 1. 0.][0. 0. 1.]]
I 的形状: (3, 3)
I 的数据类型: float64
I 的维度: 2
3 索引与切片
在 NumPy 中对数组取值,有一些相似于 Python 列表的用法,但在多维场景下更丰富。
3.1 一维数组 vs. 多维数组的索引方式
- 一维数组:和 Python list 类似,用
[索引]
即可。 - 多维数组:常用
arr[行索引, 列索引]
、arr[i, j]
来表示。
3.2 切片语法 [start:stop:step]
在 NumPy 中,如果想取连续片段,就可以用 start:stop
。step
表示步长,不写则默认为1。
- 如果只写
arr[:3]
表示从头到索引2(含2,不含3)。 - 如果想跳着取,可以写
arr[::2]
(每隔1个取一个)。
示例:从数组中取出指定行列、子矩阵
先构造一个简单的 4×5 数组,里面是从 0 到 19 的数字,然后尝试不同的索引和切片。
import numpy as nparr = np.arange(20).reshape(4, 5)
print("原始数组:\n", arr)# 1. 取某个具体元素:第2行、第3列 (从0开始计)
elem_2_3 = arr[2, 3]
print("arr[2, 3] =", elem_2_3)# 2. 取一整行
row_1 = arr[1, :]
print("第1行:", row_1)# 3. 取一整列
col_2 = arr[:, 2]
print("第2列:", col_2)# 4. 取子矩阵:取第1~2行、第2~4列
# 注意:切片区间都是 [start, stop),左含右不含
sub_arr = arr[1:3, 2:5]
print("子矩阵(第1~2行, 第2~4列):\n", sub_arr)
输出:
原始数组:[[ 0 1 2 3 4][ 5 6 7 8 9][10 11 12 13 14][15 16 17 18 19]]arr[2, 3] = 13
第1行: [5 6 7 8 9]
第2列: [ 2 7 12 17]
子矩阵(第1~2行, 第2~4列):[[ 7 8 9][12 13 14]]
4 数组的运算与广播
4.1 基本数学运算
使用 NumPy,可以对数组直接进行加减乘除操作,也可以用内置的汇总函数对整个数组或按轴做统计。例如:
np.sum(arr)
或arr.sum()
:求和np.mean(arr)
:平均值np.max(arr)
:最大值np.min(arr)
:最小值np.std(arr)
:标准差
arr = np.array([[1, 2], [3, 4]])
print("arr:\n", arr)print("元素加1:\n", arr + 1)
print("元素相乘2:\n", arr * 2)
print("数组所有元素之和: ", arr.sum())
print("每列的最小值: ", arr.min(axis=0)) # axis=0 表示按“列”方向
示例输出:
arr:
[[1 2]
[3 4]]
元素加1:
[[2 3]
[4 5]]
元素相乘2:
[[2 4]
[6 8]]
数组所有元素之和: 10
每列的最小值: [1 2]
4.2 广播机制
NumPy 的广播机制允许不同形状(但维度兼容)的数组进行运算。它的核心思想是“自动扩张”较小的数组,以匹配较大的数组,然后逐元素计算。
- 例如,一个形状为
(m, n)
的二维数组,可以与形状为(n,)
的一维数组在列方向做运算; - 或者形状
(m, 1)
与(m, n)
等等。
示例:将一个 1D 数组加到一个 2D 矩阵的每一行/每一列
import numpy as npmat = np.array([[10, 20, 30],[40, 50, 60]
]) # 形状 (2, 3)row_add = np.array([1, 2, 3]) # 形状 (3,)
print("原始矩阵:\n", mat)
print("每行加 [1, 2, 3]:\n", mat + row_add)col_add = np.array([1, 10]) # 形状 (2,) ——> 广播成(2, 1)再与(2, 3)运算
print("每列加 [1, 10]:\n", mat + col_add.reshape(-1,1))
说明:
row_add
与mat
的第二维度同为 3,所以广播可以匹配到每一行。col_add
在原始形状是(2,)
,通过reshape(-1,1)
变成(2,1)
,再与(2,3)
做加法时,会把(2,1)
广播到(2,3)
。
示例输出:
原始矩阵:
[[10 20 30]
[40 50 60]]
每行加 [1, 2, 3]:
[[11 22 33]
[41 52 63]]
每列加 [1, 10]:
[[11 21 31]
[50 60 70]]
5 数组变形 (Reshape) 与拼接
5.1 reshape, ravel, flatten 的区别
- reshape(new_shape):返回一个“视图”(view),在不改变数据本身的前提下,按新形状解释数据。
- ravel():返回一个视图或一维迭代器(如果条件允许的话),不一定会新建内存;通常将多维数组“铺平”。
- flatten():返回一个拷贝(copy),一定会申请新的内存空间来存储新的数组。
arr = np.arange(12).reshape(3, 4)
print("原始 arr:\n", arr)# reshape
arr_reshape = arr.reshape(2, 6)
print("reshape(2, 6):\n", arr_reshape)# ravel
arr_ravel = arr.ravel()
print("ravel 后:\n", arr_ravel) # 一维迭代器# flatten
arr_flatten = arr.flatten()
print("flatten 后:\n", arr_flatten) # 一维数组的拷贝
示例输出:
原始 arr:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
reshape(2, 6):
[[ 0 1 2 3 4 5]
[ 6 7 8 9 10 11]]
ravel 后:
[ 0 1 2 3 4 5 6 7 8 9 10 11]
flatten 后:
[ 0 1 2 3 4 5 6 7 8 9 10 11]
5.2 hstack, vstack, concatenate 不同维度的拼接
当我们需要把多个小矩阵或数组组合成一个更大的矩阵时,可以用 NumPy 的拼接函数。
np.hstack((arr1, arr2, ...))
:在水平方向拼接,要求行数相同。np.vstack((arr1, arr2, ...))
:在垂直方向拼接,要求列数相同。np.concatenate((arr1, arr2, ...), axis=?)
:可自行指定在第几维度上拼接。
示例:从一堆小矩阵组合出一个大矩阵
import numpy as npA = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
C = np.array([[9, 10], [11, 12]])# 垂直方向拼接 (上下拼)
v_result = np.vstack((A, B))
print("vstack(A, B):\n", v_result)# 水平方向拼接 (左右拼)
h_result = np.hstack((A, B))
print("hstack(A, B):\n", h_result)# 同时拼更多
big_mat = np.concatenate((A, B, C), axis=0) # axis=0 表示按行拼
print("concatenate(A, B, C) axis=0:\n", big_mat)
示例输出:
vstack(A, B):
[[1 2]
[3 4]
[5 6]
[7 8]]
hstack(A, B):
[[1 2 5 6]
[3 4 7 8]]
concatenate(A, B, C) axis=0:
[[ 1 2]
[ 3 4]
[ 5 6]
[ 7 8]
[ 9 10]
[11 12]]
6 难点总结
- 多维切片:初学者常常对多维切片有些晕,只要记住
[行范围, 列范围, ...]
的格式即可。确认清楚是“从第几行到第几行”(start 行到 stop-1 行),以及列的切片同理。 - 广播机制:理解广播前,最好先确认数组各维度的形状是否兼容;遇到报错可以先
reshape
一下让两者形状更匹配。 - reshape vs. flatten:
reshape()
通常只改变数组的“视图”,不复制数据;flatten()
会新建一个一维数组的副本,适合需要保留原数组同时获得一维副本的场景。
7 课后练习
练习 1
题目:生成一个 (5,5) 的随机数组(值可以使用 np.random.rand()
来实现),将其记为 arr
。
- 取其中第 2~4 行,以及第 3~5 列的子数组 (注意索引从 0 开始);
- 计算该子数组的平均值并打印出来。
提示:
- 如果
arr
是 5×5,索引行 2~4 就是[2:5]
,列 3~5 就是[3:5]
(注意结束索引要取到 4)。 - 随机数可以用
np.random.rand(5,5)
直接生成。
参考答案与讲解
import numpy as np# 1. 生成随机数组
arr = np.random.rand(5, 5)
print("原数组 arr:\n", arr)# 2. 取子数组
sub_arr = arr[2:5, 3:5]
print("子数组:\n", sub_arr)# 3. 求平均值
mean_val = sub_arr.mean()
print("子数组的平均值:", mean_val)
这里把行的索引 [2:5]
,列的索引 [3:5]
,就能取到第 2~4 行 (因为右边界不包含 5),第 3~4 列,正好是一个大小为 3×2 的子矩阵。
示例输出:
原数组 arr:
[[0.17472169 0.30419912 0.68112625 0.00321665 0.87915489]
[0.67482008 0.70894494 0.04085384 0.30370131 0.34488511]
[0.45313399 0.34835426 0.33280061 0.19336083 0.36340667]
[0.06465397 0.25293191 0.07030549 0.85075816 0.18457218]
[0.62036441 0.93252922 0.44451975 0.98231374 0.17086604]]
子数组:
[[0.19336083 0.36340667]
[0.85075816 0.18457218]
[0.98231374 0.17086604]]
子数组的平均值: 0.4575462682226081
练习 2
题目:写一个函数,输入任意维度的 ndarray
,将其按行或列拼接到另一个数组上 (可以限制行/列尺寸相同)。例如,若要在行方向(竖着)拼接两个数组,则两者列数要一致;如果要在列方向(横着)拼接,则两者行数要一致。
- 函数可以叫做
my_concat(arr1, arr2, axis=0)
,默认为 0 表示行方向拼接。 - 如果两者形状不匹配(如列数不同),可以给出提示或报错。
- 试着用这个函数来拼接几个随机矩阵,看看是否成功。
参考答案与讲解
def my_concat(arr1, arr2, axis=0):"""说明:- axis=0 表示在行方向(垂直)拼接,需要 arr1 和 arr2 的列数相同。- axis=1 表示在列方向(水平)拼接,需要 arr1 和 arr2 的行数相同。"""import numpy as np# 如果维度不同,可能需要先看能不能自动reshape或报错处理if axis == 0:# 检查列数是否相同if arr1.shape[1] != arr2.shape[1]:raise ValueError("在行方向拼接时,arr1 和 arr2 的列数不一致!")return np.concatenate((arr1, arr2), axis=0)elif axis == 1:# 检查行数是否相同if arr1.shape[0] != arr2.shape[0]:raise ValueError("在列方向拼接时,arr1 和 arr2 的行数不一致!")return np.concatenate((arr1, arr2), axis=1)else:raise ValueError("axis 只能是 0 或 1。")# 测试
import numpy as npmatA = np.random.rand(2, 3)
matB = np.random.rand(3, 3)
matC = np.random.rand(2, 3)print("matA:\n", matA)
print("matB:\n", matB)
print("matC:\n", matC)# 垂直拼接 matA 和 matC (行数2+2=4, 列数相同)
res1 = my_concat(matA, matC, axis=0)
print("垂直拼接后的结果:\n", res1)# 尝试拼接 matA 和 matB,会报错,因为 matA.shape=(2,3), matB.shape=(3,3),行数不同
# res2 = my_concat(matA, matB, axis=0) # 会报错
示例输出:
matA:
[[0.81163204 0.9802028 0.03037617]
[0.56140472 0.00258323 0.95990272]]
matB:
[[0.78104835 0.92488544 0.76512749]
[0.60052898 0.37283449 0.48025247]
[0.52653967 0.69406359 0.12275915]]
matC:
[[0.07243525 0.61638094 0.65346815]
[0.04226701 0.52721757 0.78658341]]
垂直拼接后的结果:
[[0.81163204 0.9802028 0.03037617]
[0.56140472 0.00258323 0.95990272]
[0.07243525 0.61638094 0.65346815]
[0.04226701 0.52721757 0.78658341]]
这样,我们就根据需求自定义了一个简单的拼接函数。在实际工作中,通常直接用 np.vstack
, np.hstack
或 np.concatenate
就能满足需要,这里主要是为了让你理解维度匹配的思想。
小结
通过本章学习,我们对 NumPy 的基础用法已有了初步认识:
- ndarray 的创建与属性:理解了如何使用
np.array
,np.zeros
,np.ones
,np.arange
等方式来构造数组,并查看.shape
,.ndim
,.dtype
等属性。 - 索引与切片:多维数组常用的切片方式
[start:stop:step]
,以及arr[row, col]
的二重索引。 - 数组运算与广播:学会了对数组直接加减乘除,以及利用广播机制,让不同维度兼容的数组也能做运算。
- 数组变形与拼接:
reshape
,ravel
,flatten
的区别;以及如何在行/列方向拼接多个数组。
在科学计算、数据分析的实际应用中,NumPy 提供了高效的底层支持,很多更高级的库(如 Pandas、Scikit-learn、TensorFlow、PyTorch)都会在内部使用 NumPy 的思路或 API。如果你能掌握好 NumPy,对后续学习其他库会大有助益。