Python NumPy 数组求最大值:使用 np.max() – wiki基地


深入探索 Python NumPy 数组求最大值:精通 np.max() 函数

在数据科学、机器学习、图像处理以及各种数值计算领域,Python 的 NumPy 库无疑扮演着核心角色。NumPy 提供了高效的多维数组对象(ndarray)及其配套的函数,极大地提升了数值运算的性能。在处理数据时,经常需要找到数组中的最大值,无论是为了数据归一化、异常检测、特征分析还是其他目的。NumPy 提供了多种方式来实现这一目标,其中最常用且功能强大的方法之一就是使用 np.max() 函数。

本文将深入探讨 np.max() 函数的各种用法、参数及其背后的原理,帮助读者全面掌握如何在 NumPy 数组中高效、灵活地找到最大值。我们将从最基本的用法开始,逐步深入到多维数组的处理、轴(axis)参数的应用、保持维度(keepdims)的技巧,以及如何处理缺失值(NaN)。

1. NumPy 简介与为何需要求最大值

NumPy(Numerical Python)是 Python 中用于科学计算的基础库。它提供了一个高性能的多维数组对象 ndarray,以及用于处理这些数组的大量数学函数。与 Python 内置的列表相比,NumPy 数组在存储效率、运算速度和功能丰富性方面都有显著优势,尤其适用于大规模数据的处理。

在实际应用中,寻找数组中的最大值是一个非常普遍的操作。例如:

  • 在统计分析中,我们可能想知道一组数据的最高点或峰值。
  • 在图像处理中,最大像素值可能代表最亮的区域。
  • 在机器学习模型的输出中,最大概率值可能指示了预测的类别。
  • 在信号处理中,最大振幅可能表示信号的强度。
  • 在优化问题中,可能需要找到目标函数的最大值。

NumPy 提供了 np.max() 函数来高效地完成这项任务。

2. np.max() 函数的基本用法

np.max() 是一个顶层函数,可以直接通过 np.max(array) 的形式调用,其中 array 是一个 NumPy 数组。它的基本作用是找到输入数组中的所有元素的最大值。

让我们从一个简单的一维数组开始:

“`python
import numpy as np

创建一个一维 NumPy 数组

arr_1d = np.array([10, 5, 20, 15, 8, 25])

使用 np.max() 找到最大值

max_value = np.max(arr_1d)

print(f”一维数组:{arr_1d}”)
print(f”数组中的最大值:{max_value}”)

输出:

一维数组:[10 5 20 15 8 25]

数组中的最大值:25

“`

在这个例子中,np.max(arr_1d) 遍历了 arr_1d 中的所有元素,并返回了其中的最大值 25

np.max() 也可以用于处理其他类型的数据,只要这些数据类型支持比较操作(例如整数、浮点数)。

“`python

浮点数数组

arr_float = np.array([1.2, 3.5, 0.8, 4.1, 2.9])
print(f”浮点数数组:{arr_float}”)
print(f”浮点数数组的最大值:{np.max(arr_float)}”)

输出:

浮点数数组:[1.2 3.5 0.8 4.1 2.9]

浮点数数组的最大值:4.1

布尔值数组 (True > False)

arr_bool = np.array([True, False, True, False])
print(f”布尔值数组:{arr_bool}”)
print(f”布尔值数组的最大值:{np.max(arr_bool)}”)

输出:

布尔值数组:[ True False True False]

布尔值数组的最大值:True

“`

对于布尔值,True 被视为 1False 被视为 0,因此 np.max() 返回 True 如果数组中存在 True,否则返回 False(如果数组全为 False)。

需要注意的是,如果数组是空的,np.max() 将会引发 ValueError 异常,因为无法从空集合中找到最大值。

“`python

空数组

arr_empty = np.array([])
try:
np.max(arr_empty)
except ValueError as e:
print(f”对空数组求最大值会报错: {e}”)

输出:

对空数组求最大值会报错: zero-size array to reduction operation maximum which has no identity

“`

3. 处理多维数组

NumPy 数组最强大的特性之一是其多维性。np.max() 函数同样能够处理二维、三维甚至更高维度的数组。

