至少在“ x”列中包含非零值的最大行集

时间:2019-03-05 20:31:18

标签: python algorithm

对一个复杂但又简单的矩阵运算进行排序。我想查找并最大化行数,以使至少有x列,其中那些行所约束的矩阵都是1。

行本身不需要连续,列也不需要。并且矩阵假设所有行至少有x个行,因此,我没有删除任何没有最小x的行。

我的初始方法如下:进入第一行。查找前一个带有“ 1”的“ x”列。然后对于这些列,检查多少行也有1。跟踪我发现了多少行。从每一行开始执行此操作。

但是,这是行不通的,因为即使对于第一行,我也需要考虑所有不同的列组合,这些组合仍然为我提供最少x列中带有1的列,而不仅仅是第一列{ {1}}列。

为此,计算时间迅速耗尽。有没有一种有效的方法来解决这个问题?

我正在尝试使用python。

请考虑以下示例和x

这没有解决方案,因为最初删除了行1、3、5。然后,对于第2行和第4行,在两行中都没有3列。

enter image description here

但是在这里,第2行和第4行至少有3列,全为1。因此,这是一个解决方案,最大行数为 2

enter image description here

1 个答案:

答案 0 :(得分:1)

您似乎要描述的是对关联规则学习问题的改写,例如可以使用Apriori算法解决。

这里是一个快速示例,展示了该算法的基础。它可能需要一些改进,不确定是否有错误。

此外,它也不要求必须找到所有给出最少“ x”行的不同列组合。它仅使用'x'来更快地过滤所有解决方案,最终返回的解决方案是具有至少'x'行的最大列数。

from operator import itemgetter, or_
from itertools import combinations, starmap
from collections import Counter
from math import factorial


class Apriori:

    def __init__(self, input, x):
        self.input = input
        self.cols = len(input[0])
        self.rows = len(input)
        self.x = x

    def _get_freq_combs(self, comb):
        return sum(map(lambda row:
                       sum([bool(e) for i, e in enumerate(row)
                            if i in comb]) // len(comb), self.input))

    def _make_new_combs(self, combs, comb_size):
        candidates = Counter(map(frozenset,
                                 starmap(or_, combinations(combs, 2))))
        possible_candidate_freq = factorial(comb_size) // factorial(2) \
            // factorial(comb_size - 2)
        for c, f in candidates.items():
            if f == possible_candidate_freq:
                yield c

    def solve(self):
        """Returns a list of sets with the most common items, at least x."""
        freq = [self._get_freq_combs([i]) for i in range(self.cols)]

        most_freq = [{ind} for ind in range(self.cols) if freq[ind] >= x]
        comb_size = 2
        while most_freq:
            old_freq = most_freq
            most_freq = [c for c in self._make_new_combs(most_freq, comb_size)
                         if self._get_freq_combs(c) >= x]
            comb_size += 1
        return old_freq


if __name__ == '__main__':
    input = [[1, 0, 1, 0],
             [0, 1, 1, 0],
             [0, 1, 1, 1],
             [0, 0, 0, 1]]
    x = 2
    apriori = Apriori(input, x)
    print(apriori.solve())