<think>我们正在讨论NumPy中的sum函数,特别是当指定axis=1且keepdims=True时的行为。
根据引用[1]中的说明:当我们使用sum函数并指定一个轴(axis)时,该轴会被删除(从形状中移除)。但是,如果设置了keepdims=True,那么被缩减的轴会保留为长度为1的维度。
示例:
假设我们有一个形状为(2,3,5)的数组arr(即2页,3行,5列)。
当我们执行arr.sum(axis=0)时,形状变为(3,5) —— 第一个维度(轴0)被移除。
当我们执行arr.sum(axis=1)时,形状变为(2,5) —— 第二个维度(轴1)被移除。
但是,如果我们执行arr.sum(axis=1, keepdims=True),那么形状会变成(2,1,5)。注意,轴1的位置并没有被完全移除,而是变成了1,这样原来的三维数组现在变成了一个三维数组,其中第二个维度的长度为1。
这样做的目的是为了保持数组的维度数目不变,这在某些操作(如广播)中非常有用。
现在,我们具体解释一下“沿轴1求和并保持维度”:
- 轴1:对于三维数组,我们可以认为轴0是页,轴1是行,轴2是列。那么沿轴1求和就是将每一页的每一列的所有行相加(即按行方向压缩,但保留列)。
- 保持维度:通常,求和操作会减少一个维度(删除该轴)。设置keepdims=True会保留该轴,但长度为1,因此数组的维数不变。
例如,一个形状为(2,3,5)的数组,沿轴1求和(keepdims=True)后,形状为(2,1,5)。我们可以理解为:原来有2页,每页3行5列。沿行(轴1)求和后,每页只剩下1行(因为将3行的数据加到了一起),但列数不变,所以每页现在是1行5列,因此形状为(2,1,5)。
下面我们通过一个具体的例子来说明:
创建一个2x3x5的数组(0到29,共30个元素):
arr = np.arange(0,30).reshape(2,3,5)
然后计算沿轴1求和(keepdims=True):
result = arr.sum(axis=1, keepdims=True)
结果应该是一个形状为(2,1,5)的数组。
我们也可以手动计算第一页(第0页)沿轴1(行)求和:
第一页是一个3行5列的矩阵:
[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]]
沿行求和(即每一列的元素相加):
第一列:0+5+10=15
第二列:1+6+11=18
第三列:2+7+12=21
第四列:3+8+13=24
第五列:4+9+14=27
所以第一页求和后变成一行:[15,18,21,24,27]
同样,第二页(第1页):
[[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]]
沿行求和:15+20+25=60, 16+21+26=63, 17+22+27=66, 18+23+28=69, 19+24+29=72
得到一行:[60,63,66,69,72]
因此,结果数组为:
[[[15,18,21,24,27]],
[[60,63,66,69,72]]]
注意,这里有两层方括号,因为形状是(2,1,5),所以每一页的结果外面多了一层(因为行维度现在是1,所以用一层括号表示一行,而这一行只有一个元素(即一个包含5个数的行向量))。
但是,当我们打印时,可能显示为:
array([[[15, 18, 21, 24, 27]],
[[60, 63, 66, 69, 72]]])
形状验证:result.shape = (2,1,5)
这样,我们保留了维度,使得结果数组仍然是一个三维数组,而不是变成(2,5)的二维数组。
总结:使用keepdims=True可以在求和操作后保持数组的维度不变,这在需要保持数组维度结构的情况下非常有用,例如在进行广播运算时。
根据引用[1]和引用[2](关于轴的定义),我们可以这样理解:轴(axis)是数组的维度索引,从0开始。在sum操作中,指定的轴会被求和,然后该轴的长度变为1(如果keepdims=True)或者被移除(如果keepdims=False,默认情况)。
现在,我们可以用代码来验证:</think>### NumPy 沿轴 1 求和并保持维度 (`keepdims=True`) 详解
在 NumPy 中,`sum(axis=1, keepdims=True)` 操作会沿指定轴(行方向)求和,同时保留原始数组的维度结构。以下是关键点解析:
#### 1. **核心功能**
- **沿轴 1 求和**:对二维数组的每一行元素求和(三维数组中则是沿高度方向求和)。
- **保持维度**:通过 `keepdims=True`,求和后的结果保留原始维度数,被压缩的轴长度变为 1。
#### 2. **维度变化规则**
设数组形状为 $(m, n, p)$:
- **`sum(axis=1)`**:删除轴 1 → 形状变为 $(m, p)$
- **`sum(axis=1, keepdims=True)`**:保留轴 1 且长度为 1 → 形状变为 $(m, 1, p)$
#### 3. **示例演示
```python
import numpy as np
# 创建 2x3x4 三维数组
arr = np.arange(24).reshape(2, 3, 4)
print("原始数组形状:", arr.shape) # (2, 3, 4)
# 沿轴 1 求和(不保持维度)
sum_default = arr.sum(axis=1)
print("默认求和形状:", sum_default.shape) # (2, 4)
# 沿轴 1 求和并保持维度
sum_keepdims = arr.sum(axis=1, keepdims=True)
print("保持维度形状:", sum_keepdims.shape) # (2, 1, 4)
```
**输出结果**:
```
原始数组:
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
保持维度求和结果:
[[[12 15 18 21]] # 第一页: 0+4+8=12, 1+5+9=15, 2+6+10=18, 3+7+11=21
[[48 51 54 57]]] # 第二页: 12+16+20=48, 13+17+21=51, ...
```
#### 4. **应用场景**
- **维度对齐**:在广播运算中保持维度一致(如矩阵乘法)
- **梯度计算**:深度学习反向传播时保留梯度形状
- **数据压缩**:沿特定方向聚合数据而不丢失维度信息
- **可视化**:维持多维数组结构以便绘图
#### 5. **与默认行为的对比**
| **操作** | **形状变化** | **维度数** | 典型用途 |
|------------------------|-------------------|-----------|------------------|
| `sum(axis=1)` | $(m,n,p)→(m,p)$ | 减少 1 | 数据降维 |
| `sum(axis=1, keepdims=True)` | $(m,n,p)→(m,1,p)$ | 不变 | 广播运算/维度对齐 |
> 关键理解:`keepdims=True` 确保求和后**被操作的轴保留为长度 1 的维度**,而非直接删除该轴[^1][^2]。