【问题标题】:Is there a way to find out if A is a submatrix of B?有没有办法找出A是否是B的子矩阵?
【发布时间】:2014-11-12 21:14:11
【问题描述】:

我给引号是因为我的意思是例如:

B = [[1,2,3,4,5],
     [6,7,8,9,10],
     [11,12,13,14,15],
     [16,17,18,19,20]]

假设我们选择第 2,4 行和第 1,3 列,交叉点会给我们

A = [[6,8],
     [16,18]]

我的问题是假设我有 A 和 B,有没有办法可以找出从 B 中选择哪些行和列来给 A?

顺便说一句,如果你能在 python/numpy 中给出答案,那将是最好的。但只用数学或其他编程语言也可以。

【问题讨论】:

  • [[6,8,9],[16,18,19]] 是一个有效的子矩阵吗? (换句话说,您是在寻找每个轴上的索引列表,还是只寻找开始/停止/步进切片?)
  • 另外,我们是否应该假设您可以找出明显的蛮力解决方案,所以不值得一提(至少没有争论没有更有效的方法)?
  • 你认为矩阵A中的行/列可以重复吗?您是否假设行和列在BA 中以相同的顺序出现?
  • 你真的不需要引号,因为你在这里描述的实际上叫做submatrix

标签: python algorithm math numpy matrix


【解决方案1】:

这是一个非常难的组合问题。实际上 Subgraph Isomorphism Problem 可以简化为您的问题(如果矩阵 A 只有 0-1 个条目,您的问题正是子图同构问题)。已知此问题是 NP 完全问题。

这是一个递归回溯解决方案,它比暴力破解所有可能的解决方案要好一些。请注意,在最坏的情况下,这仍然需要指数级的时间。但是,如果您假设存在解决方案并且不存在歧义(例如,B 中的所有条目都是不同的),则可以在线性时间内找到解决方案。

def locate_columns(a, b, offset=0):
    """Locate `a` as a sublist of `b`.

    Yields all possible lists of `len(a)` indices such that `a` can be read
    from `b` at those indices.
    """
    if not a:
        yield []
    else:
        positions = (offset + i for (i, e) in enumerate(b[offset:])
                     if e == a[0])
        for position in positions:
            for tail_cols in locate_columns(a[1:], b, position + 1):
                yield [position] + tail_cols


def locate_submatrix(a, b, offset=0, cols=None):
    """Locate `a` as a submatrix of `b`.

    Yields all possible pairs of (row_indices, column_indices) such that
    `a` is the projection of `b` on those indices.
    """
    if not a:
        yield [], cols
    else:
        for j, row in enumerate(b[offset:]):
            if cols:
                if all(e == f for e, f in zip(a[0], [row[c] for c in cols])):
                    for r, c in locate_submatrix(a[1:], b, offset + j + 1, cols):
                        yield [offset + j] + r, c
            else:
                for cols in locate_columns(a[0], row):
                    for r, c in locate_submatrix(a[1:], b, offset + j + 1, cols):
                        yield [offset + j] + r, c

B = [[1,2,3,4,5], [6,7,8,9,10], [11,12,13,14,15], [16,17,18,19,20]]
A = [[6,8], [16,18]]

for loc in locate_submatrix(A, B):
    print loc

这将输出:

([1, 3], [0, 2])

【讨论】:

  • 但是当B = [[1,6,3,8,5], [6,7,8,9,10], [11,12,13,14时不起作用,15], [16,17,18,19,20]]
  • 你保留A 还是[[6,8], [16,18]]?在这种情况下,A 不是B 的子矩阵,并且程序不输出任何内容。这是预期的输出。
  • @Thibaut 如果你取B的第二和第四行和列,它实际上形成了一个子矩阵。
【解决方案2】:

如果您只想知道从 B 中选择哪些行和列来给 A 并且不关心效率这里是一种将结果存储在数组中的蛮力方式res res[N] 告诉所有位置B 中的 A[N]。即使 A[N] 存在于 B 的多个位置也可以工作。

B = [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20]]
A = [[6,8], [16,18]]
res = []

for subsetIndex, subset in enumerate(A):
    k = []
    res.append(k)
    for supersetIndex, superset in enumerate(B):
        loc = []
        try:
            loc = [(supersetIndex, superset.index(item)) for item in subset]
            k.append(loc)
            print A[subsetIndex], "is at ", loc, "in B"
        except ValueError:
            pass
print res

输出:

[6, 8] is at  [(1, 0), (1, 2)] in B
[16, 18] is at  [(3, 0), (3, 2)] in B
result =  [[[(1, 0), (1, 2)]], [[(3, 0), (3, 2)]]]

【讨论】:

    【解决方案3】:

    矩阵中的所有/大部分值是否唯一 IE:它们仅在矩阵 B 中出现一次?

    值越独特,对子图同构 (SI) 的改进就越好。如果所有值都是唯一,那么您可以对每个值进行反向查找以确定它的行/列对,合并行和列列表(单独)。

    结果是一个简单的O(N) 算法,其中N = number of rows * number of columns。当然,值越不唯一,需要检查的误报就越多,越接近 SI,事情就越不简单。

    【讨论】:

      【解决方案4】:

      这里有一个蛮力解决方案,如果你只需要这样的话:

      rows = [i for aa in A for i,bb in enumerate(B) if np.in1d(aa, bb).all()]
      cols = [i for aa in A.T for i,bb in enumerate(B.T) if np.in1d(aa, bb).all()]
      
      submatrix = B[np.ix_(rows, cols)]
      

      它检查A 的每一行与B 的每一行,以确保子矩阵的所有元素都存在。然后,它对列执行相同的操作。

      您可以通过将其限制为仅相关行来加快列查找部分:

      cols = [i for aa in A.T for i,bb in enumerate(B[rows].T) if np.equal(aa, bb).all()]
      

      【讨论】:

      • 等一下......它实际上并没有检查找到的元素是否在正确的位置,是吗?
      • 没错,它只是检查它们是否存在。如果您需要处理重复的元素,此方法将中断。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-03
      • 2018-10-19
      • 2018-02-05
      相关资源
      最近更新 更多