目录

  1. 引言:numpy.sum() - 数组聚合的基石
  • 1.1 为什么 np.sum() 在 NumPy 中如此重要?
  • 1.2 np.sum() 与 Python 内置 sum() 的区别
  1. 核心功能:numpy.sum(a, axis=None, dtype=None, out=None, keepdims=False, initial=0)
  • 2.1 功能概述:计算数组元素的和
  • 2.2 参数详解
  • a: 输入数组
  • axis: 求和的轴向 (最关键参数)
  • dtype: 输出数据类型
  • out: 输出数组
  • keepdims: 保留维度 (重要参数)
  • initial: 初始值
  1. axis 参数详解:控制求和方向
  • 3.1 axis=None (默认值):对所有元素求和 (展平后求和)
  • 3.2 axis=整数:沿指定轴求和 (该轴将“塌缩”)
  • 示例一:2D 数组 axis=0 (按列求和,行塌缩)
  • 示例二:2D 数组 axis=1 (按行求和,列塌缩)
  • 示例三:3D 数组 axis=0, axis=1, axis=2
  • 3.3 axis=元组:沿多个轴同时求和
  1. keepdims=True 参数详解:保留求和轴的维度
  • 4.1 keepdims=False (默认值) vs keepdims=True 的输出形状对比
  • 4.2 keepdims=True 在广播中的应用
  1. dtype 参数:防止溢出与类型转换
  • 数据类型溢出问题示例
  • 指定 dtype 解决溢出
  1. initial 参数:为求和提供起始值
  2. numpy.sum() 与其他聚合函数
  • np.mean() (平均值)
  • np.prod() (乘积)
  • np.min() / np.max() (最小值/最大值)
  • np.cumsum() / np.cumprod() (累积和/累积积)
  1. 实际应用场景
  • 数据聚合与统计
  • 机器学习与深度学习
  • 损失函数计算 (如均方误差)
  • Softmax 函数的分母
  • 特征工程 (行/列总和作为新特征)
  • 图像处理 (像素总和)
  1. 性能考量
  2. 总结与最佳实践

1. 引言:numpy.sum() - 数组聚合的基石

在数据分析、科学计算和机器学习领域,对数据进行聚合操作(如求和、求平均、求最大值等)是极其常见的任务。NumPy 的 numpy.sum() 函数正是为此目的而设计,它能够高效、灵活地计算数组中元素的总和,并且支持多维数组的特定轴向求和。

1.1 为什么 np.sum() 在 NumPy 中如此重要?

  • 高效性: 像所有 NumPy 函数一样,np.sum() 在底层是用 C 语言实现的,对于大型数组,它的计算速度远超 Python 的原生循环求和。
  • 多维支持: 能够方便地控制求和的轴向,这是 Python 内置 sum() 所不具备的。
  • 灵活性: 结合 axiskeepdims 参数,可以实现各种复杂的聚合需求,并与广播机制无缝协作。
  • 内存优化: NumPy 数组本身内存效率高,求和操作进一步优化了计算过程。

1.2 np.sum() 与 Python 内置 sum() 的区别

虽然两者都用于求和,但存在关键差异:

  • 输入: Python sum() 可以接受任何可迭代对象(列表、元组等),而 np.sum() 专门用于 ndarray 对象。
  • 多维: Python sum() 只能处理一维可迭代对象,如果输入是列表的列表,它会尝试连接而不是求和。np.sum() 则可以处理任意维度的数组。
  • 轴向: np.sum() 提供了 axis 参数来指定求和的维度,Python sum() 没有这个功能。
  • 性能: 对于大型数值数据,np.sum() 的性能远超 Python sum()
import numpy as np

list_of_lists = [[1, 2], [3, 4]]
np_array_2d = np.array(list_of_lists)

# Python sum() 的行为
try:
    print("Python sum(list_of_lists):", sum(list_of_lists))
except TypeError as e:
    print(f"Python sum() 处理列表的列表错误: {e}")
# 错误: TypeError: unsupported operand type(s) for +: 'int' and 'list'

# NumPy sum() 的行为 (默认展平求和)
print("NumPy np.sum(np_array_2d):", np.sum(np_array_2d)) # 10 (1+2+3+4)

2. 核心功能:numpy.sum()

numpy.sum(a, axis=None, dtype=None, out=None, keepdims=False, initial=0)

2.1 功能概述:计算数组元素的和

np.sum() 函数会返回输入数组 a 中所有元素的总和,或者沿着指定轴的总和。

