【问题标题】:Mapping z's in numpy array A = [[x0, y0, z0], [x1, y1, z1]] for 3rd column of array B = [[x1, y1, ?], [x0, y0, ?]] based off matching (x,y)?在 numpy 数组 A = [[x0, y0, z0], [x1, y1, z1]] 中映射 z,用于数组 B = [[x1, y1, ?], [x0, y0, ?]] 的第三列匹配(x,y)?
【发布时间】:2021-04-23 03:52:46
【问题描述】:

我有一个 numpy 数组 T,其行具有以下列结构:[x, y, value],其中 x、y、值是整数。示例 T 数组如下所示:

[[1, 0, 4],
 [0, 2, 3],
 [1, 2, 7]]

此数据来自模型,其中第三列指定元组 (x, y) 的变量值。在模型中,这个元组对应于值的标签。例如,我的标签T_10(下标10)的值为4T_02 的值为3T_12 的值为7

现在,我想交换一对标签。例如,我想将所有标签2 替换为1(反之亦然),以分别获得前面示例的T_20T_01T_21。所以,这个新数据是

U = [[2, 0, ?],
     [0, 1, ?],
     [2, 1, ?]]

我的问题是我不知道如何使我的新数据看起来像这样:

U = [[2, 0, -3]
     [0, 1, -4],
     [2, 1, -7]]

这些新数据应遵循两条规则

首先,它应该正确识别T的行,其第一列和第二列(x, y)U中的新(x, y)相同。对于U 的每一行,如果(x, y) = (x, y)T 的有序对,那么适当的'?' U第三列的值应该是T的对应值。

第二:另一方面,如果(x, y)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 

例如,我将标签01 交换,反之亦然,列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)T(x, y)U = (y, x)T 的行的索引。然而,这是我卡住的地方。我不认为以上是正确的。此外,这种方法不会让我应用 第二条规则,如果 (x, y) = (y, x) 取负值,则为 T。我也尝试使用set() 作为初学者(以获得无序对),但即使那样我也无法正确找到T 的相应值。

基本上,我想找到与U 中的新标签匹配的Tvalues。我的数据很好,因为可能只存在一组可能的坐标,并且T(x,y)U 之间总是存在双射映射(给定我的两条规则)。

有什么建议吗? 请根据需要帮助编辑问题。我很难问。

这是一个最小的工作示例:

import numpy as np

# swap index labels if match swap pair
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
        
def find_valid_swaps(The1 = np.array([1, 0, -1, 1, 0, 1]), headers = np.array(['10', '20', '21', '30', '31', '32'])):
 
    num_indices = len(The1)
    T = np.zeros((num_indices,3)); U = T;
    
    # match format given for T in question
    for i in range(num_indices):
        T[i,:] = [int(list(headers[i])[0]), int(list(headers[i])[1]), The1[i]]
    
    pair = (0, 1) # label pair to swap
    a0 = swap_indices(T[:, 0], pair) # column 0 of U
    a1 = swap_indices(T[:, 1], pair) # column 1 of U
    
    # try to extract correct 'value' from T based on new labels in U
    for k in range(num_indices):
        temp = np.where((T[k, 0] == a0[k]) & (T[k, 1] == a1[k]) | ((T[k, 0] == a1[k]) & (T[k, 1] == a0[k])))
        print("temp",temp[0][0])
        U[k, :] = [a0[k], a1[k], T[temp[0][0], 2]] # here, I would finally create the new U matrix, applying both rules

    print(U)

find_valid_swaps()

使用@MadPhysicist 的答案的更多相关示例:

# swap index labels if match swap pair
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
    
def key(arr, m):
    return arr[:, 0] * m + arr[:, 1]
    
