查找具有唯一列的数组中每一行的最小值

Find minimum for every row in array with unique columns

我需要找到数组中的行最小值,其中每个最小值都必须来自唯一的列。

np.min(arr, axis=1) 提供按行最小值,但可能包含多次相同的列。

例如,给定:

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

np.min(a, axis=1) 会输出:[4, 1, 7]

所有返回的最小值都来自第一列,但由于每列只能使用一次的限制,所需的输出将是 [5, 1, 9] 作为最佳分配:

1 是本例中的最小值,因此分配给第一列。 5 是可以分配给第二列的最佳最小值(因为第二行已被使用)。

我现在唯一的想法是使用某种递归来实现它(这很可能非常耗时,对吧?)。

您要查找的似乎是 N 个最小值,其中每个值的行和列索引都是唯一的(假设是 NxN 矩阵)。如果我们用它的初始坐标标记矩阵中的每个值,我们就可以 rear运行ge 它们而不会失去分辨它们来自哪里的能力。我不确定 numpy 中是否有使用自定义键进行排序的巧妙方法,所以这里有一个普通的 Python 解决方案,不需要递归或回溯:

def idx_matrix(matrix):
    # return 1-D array of matrix values in (row_idx, col_idx, val) format
    return [(r, c, val) for r, row in enumerate(matrix)
                        for c, val in enumerate(row)]

def find_minima(indexed_vals, limit=0):
    # return array of indexed matrix values whose row and col indexes are unique
    minima = []
    rows = set()
    cols = set()
    for row, col, val in indexed_vals:
        if row not in rows and col not in cols:
            minima.append((row, col, val))
            if limit and len(minima) == limit:
                # optional optimization if you want to break off early
                # after you've found a value for every row
                break
            rows.add(row)
            cols.add(col)
    return minima

def sort_by_val(indexed_vals):
    # return indexed_vals sorted by original matrix value
    return sorted(indexed_vals, key=lambda x: x[2])

def sort_by_row(indexed_vals):
    # return indexed_vals sorted by row index
    return sorted(indexed_vals, key=lambda x: x[0])

def strip_indices(indexed_vals):
    # return a 1-D array with row and col index removed
    return [v[2] for v in indexed_vals]

def find_minima_by_row(matrix):
    # put it all together
    indexed = idx_matrix(matrix)
    indexed = sort_by_val(indexed)
    minima = find_minima(indexed)
    minima = sort_by_row(minima)
    return strip_indices(minima)

matrix = [[4, 5, 6],
          [1, 2, 3],
          [7, 8, 9]]
results = find_minima_by_row(matrix)
print(f'{results=}')

matrix = [[20, 17,  5, 13, 19],
          [11, 22,  8,  4,  9],
          [ 0, 10,  2, 16, 23],
          [ 1, 24, 21, 15, 14],
          [ 3, 12,  6,  7, 18]]
results = find_minima_by_row(matrix)
print(f'{results=}')
results=[5, 1, 9]
results=[5, 4, 0, 14, 12]

这个 运行 在我的工作站上用 2000x2000 矩阵在大约 4 秒内完成。您可以就地进行排序以提高 space 效率。

如果输入中有重复值,我也看不出为什么这不起作用。

使用 numpy 执行上述操作的更简单方法(可能不会更快),如果您知道数组值的上限:

# matrix is a numpy 2-D array, k is some arbirtary large value
mapping = [None]*matrix.shape[0] # row-column mapping for minimum value
tmp = matrix.copy()
for i in range(matrix.shape[0]):
        u, v = divmod(tmp.argmin(), tmp.shape[1])
        mapping[u]=v
        tmp[u,:]=k
        tmp[:,v]=k