np.max() 被应用于一个多维数组而 不指定轴(axis) 时,它会扁平化(flatten)整个数组,然后计算所有元素的全局最大值,就像处理一维数组一样。

考虑一个二维数组:

“`python

创建一个二维 NumPy 数组

arr_2d = np.array([[1, 5, 2],
[8, 3, 9],
[4, 6, 7]])

print(f”二维数组:\n{arr_2d}”)

计算整个二维数组的全局最大值

global_max_value = np.max(arr_2d)

print(f”二维数组的全局最大值:{global_max_value}”)

输出:

二维数组:

[[1 5 2]

[8 3 9]

[4 6 7]]

二维数组的全局最大值:9

“`

在这个例子中,np.max(arr_2d) 扫描了所有 9 个元素,并找到了其中的最大值 9

对于三维数组也是类似的:

“`python

创建一个三维 NumPy 数组 (2个2×3的矩阵堆叠)

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

               [[ 7,  8,  9],
                [10, 11, 12]]])

print(f”三维数组:\n{arr_3d}”)
print(f”三维数组的形状:{arr_3d.shape}”) # (层数, 行数, 列数)

计算整个三维数组的全局最大值

global_max_3d = np.max(arr_3d)

print(f”三维数组的全局最大值:{global_max_3d}”)

输出:

三维数组:

[[[ 1 2 3]

[ 4 5 6]]

[[ 7 8 9]

[10 11 12]]]

三维数组的形状:(2, 2, 3)

三维数组的全局最大值:12

“`

同样,不指定轴时,np.max() 会计算所有元素的全局最大值 12

这种用法非常直观,但很多时候,我们并不需要整个数组的最大值,而是希望找到沿着特定维度(或轴)的最大值。这就引出了 np.max() 函数最重要的参数:axis

4. 理解 axis 参数

axis 参数是 NumPy 中进行各种聚合操作(如求和、平均、最大值、最小值等)的核心概念。它指定了执行操作时应该沿着哪个维度进行归约(reduction)。归约操作会减少数组的维度。

在 NumPy 中,数组的维度是从 0 开始编号的。对于一个形状为 (d0, d1, d2, ...) 的数组:

  • axis=0 指的是第一个维度。
  • axis=1 指的是第二个维度。
  • axis=2 指的是第三个维度,以此类推。

当我们在 np.max(array, axis=i) 中指定 axis=i 时,意味着我们将在第 i 个维度上进行最大值计算。结果数组的形状将是原数组形状移除了第 i 个维度后的形状。

让我们回到二维数组的例子来详细说明:

python
arr_2d = np.array([[1, 5, 2],
[8, 3, 9],
[4, 6, 7]])
print(f"二维数组:\n{arr_2d}")
print(f"二维数组的形状:{arr_2d.shape}") # (3, 3)

二维数组 arr_2d 的形状是 (3, 3),意味着它有两个维度:axis=0axis=1

  • axis=0:沿第一个维度(行)进行归约

    当指定 axis=0 时,np.max() 会沿着垂直方向(列方向)找出每个位置的最大值。想象一下我们沿着 axis=0 向上/向下“压扁”数组。结果数组的形状将是原形状移除了第一个维度后的形状,即 (3,)

    “`python
    max_axis_0 = np.max(arr_2d, axis=0)
    print(f”沿 axis=0 求最大值:{max_axis_0}”)
    print(f”结果的形状:{max_axis_0.shape}”)

    输出:

    沿 axis=0 求最大值:[8 6 9]

    结果的形状:(3,)

    “`

    解释:
    * 第一列 [1, 8, 4] 的最大值是 8
    * 第二列 [5, 3, 6] 的最大值是 6
    * 第三列 [2, 9, 7] 的最大值是 9
    结果是一个包含这些最大值的一维数组 [8, 6, 9]

  • axis=1:沿第二个维度(列)进行归约

    当指定 axis=1 时,np.max() 会沿着水平方向(行方向)找出每行的最大值。想象一下我们沿着 axis=1 向左/向右“压扁”数组。结果数组的形状将是原形状移除了第二个维度后的形状,即 (3,)

    “`python
    max_axis_1 = np.max(arr_2d, axis=1)
    print(f”沿 axis=1 求最大值:{max_axis_1}”)
    print(f”结果的形状:{max_axis_1.shape}”)

    输出:

    沿 axis=1 求最大值:[5 9 7]

    结果的形状:(3,)

    “`

    解释:
    * 第一行 [1, 5, 2] 的最大值是 5
    * 第二行 [8, 3, 9] 的最大值是 9
    * 第三行 [4, 6, 7] 的最大值是 7
    结果是一个包含这些最大值的一维数组 [5, 9, 7]

