如何查找重叠列/行的集合

42 阅读3分钟

给定一个 2D 数组,其中列被划分为几个集合。为了简单起见,我们可以假设数组包含如下整数值:

np.random.randint(3, size=(2, 10))

# 列索引:
#       0  1  2  3  4  5  6  7  8  9                      
array([[0, 2, 2, 2, 1, 1, 0, 1, 1, 2],
       [1, 1, 0, 1, 1, 0, 2, 1, 1, 0]])

作为列索引分区的一个例子,我们可以选择以下内容:

# 分区前面的数组的列索引:

my_partition['first']  = [0,1,2]
my_partition['second'] = [3,4]
my_partition['third']  = [5,6,7]
my_partition['fourth'] = [8, 9]

我想找到具有相同值的列的列索引集合组。在上面的示例中,这些组的一些示例是:

# 以下集合包括具有值 [2,0]^T 的公共列向量的索引
group['a'] = ['first', 'fourth'] 

# 以下集合包括具有值 [1,1]^T 的公共列向量的索引
group['b'] = ['second', 'third', 'fourth'] 

我对解决此问题的方法感兴趣,该方法适用于包含实值(例如,值 1.0/2 和 1.0/2 相同,即 1.0/2 == 1.0/2 返回 True)的数组。我知道浮点精度可能存在限制,因此为了简单起见,我将此问题分为两个步骤:

  • 假设两列相同,如果值相同
  • 假设两列相同,如果值彼此接近(例如,向量差低于阈值)

我试图概括在前面的线程中的解决方案,但我不知道它是否直接适用。我认为它适用于第一个问题(列中完全相同的值),但对于第二个问题,我们可能需要“更大的船”。

2、解决方案 如果要从列的集合中创建一个集合样式的数据结构,这里有一种方法(我确定对于较大的数据,还有更有效的方法):

group = {}
for i in range(array.shape[1]):
    tup = tuple(array[:,i])
    if tup in group.keys():
        group[tup].append(i)
    else:
        group[tup] = [i]

为 array 示例执行时给出:

In [132]: group
Out[132]:
{(0, 1): [0],
 (0, 2): [6],
 (1, 0): [5],
 (1, 1): [4, 7, 8],
 (2, 0): [2, 9],
 (2, 1): [1, 3]}

由于 numpy.ndarray(比如列表)不可哈希,因此列本身不能作为字典键。我选择只使用列的元组等价物,但还有许多其他选择。 此外,我假设组希望以列表形式列出列索引。如果这确实如此,您可以考虑使用 defaultdict 而不是常规字典。但您还可以使用许多其他容器来存储列索引。 更新 我相信我更好地理解了问题的要求:给定一组任意预定义的列组,如何确定给定的两个组是否包含一个公共列。 如果我们假设您已经在我的答案中构建了类似集合的结构,您可以查看这两个组,查看它们的组成列,并询问是否有任何列出现在集合词典的相同部分: 假设我们定义:

my_partition['first']  = [0,1,2]
my_partition['second'] = [3,4]
my_partition['third']  = [5,6,7]
my_partition['fourth'] = [8, 9]

定义一个助手来回溯用作集合结构键的列。

# 取第 0 个元素,列索引应该只属于一个子集。
get_key = lambda x: [k for k,v in group.iteritems() if x in v][0]

使用迭代器

import itertools

打印出每对组之间的公共列。

for pair_x, pair_y in itertools.combinations(my_partition.keys(), 2):
    print pair_x, pair_y, (set(map(get_key, my_partition[pair_x])) &
                           set(map(get_key, my_partition[pair_y])))

每当它不是空集合时,这意味着两个组之间有一些公共列。 为您的问题执行:

In [163]: for pair_x, pair_y in itertools.combinations(my_partition.keys(), 2):
    print pair_x, pair_y, set(map(get_key, my_partition[pair_x])) & set(map(get_key, my_partition[pair_y]))
   .....:
second fourth set([(1, 1)])
second third set([(1, 1)])
second first set([(2, 1)])
fourth third set([(1, 1)])
fourth first set([(2, 0)])
third first set([])