2.2 参数详解

  • a: (必需) 输入的 ndarray
  • axis: (可选)
  • None (默认):对所有元素求和,返回一个标量。
  • int:沿指定轴求和。该轴会从结果的形状中移除。
  • tuple of int:沿多个指定轴求和。这些轴将从结果的形状中移除。
  • dtype: (可选) 指定返回数组的数据类型。这对于防止溢出或控制精度非常有用。
  • out: (可选) 提供一个可选的输出数组,结果将存储在其中。
  • keepdims: (可选) bool 类型,默认为 False。如果设置为 True,则求和的轴在结果中仍保留,但长度变为 1。这对于后续的广播操作非常有用。
  • initial: (可选) 标量。如果提供,它将作为求和的初始值。当数组为空时,这将是结果。

3. axis 参数详解:控制求和方向

理解 axis 是掌握 np.sum() 的关键。它决定了哪个维度被“压缩”或“求和掉”。

我们将使用以下 2D 数组作为示例:

arr_2d = np.arange(1, 13).reshape(3, 4)
print("原始 2D 数组 (3行4列):\n", arr_2d)
# 输出:
# [[ 1  2  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
print("原始数组形状:", arr_2d.shape) # (3, 4)

3.1 axis=None (默认值):对所有元素求和 (展平后求和)

这是最简单的用法,它将数组扁平化,然后求所有元素的和。结果是一个标量。

sum_all = np.sum(arr_2d)
print("\n3.1 axis=None (所有元素求和):", sum_all) # 1 + ... + 12 = 78
print("结果形状:", np.shape(sum_all)) # () - 标量没有维度

3.2 axis=整数:沿指定轴求和 (该轴将“塌缩”)

  • axis=0: 沿第一个轴 (行) 求和。结果是每列的总和。这意味着行会“塌缩”,列保持不变。
  • 想象成把每一列的数字垂直加起来。
  • 原始形状 (rows, cols) 变为 (cols,)
sum_axis0 = np.sum(arr_2d, axis=0)
print("\n3.2 axis=0 (按列求和):", sum_axis0)
# 输出: [1+5+9, 2+6+10, 3+7+11, 4+8+12] = [15 18 21 24]
print("结果形状:", sum_axis0.shape) # (4,)
  • axis=1: 沿第二个轴 (列) 求和。结果是每行的总和。这意味着列会“塌缩”,行保持不变。
  • 想象成把每一行的数字水平加起来。
  • 原始形状 (rows, cols) 变为 (rows,)
sum_axis1 = np.sum(arr_2d, axis=1)
print("\n3.2 axis=1 (按行求和):", sum_axis1)
# 输出: [1+2+3+4, 5+6+7+8, 9+10+11+12] = [10 26 42]
print("结果形状:", sum_axis1.shape) # (3,)
  • 3D 数组示例
arr_3d = np.arange(1, 25).reshape(2, 3, 4)
print("\n原始 3D 数组 (2x3x4):\n", arr_3d)
print("原始数组形状:", arr_3d.shape) # (2, 3, 4)
# arr_3d[0] = 第一层 (3x4)
# arr_3d[1] = 第二层 (3x4)

sum_3d_axis0 = np.sum(arr_3d, axis=0) # 沿第一维度 (层) 求和,结果是 3x4
print("\n3D 数组 axis=0 (层塌缩): 结果形状", sum_3d_axis0.shape, "\n", sum_3d_axis0)
# [1+13, 2+14, ...]

sum_3d_axis1 = np.sum(arr_3d, axis=1) # 沿第二维度 (行) 求和,结果是 2x4
print("\n3D 数组 axis=1 (行塌缩): 结果形状", sum_3d_axis1.shape, "\n", sum_3d_axis1)
# [1+5+9, 2+6+10, ...] (对每个层独立执行)

sum_3d_axis2 = np.sum(arr_3d, axis=2) # 沿第三维度 (列) 求和,结果是 2x3
print("\n3D 数组 axis=2 (列塌缩): 结果形状", sum_3d_axis2.shape, "\n", sum_3d_axis2)
# [1+2+3+4, 5+6+7+8, 9+10+11+12] (对每个层独立执行)

3.3 axis=元组:沿多个轴同时求和

您可以指定一个轴元组,NumPy 将沿这些轴同时进行求和。这些指定的轴都将从结果的形状中移除。

# 沿 axis=0 和 axis=1 (即对每个 '深度' 切片求和,结果是 4 个元素的数组)
sum_3d_axis01 = np.sum(arr_3d, axis=(0, 1))
print("\n3.3 3D 数组 axis=(0, 1) (层和行同时塌缩):", sum_3d_axis01)
# 输出: [sum(所有层的第一行), sum(所有层的第二行), sum(所有层的第三行)]
# 比如 sum_3d_axis01[0] = (1+5+9) + (13+17+21) = 56
print("结果形状:", sum_3d_axis01.shape) # (4,)

