【问题标题】:Index array using array of unique values使用唯一值数组的索引数组
【发布时间】:2020-11-12 12:54:42
【问题描述】:

我有三个数组,这样:

Data_Arr = np.array([1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5])
ID_Arr = np.array([1, 2, 3, 4, 5])
Value_Arr = np.array([0.1, 0.6, 0.3, 0.8, 0.2])

我想使用 ID 中的索引位置创建一个具有 Data 维度的新数组,但其中每个元素都来自 Values。到目前为止,我有这个循环,但它非常慢,因为我的数据数组非常大:

out = np.zeros_like(Data_Arr, dtype=np.float)

for i in range(len(Data_Arr)):
    out[i] = Values_Arr[ID_Arr==Data_Arr[I]]

是否有更 Pythonic 的方式来执行此操作并避免此循环(不必使用 numpy)?

实际数据如下:

Data_Arr = [ 852116  852116  852116 ... 1001816 1001816 1001816]
ID_Arr = [ 852116  852117  852118 ... 1001814 1001815 1001816]
Value_Arr = [1.5547194 1.5547196 1.5547197 ... 1.5536859 1.5536858 1.5536857]

形状是:

Data_Arr = (4021165,)
ID_Arr = (149701,)
Value_Arr = (149701,)

【问题讨论】:

  • 我不会提供这个作为答案,因为它使用更多内存并且可能不会更快,但我注意到d = dict(zip(ID_Arr, Value_Arr)); print([d[i] for i in Data_Arr]) 将是等效的(尽管不使用 numpy)。跨度>

标签: python numpy loops indexing


【解决方案1】:

看起来像你想要的:

out = Value_Arr[ID_Arr[Data_Arr - 1] - 1]

请注意,- 1 是因为 Python/Numpy 是基于 0 的索引。

【讨论】:

  • 这在一般情况下不起作用 - 它假设ID_Arr 值是从 1 开始的整数序列。
【解决方案2】:

由于ID_Arr已排序,我们可以直接使用np.searchsorted并索引Value_Arr结果:

Value_Arr[np.searchsorted(ID_Arr, Data_Arr)]
array([0.1, 0.1, 0.1, 0.6, 0.6, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.8, 0.8,
       0.2, 0.2, 0.2])

如果 ID_Arr 未排序(注意:如果可能存在超出范围的索引,我们应该删除它们,请参阅 divakar 的回答):

s_ind = ID_Arr.argsort()
ss = np.searchsorted(ID_Arr, Data_Arr, sorter=s_ind)
out = Value_Arr[s_ind[ss]]

检查 alaniwi 建议的数组:

Data_Arr = np.array([1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5])
ID_Arr = array([2, 1, 3, 4, 5])
Value_Arr = np.array([0.6, 0.1, 0.3, 0.8, 0.2])

out_op = np.zeros_like(Data_Arr, dtype=np.float)
for i in range(len(Data_Arr)):
    out_op[i] = Value_Arr[ID_Arr==Data_Arr[i]]

s_ind = ID_Arr.argsort()
ss = np.searchsorted(ID_Arr, Data_Arr, sorter=s_ind)
out_answer = Value_Arr[s_ind[ss]]

np.array_equal(out_op, out_answer)
#True

【讨论】:

  • 你能做一个不依赖于ID_Arr被排序的方法吗?例如,如果您以相同的方式置换ID_ArrValue_Arr(例如,在两种情况下交换前两个元素),则不应更改结果。
  • 当我尝试使用已按所述排列的列表时,输出仍然与问题中的代码不一致。
  • 这是使用排序 ID_Arr 的顺序进行搜索。因此对于无序的ID_Arr 产生相同的输出。如果你改Value_Arr,当然输出不一样了,我们是用searchsorted的结果来索引这个数组@alaniwi
  • 我交换了两个数组的前两个元素:ID_Arr = array([2, 1, 3, 4, 5])Value_Arr = array([0.6, 0.1, 0.3, 0.8, 0.2])。有问题的代码仍然给出array([0.1, 0.1, 0.1, 0.6, 0.6, ...]),但你的给出了`array([0.6, 0.6, 0.6, 0.1, 0.1, ...])。
  • @yatu 你需要用argsort() 索引我想。
【解决方案3】:

基于this post 的方法,以下是改编版。

方法#1

# https://stackoverflow.com/a/62658135/ @Divakar  
a,b,invalid_specifier = ID_Arr, Data_Arr, 0

sidx = a.argsort()
idx = np.searchsorted(a,b,sorter=sidx)

# Remove out of bounds indices as they wont be matches
idx[idx==len(a)] = 0

# Get traced back indices corresponding to original version of a
idx0 = sidx[idx]

# Mask out invalid ones with invalid_specifier and return
out = np.where(a[idx0]==b, Values_Arr[idx0], invalid_specifier)

方法#2

基于查找 -

# https://stackoverflow.com/a/62658135/ @Divakar    
def find_indices_lookup(a,b,invalid_specifier=-1):
    # Setup array where we will assign ranged numbers
    N = max(a.max(), b.max())+1
    lookup = np.full(N, invalid_specifier)

    # We index into lookup with b to trace back the positions. Non matching ones
    # would have invalid_specifier values as wount had been indexed by ranged ones
    lookup[a] = np.arange(len(a))
    indices  = lookup[b]
    return indices                     

idx = find_indices_lookup(ID_Arr, Data_Arr)
out = np.where(idx!=-1, Values_Arr[idx], 0)

更快/更简单的变体

一个简化的并且希望更快的版本是直接查找值 -

a,b,invalid_specifier = ID_Arr, Data_Arr, 0

N = max(a.max(), b.max())+1
lookup = np.zeros(N, dtype=Values_Arr.dtype)
lookup[ID_Arr] = Values_Arr
out = lookup[Data_Arr]

如果ID_Arr 中的所有值都保证在Data_Arr 中,我们可以使用np.empty 代替np.zeros 进行数组赋值,从而获得进一步的性能。提升。

【讨论】:

    猜你喜欢
    • 2017-08-03
    • 1970-01-01
    • 2016-07-14
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-16
    • 1970-01-01
    相关资源
    最近更新 更多