三维数组中的 axis

对于三维数组 arr_3d 形状为 (2, 2, 3)

“`python
arr_3d = np.array([[[ 1, 2, 3],
[ 4, 5, 6]],

               [[ 7,  8,  9],
                [10, 11, 12]]])

print(f”三维数组:\n{arr_3d}”)
print(f”三维数组的形状:{arr_3d.shape}”) # (层数, 行数, 列数)
“`

  • axis=0:沿第一个维度(层)归约。想象我们沿着层厚方向压扁。结果将是一个 2D 数组,形状为移除第一个维度后的 (2, 3)

    “`python
    max_axis_0_3d = np.max(arr_3d, axis=0)
    print(f”沿 axis=0 (层) 求最大值:\n{max_axis_0_3d}”)
    print(f”结果的形状:{max_axis_0_3d.shape}”)

    输出:

    沿 axis=0 (层) 求最大值:

    [[ 7 8 9]

    [10 11 12]]

    结果的形状:(2, 3)

    “`

    解释:比较两个层对应位置的元素 [[1, 2, 3], [4, 5, 6]][[7, 8, 9], [10, 11, 12]],取较大者形成新的 2×3 矩阵。例如,位置 (0,0) 的最大值是 max(1, 7) = 7,位置 (1,2) 的最大值是 max(6, 12) = 12

  • axis=1:沿第二个维度(行)归约。想象在每个层内部,我们沿着行方向压扁。结果将是一个 2D 数组,形状为移除第二个维度后的 (2, 3)

    “`python
    max_axis_1_3d = np.max(arr_3d, axis=1)
    print(f”沿 axis=1 (行) 求最大值:\n{max_axis_1_3d}”)
    print(f”结果的形状:{max_axis_1_3d.shape}”)

    输出:

    沿 axis=1 (行) 求最大值:

    [[ 4 5 6]

    [10 11 12]]

    结果的形状:(2, 3)

    “`

    解释:在第一个层 [[1, 2, 3], [4, 5, 6]] 中,第一列是 [1, 4],最大值是 4;第二列是 [2, 5],最大值是 5;第三列是 [3, 6],最大值是 6。所以第一个 1×3 的结果是 [4, 5, 6]。在第二个层 [[7, 8, 9], [10, 11, 12]] 中,类似地得到 [10, 11, 12]。最终结果是这两个 1×3 数组堆叠成的 2×3 数组。

  • axis=2:沿第三个维度(列)归约。想象在每个层、每行内部,我们沿着列方向压扁。结果将是一个 2D 数组,形状为移除第三个维度后的 (2, 2)

    “`python
    max_axis_2_3d = np.max(arr_3d, axis=2)
    print(f”沿 axis=2 (列) 求最大值:\n{max_axis_2_3d}”)
    print(f”结果的形状:{max_axis_2_3d.shape}”)

    输出:

    沿 axis=2 (列) 求最大值:

    [[ 3 6]

    [ 9 12]]

    结果的形状:(2, 2)

    “`

    解释:在第一个层 [[1, 2, 3], [4, 5, 6]] 中,第一行 [1, 2, 3] 的最大值是 3,第二行 [4, 5, 6] 的最大值是 6。所以第一个 2×1 的结果是 [3, 6] (列向量)。在第二个层 [[7, 8, 9], [10, 11, 12]] 中,类似地得到 [9, 12]。最终结果是将这两个 2×1 数组在 axis=1 方向上堆叠成的 2×2 数组 [[3, 9], [6, 12]] (注意 NumPy 的堆叠方式,通常是按照轴进行)。实际上,这里的结果是 [[3, 6], [9, 12]],因为我们是对 每一行 求最大值,结果保留行结构,形成 2×2 矩阵。

同时指定多个轴(轴元组)