# 沿 axis=0 和 axis=2 (即对每个 '行' 切片求和)
sum_3d_axis02 = np.sum(arr_3d, axis=(0, 2))
print("\n3.3 3D 数组 axis=(0, 2) (层和列同时塌缩):", sum_3d_axis02)
# 输出: [sum(所有层的第一行所有元素), sum(所有层的第二行所有元素), sum(所有层的第三行所有元素)]
print("结果形状:", sum_3d_axis02.shape) # (3,)

4. keepdims=True 参数详解:保留求和轴的维度

keepdims=True 时,被求和的轴在结果中仍保留,但其大小变为 1。这使得结果数组的维度数量与原始数组相同,方便进行广播操作。

4.1 keepdims=False (默认值) vs keepdims=True 的输出形状对比

print("\n--- keepdims 参数对比 ---")
print("原始 2D 数组形状:", arr_2d.shape) # (3, 4)

sum_axis0_no_keepdims = np.sum(arr_2d, axis=0, keepdims=False)
print("axis=0, keepdims=False 结果形状:", sum_axis0_no_keepdims.shape) # (4,)

sum_axis0_keepdims = np.sum(arr_2d, axis=0, keepdims=True)
print("axis=0, keepdims=True 结果形状:", sum_axis0_keepdims.shape) # (1, 4)
print("axis=0, keepdims=True 结果:\n", sum_axis0_keepdims)
# [[15 18 21 24]] (注意外层多了一对方括号,表示多了一个维度)

sum_axis1_keepdims = np.sum(arr_2d, axis=1, keepdims=True)
print("axis=1, keepdims=True 结果形状:", sum_axis1_keepdims.shape) # (3, 1)
print("axis=1, keepdims=True 结果:\n", sum_axis1_keepdims)
# [[10]
#  [26]
#  [42]]

4.2 keepdims=True 在广播中的应用

keepdims=True 的主要作用是方便后续的广播操作。例如,在标准化数据时,我们需要从每个元素中减去其所在列的平均值。如果 mean 函数不保留维度,结果形状可能无法直接与原始数组进行广播。

print("\n--- keepdims 在广播中的应用 ---")
data_matrix = np.array([[10, 20, 30],
                        [11, 21, 31],
                        [12, 22, 32]]) # 形状 (3, 3)

# 计算每列的平均值
column_means = np.mean(data_matrix, axis=0) # 形状 (3,)
print("每列平均值 (默认 keepdims=False) 形状:", column_means.shape)

# 尝试减去,会进行广播 (3,3) - (3,) -> (3,3) - (1,3) -> (3,3) 广播成功
normalized_data = data_matrix - column_means
print("广播成功 (3,3) - (3,): \n", normalized_data)

# 如果我们想显式地保留维度,可以这样操作:
column_means_keepdims = np.mean(data_matrix, axis=0, keepdims=True) # 形状 (1, 3)
print("每列平均值 (keepdims=True) 形状:", column_means_keepdims.shape)

# (3,3) - (1,3) 可以直接进行广播,更加直观,避免 NumPy 自动填充维度 (规则 1)
normalized_data_keepdims = data_matrix - column_means_keepdims
print("广播成功 (3,3) - (1,3): \n", normalized_data_keepdims)

# 结果是相同的,但在更复杂的广播场景中,keepdims=True 可以使代码更清晰、更可预测。

5. dtype 参数:防止溢出与类型转换

当对大量整数进行求和时,结果可能会超出原始数据类型所能表示的范围,导致溢出。通过指定 dtype 参数,可以确保结果存储在足够大的数据类型中。

print("\n--- dtype 参数 ---")
large_int_array = np.array([200, 200, 200], dtype=np.uint8) # 无符号8位整数,最大值 255
print("原始数组 (uint8):", large_int_array)

# 默认求和,结果会溢出 (200+200+200 = 600,超出了 255)
sum_default_dtype = np.sum(large_int_array)
print("默认 dtype 求和结果 (可能溢出):", sum_default_dtype) # 可能会是 88 (600 % 256)

# 指定 dtype 为 np.int64 或 np.float64
sum_int64 = np.sum(large_int_array, dtype=np.int64)
print("指定 dtype=np.int64 求和结果:", sum_int64) # 600

sum_float64 = np.sum(large_int_array, dtype=np.float64)
print("指定 dtype=np.float64 求和结果:", sum_float64) # 600.0

6. initial 参数:为求和提供起始值

