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

Posted

技术标签:

【中文标题】查找具有唯一列的数组中每一行的最小值【英文标题】:Find minimum for every row in array with unique columns 【发布时间】:2021-10-13 13:47:43 【问题描述】:

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

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 是可以分配给第二列的最佳最小值(因为第二行已被使用)。

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

【问题讨论】:

为什么期望的输出不是[4, 2, 9],或[6, 1, 8],或[5, 3, 7] 那些不是最佳分配。例如。 1 是此示例中的最小值,因此分配给第一列(而不是 2 或 3)。 5 是可以分配给第二列的最佳最小值(因为第二行已被使用)。 你的数组有多大(元素数量)? 平均约为 400x400,很少达到 2000x2000 我仍然不完全清楚问题陈述。我知道(1)你想要一个包含每行最小值的数组,除了每列只能使用一次; (2) 目标是找到最小的解决方案; (3) 您通过选择网格中的最小值来描述选择第一个数字(“首先在第一行中选择 1,因为 1 是网格中的最小值 [...]”)。但是输入[[4, 5, 6],[1, 2, 3],[7, 101, 100]] 呢?如果您总是在网格中选择最小的数字,您最终会得到[5,1,100] 的解,但答案[2,6,7] 的总和更小。 【参考方案1】:

您正在寻找的似乎是 N 个最小值,其中每个值的行和列索引都是唯一的(假设是 NxN 矩阵)。如果我们用它的初始坐标标记矩阵中的每个值,我们可以重新排列它们而不会失去判断它们来自哪里的能力。我不确定在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 秒内运行。你可以在适当的地方做一些更节省空间的事情。

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

【讨论】:

【参考方案2】:

如果您知道数组值的上限,则使用 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

【讨论】:

以上是关于查找具有唯一列的数组中每一行的最小值的主要内容,如果未能解决你的问题,请参考以下文章

在索引 0 为 0 的数组中查找非零最小值 C++

在 Pandas、Python 中查找具有相同第一列的所有行的最小值、最大值、平均值

PHP如何取二维数组中的某列的最大值和最小值?

查找2D数组C ++中每一行的最大值

获取二维数组中某一列的最小值

R获取矩阵中每一行的最小值,并返回行名和列名