【问题标题】:Finding all segments members of four sets intersections (ala Venn diagram)查找四组交点的所有段成员(ala 维恩图)
【发布时间】:2015-08-25 12:52:03
【问题描述】:

我有四组数据:

A=range(10,20) 
B=range(5,17) 
C=range(15,25) 
D=range(18,30)
sets = [A, B, C, D]

我想要做的是获取可以 被视为在这里获取了维恩图的所有部分(这是完整的案例):

对于上面的示例,分区填充如下:

()  ----> set()
('A',)  ----> set()
('B',)  ----> {8, 9, 5, 6, 7}
('C',)  ----> set()
('D',)  ----> {25, 26, 27, 28, 29}
('A', 'B')  ----> {10, 11, 12, 13, 14}
('A', 'C')  ----> {17}
('A', 'D')  ----> set()
('B', 'C')  ----> set()
('B', 'D')  ----> set()
('C', 'D')  ----> {24, 20, 21, 22, 23}
('A', 'B', 'C')     ----> {16, 15}
('A', 'B', 'D')     ----> set()
('A', 'C', 'D')     ----> {18, 19}
('B', 'C', 'D')     ----> set()
('A', 'B', 'C', 'D')    ----> set()

这些是预期的答案。

我被下面的代码卡住了,它只能找到必须的交集 存在于所有给定的集合中:

# only gives ACD members
test = [tuple([A[0],A[-1]]), tuple([C[0],C[-1]]), tuple([D[0],D[-1]])]
starts, ends = zip(*test)
result = range(max(starts), min(ends) + 1)
# Gives 18,19

有什么办法呢? 请注意,我对绘制图表不感兴趣。 我关心的是获得每个细分市场的成员。

【问题讨论】:

  • 你期望什么输出?
  • 交集为零
  • @Pynchia:我知道。请仔细阅读OP。我的例子只能填写一些部分。
  • 好的,问题已经仔细阅读了,但我还是无法理解。请回答@andi 的评论并编辑您的帖子,以便其他人理解和使用该问题。
  • 您的示例代码也没有定义ranges

标签: python algorithm


【解决方案1】:

我在博客上写了关于这种问题的解决方案:http://paddy3118.blogspot.de/2013/07/set-divisionspartitions.html

您需要将 x..y 语法扩展为整数集,但如果这种形式的输出对您有用,那么您可能希望将输出与这种函数接口:http://rosettacode.org/wiki/Range_extraction

附:这是一个漂亮的维恩图。