在求和操作开始之前,可以将 initial 的值添加到总和中。当数组为空时,它也是结果。

print("\n--- initial 参数 ---")
arr_small = np.array([10, 20])
sum_with_initial = np.sum(arr_small, initial=100)
print("带初始值的求和:", sum_with_initial) # 100 + 10 + 20 = 130

empty_array = np.array([])
sum_empty_with_initial = np.sum(empty_array, initial=50)
print("空数组带初始值的求和:", sum_empty_with_initial) # 50

7. numpy.sum() 与其他聚合函数

NumPy 提供了许多与 np.sum() 具有相似参数结构的聚合函数,它们也支持 axiskeepdims

print("\n--- 其他聚合函数 ---")
arr_agg = np.array([[1, 2, 3], [4, 5, 6]])

print("np.mean(arr_agg, axis=0):", np.mean(arr_agg, axis=0)) # [2.5 3.5 4.5]
print("np.prod(arr_agg, axis=1):", np.prod(arr_agg, axis=1)) # [6 120]
print("np.min(arr_agg):", np.min(arr_agg)) # 1
print("np.max(arr_agg, axis=1, keepdims=True):\n", np.max(arr_agg, axis=1, keepdims=True)) # [[3],[6]]

print("np.cumsum(arr_agg, axis=1):\n", np.cumsum(arr_agg, axis=1)) # 累积和
# [[ 1  3  6]
#  [ 4  9 15]]

8. 实际应用场景

8.1 数据聚合与统计

计算数据集的总和、平均值等统计量。

sales_data = np.random.randint(100, 1000, size=(5, 3)) # 5天3个产品的销售额
print("\n应用场景 - 销售数据:\n", sales_data)
total_sales_per_product = np.sum(sales_data, axis=0)
print("各产品总销售额:", total_sales_per_product)
total_sales_per_day = np.sum(sales_data, axis=1)
print("每天总销售额:", total_sales_per_day)
overall_total_sales = np.sum(sales_data)
print("总销售额:", overall_total_sales)

8.2 机器学习与深度学习

  • 损失函数计算 (如均方误差 MSE)
predictions = np.array([0.9, 0.2, 0.8, 0.4])
true_labels = np.array([1.0, 0.0, 0.7, 0.5])
mse = np.sum((predictions - true_labels)**2) / len(predictions)
print("\n应用场景 - 均方误差 (MSE):", mse) # 或使用 np.mean((predictions - true_labels)**2)
  • Softmax 函数的分母
    Softmax 函数用于将向量转换为概率分布,其分母是指数化后元素的总和。
logits = np.array([1.0, 2.0, 3.0])
exp_logits = np.exp(logits)
softmax_denom = np.sum(exp_logits)
softmax_output = exp_logits / softmax_denom
print("\n应用场景 - Softmax 函数:")
print("exp_logits:", exp_logits)
print("softmax_denom:", softmax_denom)
print("softmax_output (概率分布):", softmax_output)
  • 特征工程 (行/列总和作为新特征)
    将某些行或列的总和作为新的数据特征。

8.3 图像处理 (像素总和)

计算图像所有像素值的总和,例如用于亮度分析或图像特征。

image_pixels = np.random.randint(0, 256, size=(100, 100), dtype=np.uint8)
total_intensity = np.sum(image_pixels)
print("\n应用场景 - 图像处理 (总像素强度):", total_intensity)

9. 性能考量

np.sum() 比 Python 的内置 sum() 具有显著的性能优势,尤其是在处理大型 NumPy 数组时。这是因为 NumPy 操作是经过优化的 C 语言实现,避免了 Python 解释器的开销。对于需要频繁求和的数值计算任务,始终推荐使用 np.sum()

10. 总结与最佳实践

numpy.sum() 是 NumPy 库中一个功能强大且用途广泛的函数,是进行数据聚合和数值计算不可或缺的工具。

核心要点回顾:

  • 元素级求和: 默认或不指定 axis 时对所有元素求和。
  • axis 参数: 精确控制沿哪个维度进行求和,该维度将被“塌缩”。理解 axis=0 (按列) 和 axis=1 (按行) 是基础。
  • keepdims=True 保留求和轴的维度 (长度为 1),这在需要后续广播操作时非常有用,可以保持数组的维度一致性。
  • dtype 参数: 防止整数溢出,并控制输出结果的数据类型。
  • initial 参数: 可为求和提供起始值。
  • 高性能: 远超 Python 原生 sum()

掌握 np.sum() 及其参数的细微之处,将使您能够更高效、更灵活地处理各种数值数据,为数据分析、机器学习模型开发和科学研究打下坚实的基础。