【问题标题】:Lookup table using 2 columns to identify rows使用 2 列来识别行的查找表
【发布时间】:2018-04-04 09:33:25
【问题描述】:

我有一个 xy 坐标的 numpy 查找表,其中列 0=xa、1=ya、2=xb、3=yb。我正在尝试使用 xa 和 ya (cols 0 & 1) 作为能够查找 xb 和 yb (cols 2 & 3) 的元素对,它们是我想要使用的实际 xy 坐标。

lookup=
[[0,    0,  0,      0]
[2,     0,  1.98,   -0.01]
[4,     0,  3.99,   -0.01]
[6,     0,  6.03,   -0.01]
[8,     0,  8.02,   -0.03]
[10,    0,  9.98,   -0.01]
[12,    0,  11.99,  0]
[14,    0,  13.99,  0]
[0,     1,  -0.03,  0.88]
[2,     1,  1.95,   0.86]
[4,     1,  3.97,   0.85]
[6,     1,  5.97,   0.87]
[8,     1,  7.96,   0.86]
[10,    1,  9.95,   0.92]
[12,    1,  11.95,  0.92]
[14,    1,  13.97,  0.87]]

我有一个表格,其中包含 x 和 y 位置的数据,格式为 xa ya,我希望使用查找表将其更改为 xb yb:

gridloc=
[[6,    0]
 [8,    0]
 [8,    0]
 [10,   0]
 [8,    1]
 [10,   1]
 [12,   1]
 [14,   1]

所以我希望结果是这样的:

newloc=
[[6.03,   -0.01]
 [8.02,   -0.03]
 [8.02,   -0.03]
 [9.98,   -0.01]
 [7.96,   0.86]
 [9.95,   0.92]
 [11.95,  0.92]
 [13.97,  0.87]]

我尝试使用它来尝试创建字典,但出现错误:

mapping = dict(zip(lookup[:,0:2], range(len(lookup))))

Traceback (most recent call last):

  File "<ipython-input-12-528fb6616ce0>", line 1, in <module>
    mapping = dict(zip(lookup[:,0:2], range(len(lookup))))

TypeError: unhashable type: 'numpy.ndarray'

请问大家有什么建议吗?我的表应该首先放在 numpy 中吗? dict是解决问题的方法吗?

【问题讨论】:

    标签: python python-3.x numpy lookup lookup-tables


    【解决方案1】:

    这是一种 Numpythonic 方法:

    In [89]: mask = np.logical_and(gridloc[:,0] == lookup[:,None,0], gridloc[:,1] == lookup[:,None, 1])
    
    In [90]: ind = np.where(mask)[0]
    
    In [91]: lookup[ind, 2:]
    Out[91]: 
    array([[ 6.030e+00, -1.000e-02],
           [ 8.020e+00, -3.000e-02],
           [ 8.020e+00, -3.000e-02],
           [ 9.980e+00, -1.000e-02],
           [ 7.960e+00,  8.600e-01],
           [ 9.950e+00,  9.200e-01],
           [ 1.195e+01,  9.200e-01],
           [ 1.397e+01,  8.700e-01]])
    

    【讨论】:

    • 这很好,尽管值得注意的是它需要二次空间(或者,更具体地说,O(len(gridloc) * len(lookup)) 空间)。
    • @jdehesa 你说什么都没有是什么意思?值得什么?你能详细说明一下吗?我假设您的意思是就内存使用而言,如果是这样,那么在大多数情况下,您必须放弃以换取在运行时获得性能。由于内存使用在这里不是一个关键问题,因此我没有提出基于生成器的方法,它比这种矢量化方法慢得多。
    • 我所说的“值得注意”是指它是一个需要考虑的因素。如果 gridloclookup 各有 100k 行,这可能不是一个可行的选择。我并不是说这使它成为一个糟糕的答案,它可能是大多数类似情况下的最佳选择(这就是我赞成它的原因),但如果一个人有很大的数组,可能有必要诉诸不同的东西,即使它是效率较低。
    • @jdehesa 你是对的,这实际上是一个显而易见的事实。您还可以假设许多其他的可能性,一开始可能看起来微不足道,但可以很容易地证明,如果不照顾它们,它们可能会造成非常巨大的损害。其中之一是项目的大小,默认情况下是float64。尽管如此,由于我描述的所有原因,我的观点是在这种情况下不要使用确定的动词。
    • 我无法让它在我更大的现实生活示例中工作,所以我无法对此投票,抱歉
    【解决方案2】:

    一种选择是使用 Pandas 索引功能:

    import numpy as np
    import pandas as pd
    
    lookup = np.array(
        [[0,    0,  0,      0],
         [2,     0,  1.98,   -0.01],
         [4,     0,  3.99,   -0.01],
         [6,     0,  6.03,   -0.01],
         [8,     0,  8.02,   -0.03],
         [10,    0,  9.98,   -0.01],
         [12,    0,  11.99,  0],
         [14,    0,  13.99,  0],
         [0,     1,  -0.03,  0.88],
         [2,     1,  1.95,   0.86],
         [4,     1,  3.97,   0.85],
         [6,     1,  5.97,   0.87],
         [8,     1,  7.96,   0.86],
         [10,    1,  9.95,   0.92],
         [12,    1,  11.95,  0.92],
         [14,    1,  13.97,  0.87]])
    gridloc = np.array(
        [[6,    0],
         [8,    0],
         [8,    0],
         [10,   0],
         [8,    1],
         [10,   1],
         [12,   1],
         [14,   1]])
    
    idx = pd.MultiIndex.from_arrays([lookup[:, 0], lookup[:, 1]], names=('xa', 'ya'))
    df = pd.DataFrame(lookup[:, 2:], columns=('xb', 'yb'), index=idx)
    # This should work but is not implemented for multidimensional arrays
    # newloc = df.loc[gridloc].values
    # Converting to list of tuples works
    newloc = df.loc[list(map(tuple, gridloc))].values  # Add .copy() if need writing
    print(newloc)
    

    输出:

    [[  6.03000000e+00  -1.00000000e-02]
     [  8.02000000e+00  -3.00000000e-02]
     [  8.02000000e+00  -3.00000000e-02]
     [  9.98000000e+00  -1.00000000e-02]
     [  7.96000000e+00   8.60000000e-01]
     [  9.95000000e+00   9.20000000e-01]
     [  1.19500000e+01   9.20000000e-01]
     [  1.39700000e+01   8.70000000e-01]]
    

    【讨论】:

      【解决方案3】:

      首先,列表是可变的,不能用作字典键。这就是您需要将数据转换为元组的原因:

      mapping = dict(zip(map(tuple, lookup[:, :2]), map(tuple, lookup[:, 2:])))#
      mapping
      #{(0.0, 0.0): (0.0, 0.0),
      # (0.0, 1.0): (-0.029999999999999999, 0.88),
      # (2.0, 0.0): (1.98, -0.01),
      # (2.0, 1.0): (1.95, 0.85999999999999999),
      # (4.0, 0.0): (3.9900000000000002, -0.01),
      # (4.0, 1.0): (3.9700000000000002, 0.84999999999999998),
      # (6.0, 0.0): (6.0300000000000002, -0.01),
      # (6.0, 1.0): (5.9699999999999998, 0.87),
      # (8.0, 0.0): (8.0199999999999996, -0.029999999999999999),
      # (8.0, 1.0): (7.96, 0.85999999999999999),
      # (10.0, 0.0): (9.9800000000000004, -0.01),
      # (10.0, 1.0): (9.9499999999999993, 0.92000000000000004),
      # (12.0, 0.0): (11.99, 0.0),
      # (12.0, 1.0): (11.949999999999999, 0.92000000000000004),
      # (14.0, 0.0): (13.99, 0.0),
      # (14.0, 1.0): (13.970000000000001, 0.87)}
      

      现在要实现您的目标,您需要将gridloc 转换为元组列表,然后将mapping 映射到它:

      gridloc = list(map(mapping.get, map(tuple, gridloc)))
      gridloc
      #[(6.0300000000000002, -0.01),
      # (8.0199999999999996, -0.029999999999999999),
      # (8.0199999999999996, -0.029999999999999999),
      # (9.9800000000000004, -0.01),
      # (7.96, 0.85999999999999999),
      # (9.9499999999999993, 0.92000000000000004),
      # (11.949999999999999, 0.92000000000000004),
      # (13.970000000000001, 0.87)]
      

      附: Floating point math is not broken.

      【讨论】:

      • 是否也需要将值映射到tuples
      • @jpp 另一方面 - 你寻找元组然后你得到元组 - 对我来说看起来更漂亮:)
      • 我无法让它给出一个输出,只有一个地图对象。除了浮点数指针之外,我真的需要学习 Python 课程,而不是像以前那样在黑暗中磕磕绊绊
      • @georussell 您是否尝试过与gridloc = list(map(mapping.get, map(tuple, gridloc))) 编辑一样?
      • 错过了,但确实有效,谢谢。选择 Pandas 的答案只是因为让一个数组向前发展对我更有用
      猜你喜欢
      • 1970-01-01
      • 2012-09-11
      • 1970-01-01
      • 2013-01-15
      • 1970-01-01
      • 2018-01-14
      • 1970-01-01
      • 2020-02-22
      • 1970-01-01
      相关资源
      最近更新 更多