axis 参数也可以是一个元组,表示同时在这些指定的维度上进行归约。结果数组的形状将是原数组形状移除了元组中所有维度后的形状。

例如,对于 arr_3d (形状 (2, 2, 3)),如果指定 axis=(0, 1),意味着先在 axis=0(层)上归约,然后在 axis=1(行)上归约。等价于对整个数组的每个“列”求最大值(跨层跨行)。结果数组的形状将是移除 axis=0axis=1 后的 (3,)

“`python
max_axis_0_1_3d = np.max(arr_3d, axis=(0, 1))
print(f”沿 axis=(0, 1) 求最大值:{max_axis_0_1_3d}”)
print(f”结果的形状:{max_axis_0_1_3d.shape}”)

输出:

沿 axis=(0, 1) 求最大值:[10 11 12]

结果的形状:(3,)

“`

解释:
* 所有层和所有行的第一个元素构成了数组 [1, 4, 7, 10],最大值是 10
* 所有层和所有行的第二个元素构成了数组 [2, 5, 8, 11],最大值是 11
* 所有层和所有行的第三个元素构成了数组 [3, 6, 9, 12],最大值是 12
结果是 [10, 11, 12]

如果指定 axis=(0, 1, 2),则意味着对所有维度进行归约,结果将是一个标量,这与不指定 axis 的全局最大值是等价的。

“`python
max_axis_0_1_2_3d = np.max(arr_3d, axis=(0, 1, 2))
print(f”沿 axis=(0, 1, 2) 求最大值:{max_axis_0_1_2_3d}”)
print(f”结果的类型:{type(max_axis_0_1_2_3d)}”)

输出:

沿 axis=(0, 1, 2) 求最大值:12

结果的类型: # 或其他整数/浮点数类型

“`

理解 axis 参数的关键在于记住它指定的是被归约的维度,这些维度将在结果中被移除(或者尺寸变为 1,如果使用了 keepdims=True)。

5. 保持维度 (keepdims)

默认情况下,np.max() 在指定 axis 后会移除对应的维度。但有时,为了进行后续的广播(broadcasting)或其他需要保留维度结构的运算,我们希望归约后的结果仍然保持与原数组相同的维度数量,只不过被归约的维度其大小变为 1。这就是 keepdims=True 参数的作用。

我们再次使用二维数组的例子:

python
arr_2d = np.array([[1, 5, 2],
[8, 3, 9],
[4, 6, 7]])
print(f"二维数组:\n{arr_2d}")
print(f"二维数组的形状:{arr_2d.shape}") # (3, 3)

之前我们看到,np.max(arr_2d, axis=0) 结果形状是 (3,)np.max(arr_2d, axis=1) 结果形状也是 (3,)

现在使用 keepdims=True

“`python
max_axis_0_keepdims = np.max(arr_2d, axis=0, keepdims=True)
print(f”沿 axis=0 并保持维度求最大值:{max_axis_0_keepdims}”)
print(f”结果的形状:{max_axis_0_keepdims.shape}”)

输出:

沿 axis=0 并保持维度求最大值:[[8 6 9]]

结果的形状:(1, 3)

“`

解释:结果仍然是一个二维数组 [[8, 6, 9]]。虽然内容与 [8, 6, 9] 相同,但它的形状是 (1, 3)。原来的第一个维度(大小为 3)被归约了,但因为 keepdims=True,它并没有被移除,而是被替换成一个大小为 1 的维度。

“`python
max_axis_1_keepdims = np.max(arr_2d, axis=1, keepdims=True)
print(f”沿 axis=1 并保持维度求最大值:\n{max_axis_1_keepdims}”)
print(f”结果的形状:{max_axis_1_keepdims.shape}”)

输出:

沿 axis=1 并保持维度求最大值:

[[5]

[9]

[7]]

结果的形状:(3, 1)

“`

解释:结果是一个形状为 (3, 1) 的二维数组。原来的第二个维度(大小为 3)被归约了,并被替换成一个大小为 1 的维度。

keepdims=True 的应用场景

keepdims=True 在进行涉及广播的运算时非常有用。广播是 NumPy 允许不同形状数组之间进行数学运算的一种机制。通常,广播要求数组的维度兼容。通过 keepdims=True 保持维度,可以使得归约结果与原数组具有兼容的形状,从而方便进行元素级的运算。

