创建具有标识符之间关系的数组



考虑以下玩具数组a

a = np.array([[1074279, 937077, 1445858, 1679465], 
[1074280, 1023600, 1679465, 937077],  
[1074281, 908450, 1932761, 1100360],  
[1074282, 1445858, 893656, 908183], 
[1074283, 1958030, 1932761, 1445858]])

第一列是标识符。

如何以显示标识符何时相关的方式转换数组 到另一个?如果两个标识符至少有一个共同点,则存在关系 列中的值2-a4

最终结果应该是下面b数组:

b = np.array([[1, 1, 0, 1, 1],
[1, 1, 0, 0, 0],
[0, 0, 1, 0, 1],
[1, 0, 0, 1, 1],
[1, 0, 1, 1, 1]])

这也许可以更好地理解如下:

1074279 1074280 1074281 1074282 1074283
1074279     1       1       0       1       1
1074280     1       1       0       0       0
1074281     0       0       1       0       1
1074282     1       0       0       1       1
1074283     1       0       1       1       1

我尝试(双重(循环元素以找到所有组合和 然后将其减少到所需的数组,但我无法正确处理。

外相等可以完成矢量化解决方案的工作 -

In [90]: np.equal.outer(a[:,1:],a[:,1:]).any(axis=(1,3)).view('i1')
Out[90]: 
array([[1, 1, 0, 1, 1],
[1, 1, 0, 0, 0],
[0, 0, 1, 0, 1],
[1, 0, 0, 1, 1],
[1, 0, 1, 1, 1]], dtype=int8)

解释

基本上,我们正在对所有行以及每行内与np.equal.outer(..)进行成对相等比较。相等比较是一个 4D 数组。因此,对于(m,n)形状的切片a[:,1:],将为我们提供形状(m,n,m,n)的相等比较数组。因此,我们ANY沿轴减小它 -13,给我们一个形状(m,m)的 2D 布尔数组,这是我们转换为 int 数组后的最终输出。

具有显式维度扩展的替代方案是 -

In [92]: (a[:,1:,None,None]==a[:,1:]).any(axis=(1,3)).view('i1')
Out[92]: 
array([[1, 1, 0, 1, 1],
[1, 1, 0, 0, 0],
[0, 0, 1, 0, 1],
[1, 0, 0, 1, 1],
[1, 0, 1, 1, 1]], dtype=int8)

因此,唯一的变化是我们正在为切片的第一个版本添加新轴,None/np.newaxis以创建 4D 版本。然后将其与原始 2D 版本进行比较,以得出 4D 相等比较布尔数组。

一个更简单的经典解决方案,易于理解:

def has_in_common(a1, a2):
"""
@param a1, a2: two input arrays
@returns True if a1 and a2 has at least one value in common, otherwise False
"""
for v1 in a1[1:]:
for v2 in a2[1:]:
if v1 == v2:
return True
return False

def relation_matrix(a):
"""
@param a: an input array
@returns m a matrix specifying the relationship between the rows of a
ex: a = [[1074279, 937077, 1445858, 1679465], 
[1074280, 1023600, 1679465, 937077],  
[1074281, 908450, 1932761, 1100360],  
[1074282, 1445858, 893656, 908183], 
[1074283, 1958030, 1932761, 1445858]]
m = [[1, 1, 0, 1, 1],
[1, 1, 0, 0, 0],
[0, 0, 1, 0, 1],
[1, 0, 0, 1, 1],
[1, 0, 1, 1, 1]]
more precisely
m =      1074279 1074280 1074281 1074282 1074283
1074279     1       1       0       1       1
1074280     1       1       0       0       0
1074281     0       0       1       0       1
1074282     1       0       0       1       1
1074283     1       0       1       1       1
"""
m = np.zeros((a.shape[0], a.shape[0]))
for i in range(len(a)):
for j in range(len(a)):
if has_in_common(a[i], a[j]):
m[i, j] = 1
return m.astype('int')

演示:

In [1]:relation_matrix(a)
Out[1]: 
array([[1, 1, 0, 1, 1],
[1, 1, 0, 0, 0],
[0, 0, 1, 0, 1],
[1, 0, 0, 1, 1],
[1, 0, 1, 1, 1]])

最新更新