def find_valid_swaps(Thetas1 = np.array([1, 1, 0, 0, -1, -1]), Thetas2 = np.array([1, 0, -1, 1, 0, 1]), num_bands = 4, headers = np.array(['10', '20', '21', '30', '31', '32'])):
    
    import itertools # for permutations: https://stackoverflow.com/questions/40092474/get-all-pairwise-combinations-from-a-list
    
    if (Thetas1==Thetas2).all():
        print("Warning: Input sets of indices are equal to each other. Will check other possible permutations regardless.")
    else: 
        print("Input sets of indices are unique. Will proceed checking other viable permutations.")

    num_indices = len(Thetas1)
    
    T = np.zeros((num_indices,3))
    U = np.zeros((num_indices,3))
    
    for i in range(num_indices):
        T[i,:] = [int(list(headers[i])[0]), int(list(headers[i])[1]), Thetas2[i]]
    
    print("input T")
    print(T)
    
    pair = (2,3)
    a0 = swap_indices(T[:,0], pair) # column 1  
    a1 = swap_indices(T[:,1], pair) # column 2 
    
    
    for k in range(num_indices):
        U[k, :] = [a0[k], a1[k], 0] 

    # below code due to @MadPhysicist from https://stackoverflow.com/questions/67223782/mapping-zs-in-numpy-array-a-x0-y0-z0-x1-y1-z1-for-3rd-column-of-ar/67235030?noredirect=1#67235030
    
    y_max = T[:, 1].max() + 1
    Tkey = key(T, y_max)
    s = np.argsort(Tkey)

    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[mask, -1] = T[s[i[mask]], -1]
    U[~mask, -1] = -T[s[j], -1]
    
    print("reordered U")
    print(U)

上面给出了输出:

input T
[[ 1.,  0.,  1.]
 [ 2.,  0.,  0.]
 [ 2.,  1., -1.]
 [ 3.,  0.,  1.]
 [ 3.,  1.,  0.]
 [ 3.,  2.,  1.]]
reordered U
[[ 1.,  0.,  1.]
 [ 3.,  0.,  0.]
 [ 3.,  1., -1.]
 [ 2.,  0.,  1.]
 [ 2.,  1.,  0.]
 [ 2.,  3.,  1.]]

【问题讨论】:

  • SO 不支持 tex 格式。如果必须,请格式化为代码并使用类似 python 的伪代码。
  • 这个问题很清楚。
  • 我猜你已经有了TU 的前两列,并且只想在T 中搜索行U 以找到相应的行。我说的对吗?
  • 感谢您的建议。我已经相应地编辑了这个问题并提供了一个最小的工作示例。 @swag2198 是的,你是对的。这样的搜索将只产生一个直接查找(直到应用第二条规则)。
  • 您可以在示例数组中添加逗号吗?

标签: python arrays numpy indexing label


【解决方案1】:

您可以将您的算法归结为三个大步骤:

  1. Txy 排序
  2. 在 Txy 中对 Uxy 进行二进制搜索
  3. 对 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, 0, 4],
                  [0, 2, 3],
                  [1, 2, 7]])
>>> U = np.array([[2, 1, 0],
                  [1, 0, 0],
                  [2, 0, 0]])
>>> 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)

>>> 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[mask, -1] = T[s[i[mask]], -1]
>>> U[~mask, -1] = -T[s[j], -1]
>>> print(U)
[[ 2  1 -7]
 [ 1  0  4]
 [ 2  0 -3]]

【讨论】:

  • 好收获。 Tsort 是之前编辑的保留,这实际上是让我介绍 Tkeys 而不是直接排序 T 的东西。我现在修好了
  • @TribalChief。我添加了一个小示例供您使用(并帮助我确保我发布了工作代码:)。
  • @TribalChief。哪个排序不起作用?怎么没用?
  • @TribalChief。我在某处搞砸了索引。给我一点,我会弄清楚的。概念是合理的
  • @TribalChief。固定的。看看y_max 的新定义。我暗中依赖y.max() > x.max()。现在,我只取两列的最大值,瞧,所有的键都是唯一的。
猜你喜欢
  • 2019-12-05
  • 2018-08-01
  • 2015-09-22
  • 2011-12-20
  • 1970-01-01
  • 1970-01-01
  • 2011-11-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多