问题描述
我有一个 numpy 数组 T
,其行具有以下列结构:[x,y,value]
,其中 x、y、value 是整数。示例 T
数组如下所示:
[[1,4],[0,2,3],[1,7]]
此数据来自一个模型,其中第三列指定元组 (x,y)
的变量值。在模型中,此元组对应于值的标签。例如,我的标签 T_10
(下标 10
)的值为 4
,T_02
的值为 3
,T_12
的值为 {{1} }.
现在,我想交换一对标签。例如,我想用 7
替换所有标签 2
(反之亦然),分别为前面的例子得到 1
、T_20
和 T_01
.所以,这个新数据是
T_21
我的问题是我不知道如何让我的新数据看起来像这样:
U = [[2,?],1,[2,?]]
这个新数据应该遵循两条规则:
第一,它应该正确识别U = [[2,-3]
[0,-4],-7]]
的第一列和第二列T
与{{1}中的新(x,y)
相同的行}.对于 (x,y)
的每一行,如果 U
的有序对 U
,那么相应的 '?' (x,y) = (x,y)
的第三列中的值应该是 T
中的对应值。
第二:另一方面,如果 U
的 T
的 (x,y)
,那么它应该是相应的 {{1} }.
我的尝试涉及首先提取 U = (y,x)
的列,然后使用以下函数交换这对标签:
T
例如,我会将标签 value
与 T
交换,反之亦然,用于列 def swap_indices(a,pair):
for n,i in enumerate(a):
if i == pair[0]: # check whether a0's element is = swap element 1
a[n] = pair[1]
elif i == pair[1]:
a[n] = pair[0]
return a
和列 0
使用:
1
然后我遍历 x
的行数; y
:
pair = (0,1)
a0 = swap_indices(T[:,0],pair) # column x
a1 = swap_indices(T[:,1],pair) # column y
上面,我试图获取行的索引,其中 T
的 num_rows_of_T
= for k in range(num_rows_of_T):
temp = np.where((T[k,0] == a0[k]) & (T[k,1] == a1[k]) | ((T[k,0] == a1[k]) & (T[k,1] == a0[k])))
的 (x,y)
,或 U
的 (x,y)
1}} 个,共 T
个。然而,这是我陷入困境的地方。我不认为以上是正确的。此外,这种方法不会让我应用第二条规则,如果 (x,y)
,我取 U = (y,x)
的值的负数。我还尝试将 T
用于初学者(以获得无序对),但即使那样我也无法正确找到 T
的相应值。
基本上,我想找到与 (x,y) = (y,x)
中的新标签匹配的 set()
的 T
。我的数据很好,因为可能只存在一组可能的坐标,并且 value
的 T
和 U
之间总是存在双射映射(给定我的两个规则) .
有什么建议吗? 请根据需要帮助编辑问题。我很难问。
这是一个最小的工作示例:
(x,y)
使用@MadPhysicist 的答案的更多涉及示例:
T
上面给出了输出:
U
解决方法
您可以将算法归结为三个主要步骤:
- Txy 排序
- 在 Txy 中对 Uxy 进行二分搜索
- 二分查找 Txy 中剩余的 Uyx
合并结果显然是微不足道的。整个操作应该在 O(N log N)
时间内完全可行,因为这是每一步所需的时间。
由于 np.searchsorted
是第 2 步和第 3 步的主要候选者,假设您可以将前两列转换为唯一键。例如,假设在所有情况下都有 y <= y_max
,并且 y_max
有一个合理的界限,使得 x * y_max + y <= 2**32-1
对所有 x
。您可以在闲暇时使用 np.int64
或使用 x_max
代替 y_max
。
现在你这样做了:
def key(arr,m):
return arr[:,0] * m + arr[:,1]
y_max = T[:,:1].max(None) + 1
Tkey = key(T,y_max)
s = np.argsort(Tkey)
要查找 U
的哪些元素匹配:
Ukey = key(U,y_max)
i = np.searchsorted(Tkey,Ukey,sorter=s)
i[i == len(i)] -= 1 # cleanup indices that won't match anyway
mask = (Ukey == Tkey[s[i]])
现在找到反向索引。
U2key = key(U[~mask,1::-1],y_max)
j = np.searchsorted(Tkey,U2key,sorter=s)
由于映射是双射的,这一步只搜索保证存在的元素,不需要验证索引。
现在您可以组合索引。如果 U
还没有第三列,请添加一列:
U = np.concatenate((U,np.empty_like(T[:,:1])),axis=1)
使用我们计算的索引,提取您想要的 Tsort
元素:
U[mask,-1] = T[s[i[mask]],-1]
U[~mask,-1] = -T[s[j],-1]
现在,如果像 key
这样的映射不能工作,事情可能会更复杂一些。如果没有其他方法,请先尝试
def key(arr):
return arr[:,0] + 1j * arr[:,1]
复杂值将仅用作排序键,而不会用作其他任何东西。如果失败,您可能必须定义结构化数据类型并通过它查看您的数组以使搜索工作。你当然可以实现分层搜索,但我觉得这超出了这里的范围。
这是一个基于您的 T
的完整玩具示例,稍加修改的 U
在最后一列中同时显示正数和负数:
>>> T = np.array([[1,4],[0,2,3],[1,7]])
>>> U = np.array([[2,1,0],[2,0]])
>>> def key(arr,m):
... return arr[:,1]
>>> y_max = T[:,:1].max(None) + 1
>>> Tkey = key(T,y_max)
>>> s = np.argsort(Tkey)
>>> Ukey = key(U,y_max)
>>> i = np.searchsorted(Tkey,sorter=s)
>>> i[i == len(i)] -= 1 # cleanup indices that won't match anyway
>>> mask = (Ukey == Tkey[s[i]])
>>> U2key = key(U[~mask,y_max)
>>> j = np.searchsorted(Tkey,sorter=s)
>>> U[mask,-1]
>>> U[~mask,-1]
>>> print(U)
[[ 2 1 -7]
[ 1 0 4]
[ 2 0 -3]]