例如,如果我们想对二维数组的每一行元素除以该行的最大值(归一化行):

不使用 keepdims:

“`python
arr_2d = np.array([[1, 5, 2],
[8, 3, 9],
[4, 6, 7]])

row_maxes = np.max(arr_2d, axis=1) # 形状 (3,)
print(f”行最大值 (不保持维度): {row_maxes}, 形状: {row_maxes.shape}”)

直接用 arr_2d (形状 (3, 3)) 除以 row_maxes (形状 (3,))

NumPy 会尝试广播。这里广播是成功的:row_maxes 会被扩展为形状 (3, 3)

具体是每一行都复制 row_maxes 向量

normalized_arr_no_keepdims = arr_2d / row_maxes # 广播发生
print(f”行归一化结果 (不保持维度):\n{normalized_arr_no_keepdims}”)

输出:

行最大值 (不保持维度): [5 9 7], 形状: (3,)

行归一化结果 (不保持维度):

[[0.2 1. 0.4 ]

[0.88888889 0.33333333 1. ]

[0.57142857 0.85714286 1. ]]

“`

在这个例子中,虽然广播成功了,但广播的逻辑是将 [5, 9, 7] 扩展成一个 [[5, 9, 7], [5, 9, 7], [5, 9, 7]] 形状的数组。这不是我们想要的按行进行除法。我们希望的是第一行除以 5,第二行除以 9,第三行除以 7。

使用 keepdims=True:

“`python
arr_2d = np.array([[1, 5, 2],
[8, 3, 9],
[4, 6, 7]])

row_maxes_keptdims = np.max(arr_2d, axis=1, keepdims=True) # 形状 (3, 1)
print(f”行最大值 (保持维度): \n{row_maxes_keptdims}, 形状: {row_maxes_keptdims.shape}”)

用 arr_2d (形状 (3, 3)) 除以 row_maxes_keptdims (形状 (3, 1))

NumPy 会尝试广播。这里广播是成功的:row_maxes_keptdims (3, 1) 会沿着 axis=1 扩展为 (3, 3)。

具体是[[5], [9], [7]] 扩展为 [[5, 5, 5], [9, 9, 9], [7, 7, 7]] 形状的数组。

normalized_arr_keepdims = arr_2d / row_maxes_keptdims # 广播发生,逻辑正确
print(f”行归一化结果 (保持维度):\n{normalized_arr_keepdims}”)

输出:

行最大值 (保持维度):

[[5]

[9]

[7]], 形状: (3, 1)

行归一化结果 (保持维度):

[[0.2 1. 0.4 ]

[0.88888889 0.33333333 1. ]

[0.57142857 0.85714286 1. ]]

“`

这次广播的逻辑是正确的,row_maxes_keptdims (3, 1) 会被广播到 (3, 3),相当于 [[5], [9], [7]] 变成了 [[5, 5, 5], [9, 9, 9], [7, 7, 7]],然后进行元素级的除法。这正是我们想要的行归一化效果。

因此,当归约结果需要与原数组或其他数组进行广播运算,并且希望广播行为符合维度结构时,keepdims=True 非常有用。

6. 处理缺失值(NaN)

在真实世界的数据中,缺失值(通常表示为 NaN – Not a Number)是常见的问题。np.max() 函数在遇到 NaN 时有特定的行为。

默认情况下,如果数组中包含任何 NaN 值,并且你在包含 NaN 的子数组(例如,沿着某个轴计算时遇到的行或列)上求最大值,那么结果通常会是 NaN。这是因为 NaN 与任何数进行比较的结果都是不确定的(通常是 False 或引发错误),所以最大值无法确定。

“`python
arr_with_nan = np.array([[1, 5, np.nan],
[8, 3, 9],
[np.nan, 6, 7]])

print(f”包含 NaN 的数组:\n{arr_with_nan}”)

全局最大值

global_max_nan = np.max(arr_with_nan)
print(f”全局最大值 (含 NaN):{global_max_nan}”) # 通常输出 NaN

沿 axis=0 求最大值

max_axis_0_nan = np.max(arr_with_nan, axis=0)
print(f”沿 axis=0 求最大值 (含 NaN):{max_axis_0_nan}”) # [ 8. 6. nan]

沿 axis=1 求最大值

max_axis_1_nan = np.max(arr_with_nan, axis=1)
print(f”沿 axis=1 求最大值 (含 NaN):{max_axis_1_nan}”) # [nan 9. 7.]
“`

