最值索引
对于一维数组(仅返回匹配到的第一个最值),argmax()和argmin()最常用。PS:如果输入的数组是多维的,也会先展平(flatten)转化为一维数组。
import numpy as np
# 最小值用np.argmin()
arr = np.array([3, 1, 4, 1, 5, 9, 2])
max_idx = np.argmax(arr)
print(max_idx) # 输出: 5 (值为9的索引)
print(arr[max_idx]) # 输出: 9
对于多维数组我推荐两种方法,其一是采用unravel_index() ,它的作用是将展平(flatten)后的索引转换为原始多维数组的坐标索引。
但该方法依然基于argmax()和argmin(),所以仅返回匹配到的第一个最值
import numpy as np
arr = np.array([[1, 5, 3],
[7, 2, 4]])
# 获取多维数组中的位置
max_idx_flat = np.argmax(arr)
max_idx_multi = np.unravel_index(max_idx_flat, arr.shape)
print(max_idx_multi) # 输出: (1, 0) 即第1行第0列
print(arr[max_idx_multi]) # 输出: 7
# 一步到位的方法
max_idx_multi = np.unravel_index(np.argmax(arr), arr.shape)
print(max_idx_multi) # (1, 0)
另外,我比较常用的是where() ,它可以处理多个最值,可以作为条件搜索。比如np.where((条件一) & (条件二)),&代表的是和条件,|代表的是与条件
import numpy as np
arr = np.array([[9, 1, 9],
[3, 9, 2]])
# 获取最值
max_value = np.max(arr)
# 建立mask = arr == max_value
all_max_idx = np.where(arr == max_value)
# np.where将最值对应的行列分开储存为数组
print(all_max_idx) # (array([0, 0, 1]), array([0, 2, 1]))
# 即 (0,0), (0,2), (1,1) 三个位置
# 转换为坐标列表
coords = list(zip(all_max_idx[0], all_max_idx[1]))
print(coords) # [(0, 0), (0, 2), (1, 1)]
一个复杂案例,我有一个无符号整数形数组labeled_array(标记了具有相同连通域的洼地)和浮点数数组arr_dem(代表高程数据),现在我要识别具有同一连通域的洼地中高程值最小的像元的空间位置。主要学习np.flatnonzero()和np.argwhere()
lowland_path = np.zeros_like(labeled_array)
# 数组中出现的值由小到大排序
unique_labels = np.unique(labeled_array)
# 提取其中的最大值
max_label = unique_labels.max() if unique_labels.size > 0 else 0
for i in tqdm(range(1, max_label + 1), '计算淹没路径点'):
mask = labeled_array == i
# 判断淹没是否为空np.all()和np.any()
if not np.any(mask):
continue
# 提取其中的最小值
min_val = arr_dem[mask].min()
# 返回最小值的行列坐标,是一个2列的数组,第一列代表行数,第二列代表列数
mask_coords = np.argwhere(mask)
# 读取展平后的数组中非零元素的索引
flat_indices = np.flatnonzero(arr_dem[mask] == min_val)
# 读取对应的行列值
result_coords = mask_coords[flat_indices]
# 更新结果数组
lowland_path[result_coords[:, 0], result_coords[:, 1]] = i
数组偏移
通过np.roll使数组中的元素沿着给定轴滚动,超出最后位置的元素将会滚动到第一个位置。
# 假设一个原始数组x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 经过 np.roll(x, 2) 后输出
# 因为没有指定axis,所以先进行展平,然后再向水平滚动2个位置
[8, 9, 0, 1, 2, 3, 4, 5, 6, 7]
# 假设一个原始数组x2:
[[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]]
# 经过 np.roll(x2, 1) 后输出:
# 同样先进行展平,然后再向水平滚动2个位置
[[9, 0, 1, 2, 3],
[4, 5, 6, 7, 8]]
# 经过 np.roll(x2, 1, axis=0) 后输出:
# 5列同时向垂直方向(行)滚动1个位置
array([[5, 6, 7, 8, 9],
[0, 1, 2, 3, 4]])
将其用于邻域坡度的快速计算,相比于遍历操作,性能可提升数倍。
arr_dem = arr_dem.copy()
valid_mask = (arr_dem > nodata)
neighbors = [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)]
all_slopes = []
padded = np.pad(arr_dem, 1, constant_values=nodata)
for dr, dc in neighbors:
# 在填充后的数组上滚动(1是pad的宽度)
shifted = np.roll(padded, dr, axis=0)
shifted = np.roll(shifted, dc, axis=1)
shifted_original = shifted[1:-1, 1:-1]
valid_pair = valid_mask & (shifted_original != nodata)
height_diff = arr_dem[valid_pair] - shifted_original[valid_pair]
pos_mask = height_diff > 0
height_diff = height_diff[pos_mask]