【讨论】:

    【解决方案2】:

    最好使用具有线性复杂度(好吧,加上输出的长度)而不是指数的扫描线算法。

    A=range(10,20) 
    B=range(5,17) 
    C=range(15,25) 
    D=range(18,30)
    sets = [A, B, C, D]
    import string
    events = []
    for letter, set_ in zip(string.ascii_uppercase, sets):
        events.append((set_.start, True, letter))
        events.append((set_.stop, False, letter))
    events.sort()
    intersection = set()
    intersections = []
    last_t = None
    for t, insert, letter in events:
        if t != last_t and intersection:
            intersections.append((''.join(sorted(intersection)), range(last_t, t))) 
        last_t = t
        if insert:
            intersection.add(letter)
        else:
            intersection.remove(letter)
    print(intersections)
    

    【讨论】:

    • 谢谢。但我得到这个错误:'list' object has no attribute 'start' 此外,我们还需要剩余的非相交部分。例如:B=5,6,7,8,9
    【解决方案3】:
    import itertools
    
    def powerset(iterable):
        "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
        s = list(iterable)
        return itertools.chain.from_iterable(itertools.combinations(s, r) for r in range(len(s)+1))
    
    A = set(range(10,20)) 
    B = set(range(5,17)) 
    C = set(range(15,25)) 
    D = set(range(18,30))
    
    titles = (partition for partition in powerset(['A', 'B', 'C', 'D']))
    source = (partition for partition in powerset([A, B, C, D]))
    
    for elt in (zip(titles, source)):
        try:
            res = elt[1][0]
            for el in elt[1]:
                res.intersection(el)
        except IndexError:
            pass
        print(elt[0], ' = ', res)
    

    输出 = 每组之间的交集

    ()  =  {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}
    ('A',)  =  {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
    ('B',)  =  {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
    ('C',)  =  {15, 16, 17, 18, 19, 20, 21, 22, 23, 24}
    ('D',)  =  {18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}
    ('A', 'B')  =  {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
    ('A', 'C')  =  {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
    ('A', 'D')  =  {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
    ('B', 'C')  =  {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
    ('B', 'D')  =  {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
    ('C', 'D')  =  {15, 16, 17, 18, 19, 20, 21, 22, 23, 24}
    ('A', 'B', 'C')  =  {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
    ('A', 'B', 'D')  =  {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
    ('A', 'C', 'D')  =  {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
    ('B', 'C', 'D')  =  {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
    ('A', 'B', 'C', 'D')  =  {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
    

    【讨论】:

    • 谢谢,但我们还需要剩余的非相交部分。例如:B=5,6,7,8,9
    • 注意,我会再试一次。
    【解决方案4】:

    这里是: 输出是专门属于每个分区的元素集合。它适用于任意数量的集合。

    import itertools
    
    def intersect(d):
        """
        d is an iterable collection of sets or frozensets
        returns the intersection of the sets in d"
        """
        res = set()
        try:
            res = set(d[0])
        except IndexError:
            pass
        for elt in d:
            elt = set(elt)
            res = res.intersection(elt)
        return res
    
    A = frozenset(range(10,20))
    B = frozenset(range(5,17))
    C = frozenset(range(15,25))
    D = frozenset(range(18,30))
    
    titles = ('A','B','C','D')
    data = (A, B, C, D)
    
    dataset = set(data)
    titles_comb, data_comb = [], []
    
    for n in range(len(data)+1):
        titles_comb.append(list(itertools.combinations(titles, n)))
        data_comb.append(list(itertools.combinations(data, n)))
    
    for title, dat in zip(titles_comb, data_comb):
        for t, d in zip(title, dat):
            #intersect(d) = elements in the intersection of the sets (what we want, but has overlap)
            #complement = sets from data that were not used in intersect(d) (the overlap we want to discard)
            result = intersect(d)
            complement = dataset.difference(set(d))
            comp = set()
            for elt in complement:
                for e in elt:
                    comp.add(e)
    
            print(t, "\t---->", result.difference(comp))
    

    输出 = 每个分区的内容(不包括所有其他分区)

    ()  ----> set()
    ('A',)  ----> set()
    ('B',)  ----> {8, 9, 5, 6, 7}
    ('C',)  ----> set()
    ('D',)  ----> {25, 26, 27, 28, 29}
    ('A', 'B')  ----> {10, 11, 12, 13, 14}
    ('A', 'C')  ----> {17}
    ('A', 'D')  ----> set()
    ('B', 'C')  ----> set()
    ('B', 'D')  ----> set()
    ('C', 'D')  ----> {24, 20, 21, 22, 23}
    ('A', 'B', 'C')     ----> {16, 15}
    ('A', 'B', 'D')     ----> set()
    ('A', 'C', 'D')     ----> {18, 19}
    ('B', 'C', 'D')     ----> set()
    ('A', 'B', 'C', 'D')    ----> set()
    

    【讨论】:

    • 谢谢。但我认为您的代码中存在错误。我认为AB 应该是{10....17}
    • 我不这么认为,我认为您的手工计算有缺陷:结果集必须是不相交的(不能有任何重叠) - 在这种情况下,16 和 15 在 ABC 中,17 在AC,因此不能出现在 AB 中。
    【解决方案5】:

    您是否尝试过使用 python sets

    A = set(range(10,20))
    B = set(range(5,17))
    C = set(range(15,25))
    D = set(range(18,30))
    
    A.intersection(B).intersection(C)
    set([15, 16])
    
    A.intersection(B)
    set([10, 11, 12, 13, 14, 15, 16])
    
    A.intersection(C).intersection(D)
    set([18, 19])
    
    A.intersection(B).intersection(C).intersection(D)
    set()
    

    【讨论】:

    • 更好地使用A & B & C & D
    • 值得注意的是,如果所涉及的所有集合都是range(a,b) 类型,那么通过比较端点可以显着加快寻找交叉点的速度。当然,是否值得这样做取决于规模和时间限制。
    猜你喜欢
    • 2017-12-28
    • 1970-01-01
    • 2015-06-27
    • 1970-01-01
    • 1970-01-01
    • 2023-02-16
    • 1970-01-01
    • 2015-10-11
    • 1970-01-01
    相关资源
    最近更新 更多