可以看到,只要参与计算的元素中包含 NaN,结果就可能变成 NaN。这在很多情况下并不是我们想要的行为,我们可能希望忽略 NaN 值,只计算非 NaN 元素的最小值。

NumPy 提供了专门的函数来处理这种情况:np.nanmax()np.nanmax() 的作用与 np.max() 完全相同,但它会忽略输入数组中的 NaN 值,只考虑有效的数值。

“`python

使用 np.nanmax() 忽略 NaN 求最大值

global_nanmax = np.nanmax(arr_with_nan)
print(f”全局最大值 (忽略 NaN):{global_nanmax}”) # 输出 9.0

沿 axis=0 求最大值 (忽略 NaN)

nanmax_axis_0 = np.nanmax(arr_with_nan, axis=0)
print(f”沿 axis=0 求最大值 (忽略 NaN):{nanmax_axis_0}”) # [8. 6. 9.]

沿 axis=1 求最大值 (忽略 NaN)

nanmax_axis_1 = np.nanmax(arr_with_nan, axis=1)
print(f”沿 axis=1 求最大值 (忽略 NaN):{nanmax_axis_1}”) # [5. 9. 7.]
“`

使用 np.nanmax() 后,计算结果忽略了 NaN 值,得到了我们通常期望的最大值。

需要注意的是,如果沿某个轴的所有元素都是 NaN,那么 np.nanmax() 会返回负无穷大 (-inf)。如果整个数组所有元素都是 NaN 或者数组为空,np.nanmax() 会返回负无穷大。

“`python
arr_all_nan = np.array([np.nan, np.nan, np.nan])
print(f”全 NaN 数组最大值 (忽略 NaN):{np.nanmax(arr_all_nan)}”) # 输出 -inf

arr_mixed_nan = np.array([[1, np.nan], [np.nan, np.nan]])
print(f”部分 NaN 数组沿 axis=0 最大值 (忽略 NaN):{np.nanmax(arr_mixed_nan, axis=0)}”) # [ 1. nan]
print(f”部分 NaN 数组沿 axis=1 最大值 (忽略 NaN):{np.nanmax(arr_mixed_nan, axis=1)}”) # [ 1. -inf]
“`

因此,在处理可能包含 NaN 的数据时,np.nanmax() 是一个非常有用的函数。

7. np.max() 与数组方法 .max()

除了作为顶层函数 np.max(array, ...) 使用外,NumPy 数组对象本身也提供了 .max() 方法:array.max(...)

这两个方法在功能上是等价的:

“`python
arr = np.array([[1, 5], [8, 3]])

使用 np.max() 函数

max_func = np.max(arr)
max_func_axis_0 = np.max(arr, axis=0)

使用数组方法 .max()

max_method = arr.max()
max_method_axis_0 = arr.max(axis=0)

print(f”使用 np.max() 函数获取全局最大值: {max_func}”)
print(f”使用数组方法 .max() 获取全局最大值: {max_method}”)
print(f”使用 np.max() 函数沿 axis=0 获取最大值: {max_func_axis_0}”)
print(f”使用数组方法 .max() 沿 axis=0 获取最大值: {max_method_axis_0}”)

输出:

使用 np.max() 函数获取全局最大值: 8

使用数组方法 .max() 获取全局最大值: 8

使用 np.max() 函数沿 axis=0 获取最大值: [8 5]

使用数组方法 .max() 沿 axis=0 获取最大值: [8 5]

“`

可以看到,两者的结果完全一致。在实际使用中,选择哪种方式更多是个人偏好。有些人喜欢函数式写法 np.max(...),认为它更明确是调用 NumPy 的一个函数;有些人喜欢面向对象式写法 array.max(...),认为它更符合 Python 的对象方法调用习惯。两者都没有性能上的显著差异。

同样,对于忽略 NaN 的情况,数组方法是 .nanmax()

