NumPy入门

本文默认读者具有 Python 语法基础和线性代数基础。

Numpy

众所周知,常规的Python程序中,列表的本质是一个存储一堆指针的数组。这说明,它的内存地址是离散的,在每次读取时不能“沿着内存”一个一个读下去,需要间接寻址,这也带来了巨大的性能开销。

在小规模计算中,这样的性能开销可以忽略不计;但是在大规模的计算过程中,为了优化性能,我们必须引入Numpy进行计算。

NumPy是Python科学计算的核心库,它引入了高效的 ndarray(多维数组)对象,它的地址在内存中是连续的。同时,各种语法的设计也更有利于大规模计算。

以下是我们在数据科学和机器学习中最常用的五类 NumPy 语法。

1. 数组的创建

NumPy 提供了多种灵活创建数组(向量、矩阵)的方式:

import numpy as np # 导入的习惯写法
# 从 Python 列表创建
arr_1d = np.array([1, 2, 3])                 # 一维数组(向量)
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])     # 二维数组(矩阵)
# 创建特殊矩阵
zeros_matrix = np.zeros((2, 3))               # 2x3 的全 0 矩阵
ones_matrix = np.ones((3, 3))                 # 3x3 的全 1 矩阵
arange_arr = np.arange(0, 10, 2)              # 类似 range,生成 [0, 2, 4, 6, 8]

2. 观察数组属性

在线性代数运算中,时刻关注矩阵的“形状”和“数据类型”是一个极好的习惯:

matrix = np.array([[1, 2, 3], [4, 5, 6]])
print(matrix.shape)  # 输出形状: (2, 3) -> 2 行 3 列
print(matrix.dtype)  # 输出数据类型: int64
print(matrix.ndim)   # 输出维度数量: 2(代表是二维数组)

3. 切片与索引

如何从矩阵中精准提取出我们需要的数据?NumPy 采用的是 [行切片, 列切片] 的格式:

data = np.array([
    [10, 20, 30],
    [40, 50, 60],
    [70, 80, 90]
])
print(data[0, 1])    # 获取第 0 行、第 1 列的元素 -> 20
print(data[1, :])    # 获取第 1 行的所有元素 -> [40, 50, 60]
print(data[:, 2])    # 获取所有行的第 2 列元素 -> [30, 60, 90]
print(data[0:2, 1:3]) # 获取前 2 行、后 2 列的子矩阵 -> [[20, 30], [50, 60]]

注意:这里返回的是原数组的视图(类似引用),修改切片会导致原数组同时被修改。

4. 数学运算

在常规python中,我们使用for循环来处理元素,必须一个一个处理。而NumPy采用向量化计算,运算符默认是对应元素进行的。

a = np.array([1, 2])<br>b = np.array([3, 4])
print(a + b)  # 对应元素相加 -> [4, 6]
print(a * b)  # 对应元素相乘 -> [3, 8]

# 矩阵相乘(左行乘以右列)
A = np.array([[1, 2], [3, 4]])<br>B = np.array([[5, 6], [7, 8]])
C = A @ B     # 使用 @ 符号进行矩阵乘法,或者用dot函数
# C = np.dot(A, B)

5. 改变数组形状

在处理图像或文本数据时,我们经常需要把高维数据“展平”或重构形状:

flat_arr = np.arange(8)              # [0, 1, 2, 3, 4, 5, 6, 7]
matrix_2x4 = flat_arr.reshape(2, 4)  # 重构为 2行4列

# 这里的重构本质上是重构观察视角,而并非改变数组,因此数据不匹配(如3x3重构为2x4)会直接报错

6. 广播机制

当两个数组的形状不完全相同时,NumPy 的“广播机制”可以允许它们进行数学运算。这种机制会自动且隐式地扩展较小维度的数组,使其形状与较大维度的数组相匹配,从而避免了不必要的内存复制。

实际上,这正是批量处理元素的底层机制。

import numpy as np

matrix = np.array([
    [1, 2, 3],
    [4, 5, 6]
])

# 1. 矩阵与标量相加(标量 10 被广播到矩阵的每一个元素上)
print(matrix + 10)
# 输出:
# [[11 12 13]
#  [14 15 16]]

# 2. 矩阵与一维向量相加
# 向量形状为 (3,),矩阵形状为 (2, 3),向量在行方向上被复制并应用到每一行
row_vector = np.array([1, 0, -1])
print(matrix + row_vector)
# 输出:
# [[2 2 2]
#  [5 5 5]]

7. 条件筛选与布尔索引

在实际的数据处理中,我们经常需要筛选出满足特定条件的数据。NumPy 支持直接使用条件表达式生成“布尔掩码(Mask)”,并以此作为索引来过滤数组。

简单来说,mask是一个布尔数组,对应每个数据是否满足我们筛选的条件。我们利用这个数组再去从原来的数组中获得筛选后的数据。

data = np.array([5, 12, 8, 21, 3])

mask = data > 10
print(mask)  # 输出: [False  True False  True False]

# 使用布尔数组作为索引过滤原数据
filtered_data = data[mask]
print(filtered_data)  # 输出: [12 21]

# 简写形式(最常用写法)
print(data[data > 10])  # 输出: [12 21]

8. 常用统计与聚合函数

NumPy 提供了许多内置的聚合函数,用于快速计算数组的求和、均值、最大/最小值等属性。

同时,在多维数组中,我们可以通过设置axis参数来决定是沿着行计算还是沿着列计算。

matrix = np.array([
    [1, 2, 3],
    [4, 5, 6]
])

# 全局聚合
print(np.sum(matrix))   # 计算所有元素之和 -> 21
print(np.mean(matrix))  # 计算所有元素的均值 -> 3.5

# 沿特定轴聚合
# axis=0 表示压缩行方向,即按列进行计算
print(np.mean(matrix, axis=0))  # 输出: [2.5 3.5 4.5]

# axis=1 表示压缩列方向,即按行进行计算
print(np.max(matrix, axis=1))   # 输出: [3 6]

结语

恭喜你,成功入门numpy!

在后续的学习中,无论是操作 Pandas 数据表,还是在使用 PyTorch / TensorFlow 进行深度学习模型的参数管理时,你都会反复看到这些熟悉的设计逻辑和语法习惯。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