HOWTO · NumPy

在 NumPy 数组中查找元素的第一个索引

本教程演示了如何在 python 中查找数组中元素的索引

本页内容

若要查找一维 NumPy 数组中某个值首次出现的位置,并且确定该值存在,可以使用 np.where(array == value)[0][0]。该表达式会返回第一个匹配位置;如果该值可能不存在,请先检查是否存在匹配项。NumPy 索引从零开始。

使用 np.where() 查找第一个匹配索引

np.where(condition) 会返回一个元组,其中每个数组维度各对应一个索引数组。对于一维数组,元组的第一个元素就是所有匹配位置组成的数组。取出其中第一个元素即可得到首次匹配的位置。

运行以下示例:

本节中的代码以及显示的标签或输出仍为英文。

import numpy as np

values = np.array([10, 20, 30, 40, 50, 20])
target = 20
matches = np.where(values == target)[0]
print(int(matches[0]))
1

这里,matches 包含 20 出现的两个位置,而 matches[0] 会选出第一个位置。如果没有匹配值,matches 就不包含任何元素,因此对它进行索引会引发 IndexError。如果不确定是否存在匹配项,请在选择索引前检查 matches.size。三参数形式 np.where(condition, x, y) 会根据条件从 x 或 y 中选择值;它与此处展示的索引返回形式不同。

使用 np.nonzero() 查找匹配索引

对于布尔条件,np.nonzero() 会返回其中为 True 的元素的索引。与单参数形式的 np.where() 一样,它会返回一个索引数组元组,每个数组维度对应一个索引数组。对于一维数组,取出元组中的第一个数组即可。

本节中的代码以及显示的标签或输出仍为英文。

import numpy as np

values = np.array([4, 7, 4, 9])
positions = np.nonzero(values == 4)[0]
print(positions.tolist())

结果会按数组中的顺序包含所有匹配位置。只有在确认数组非空后,才能用 positions[0] 取得第一个匹配位置。对于多维数组,元组中的每个元素都包含沿一个维度的坐标;将对应位置的坐标配对,即可定位每个匹配项。

使用 np.argmax() 查找布尔匹配项

np.argmax() 会返回最大值所在的位置。用于布尔掩码时,它会返回第一个 True 的位置,因为 True 大于 False。非空且全为 False 的掩码也会得到 0,所以使用结果前应先检查是否存在匹配项。

本节中的代码以及显示的标签或输出仍为英文。

import numpy as np

values = np.array([5, 8, 3, 8])
mask = values == 8
first = int(np.argmax(mask)) if np.any(mask) else None
print(first)

这种写法在目标值不存在时会得到 None,否则会得到第一个匹配位置。若要获取所有匹配位置,请改用 np.where() 或 np.nonzero()。

将数组转换后使用 list.index()

将一维数组转换为 Python 列表后,就可以使用列表方法 list.index()。它会返回第一次出现的位置。转换会创建一个 Python 列表,因此会增加时间和内存开销;对于小型数组,或本来就在使用列表的代码,这种方法通常最方便。

本节中的代码以及显示的标签或输出仍为英文。

import numpy as np

values = np.array([10, 20, 30, 20])
items = values.tolist()
target = 20
index = items.index(target) if target in items else None
print(index)

成员检查会在找不到值时明确返回 None;如果值不存在,直接调用 items.index(target) 则会引发 ValueError。成员检查和查找都会各自扫描一次列表,因此只查找一次时,也可以在 list.index() 外捕获 ValueError。

使用循环实现自定义逻辑

如果需要对每个元素执行难以用 NumPy 向量化条件表达的自定义测试,循环会很有用。先将结果初始化为表示未找到的值,然后在首次匹配时立即停止。

本节中的代码以及显示的标签或输出仍为英文。

import numpy as np

values = np.array([12, 15, 18, 21])
index = None

for position, value in enumerate(values):
    if value % 2 == 0 and value > 12:
        index = position
        break

print(index)

循环会逐个检查元素,并在找到同时满足两个条件的第一个值时退出。对于简单的相等性检查,使用 NumPy 掩码通常更简洁;当匹配规则需要自定义分支或状态时,再使用循环。

处理未匹配项、重复值和数组维度

根据任务选择合适的结果形式:

  • 对于一维数组中的第一个匹配项,使用 np.where() 或 np.nonzero() 获取位置,先检查是否至少有一个匹配项,再选取第一个位置。
  • 若要获取所有匹配项,请保留完整的索引数组。重复值会产生多个位置;如果需要全部位置,就不要只选取 [0]。
  • 对于二维数组,np.where(matrix == target) 会返回 (row_indices, column_indices)。对应位置的元素组成坐标对。例如,(rows[0], columns[0]) 是第一个匹配项的行和列,而不是一个扁平索引。
  • 如果确实需要多维数组中的扁平位置,请先展平数组,再在展平后的值中查找。需要时,可用 np.unravel_index() 将该扁平位置转换回坐标。
  • 对于非空且全为 False 的掩码,np.argmax() 会返回 0,但这个位置不代表存在匹配项。如果掩码为空,np.argmax() 则会引发 ValueError。上面的防护表达式会先检查 np.any(mask),因此无论掩码中没有 True 值还是掩码为空,都会返回 None。

对于常见的数值数组查找,需要第一个或全部匹配项时,np.where() 都是直接的选择。若要获取相同的 True 条件位置,可以使用 np.nonzero();对布尔掩码使用 np.argmax() 前应先检查;已经适合使用 Python 列表时可选 list.index();需要自定义匹配规则时则可使用循环。