“`python
arr_with_nan = np.array([[1, 5, np.nan],
[8, 3, 9],
[np.nan, 6, 7]])

print(f”使用 np.nanmax() 全局最大值: {np.nanmax(arr_with_nan)}”)
print(f”使用数组方法 .nanmax() 全局最大值: {arr_with_nan.nanmax()}”)

print(f”使用 np.nanmax() 沿 axis=0 最大值: {np.nanmax(arr_with_nan, axis=0)}”)
print(f”使用数组方法 .nanmax() 沿 axis=0 最大值: {arr_with_nan.nanmax(axis=0)}”)
“`

8. 性能优势

为什么推荐使用 NumPy 的 np.max() 而不是 Python 内置的 max() 函数结合循环来处理 NumPy 数组?

“`python

不推荐的做法 (使用 Python 内置 max 和列表理解)

arr_2d = np.array([[1, 5, 2],
[8, 3, 9],
[4, 6, 7]])

全局最大值

max(arr_2d.flatten().tolist()) # 先展平转列表,再用内置max,低效

沿 axis=0 最大值

[max(arr_2d[:, i]) for i in range(arr_2d.shape[1])] # 使用列表理解和切片,低效且不通用

沿 axis=1 最大值

[max(row) for row in arr_2d] # 使用列表理解,对大数组仍然低效

“`

主要原因在于性能。NumPy 的核心是使用 C 或 Fortran 语言编写的,其操作(包括 np.max())是高度优化的向量化操作。这意味着计算是在底层以批处理的方式进行的,避免了 Python 解释器的循环开销。对于大型数组,NumPy 的速度优势是压倒性的。

使用 Python 循环和内置函数来处理大型 NumPy 数组通常会非常慢,因为它需要在 Python 层面上逐个元素地进行操作,而 NumPy 函数则直接利用底层的优化实现。

因此,始终优先使用 NumPy 提供的函数来进行数组运算,包括求最大值。

9. 实际应用举例

np.max() 在各种实际场景中都有广泛应用:

  • 数据分析: 找出某个传感器读数的峰值,股票价格的最高点,某个时间段内的最高温度等。
  • 图像处理: 确定图像中最亮的像素值(全局最大值),或者找到每一行/列中的最大亮度值(沿轴求最大值)。
  • 机器学习: 在激活函数的输出中找到最大值(如 Softmax 的结果),或者在梯度下降中监控最大梯度值。
  • 统计学: 计算样本集合的最大值。
  • 物理/工程: 分析信号的峰值振幅,结构的最大应力点等。

例如,在一个模拟的数据集中,我们可能有多个实验的测量结果,存储在一个二维 NumPy 数组中,每一行代表一个实验,每一列代表一个测量点。要找到每个实验的最大测量值,就可以使用 np.max(data, axis=1)

10. 总结

本文详细介绍了如何使用 Python NumPy 库中的 np.max() 函数来寻找数组中的最大值。我们从最基本的用法开始,逐步深入到多维数组的处理、关键参数 axiskeepdims 的作用,以及如何使用 np.nanmax() 函数优雅地处理缺失值 NaN

关键 takeaways:

  • np.max(array) (不指定 axis) 计算整个数组的全局最大值。
  • np.max(array, axis=i) 计算沿第 i 个维度(轴)的最大值,结果的维度会减少。
  • axis 参数可以是一个整数或一个整数元组,指定要归约的一个或多个维度。
  • keepdims=True 参数可以在归约后保留原有的维度数量,被归约的维度大小变为 1,这对于广播操作非常有用。
  • np.max() 在遇到 NaN 时结果可能为 NaN
  • np.nanmax() 函数专门用于忽略 NaN 值计算最大值。
  • 数组对象方法 .max().nanmax() 在功能上与对应的顶层函数 np.max()np.nanmax() 等价。
  • 使用 NumPy 函数求最大值比使用 Python 内置方法和循环效率更高。

掌握 np.max() 及其相关参数,能够帮助你更有效地进行数值计算和数据分析。它是 NumPy 提供的众多强大聚合函数中的一个,是处理数组不可或缺的工具。在实际工作中,请根据你的具体需求,灵活运用 axiskeepdims 参数,并注意处理潜在的缺失值 NaN,选择合适的函数 (np.maxnp.nanmax)。


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部