Python 使用唯一值数组索引数组
我有三个阵列,这样:Python 使用唯一值数组索引数组,python,numpy,loops,indexing,Python,Numpy,Loops,Indexing,我有三个阵列,这样: 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中的索引位置创建一个新数组,该数组具有数据维度,但每个元素都来自值。到目前为止,我在循环中有这个数组,但它非常慢,因为我的数据数组非常大: out = np.
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中的索引位置创建一个新数组,该数组具有数据维度,但每个元素都来自值。到目前为止,我在循环中有这个数组,但它非常慢,因为我的数据数组非常大:
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]]
有没有一种更像python的方法来实现这一点并避免这个循环(不必使用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,)
看起来你想要:
out = Value_Arr[ID_Arr[Data_Arr - 1] - 1]
请注意,
-1
是由于Python/Numpy是基于0
的索引。由于ID\u Arr
是排序的,我们可以直接使用并索引Value\u 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\u Arr
进行排序(注意:如果可能存在越界索引,我们应该删除它们,请参阅divakar的答案):
使用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
根据来自的方法,以下是调整
方法#1
进近#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\u Arr
中的所有值都在Data\u Arr
中,我们可以使用np.empty
代替np.zero
进行数组赋值,从而获得更高的性能。boost.这在一般情况下不起作用——它假设ID\u Arr
值是从1开始的整数序列。您能否找到一种不依赖于排序的ID\u Arr
的方法?例如,如果以相同的方式排列ID\u Arr
和Value\u Arr
(例如,在两种情况下交换前两个元素),它不应该改变结果。当我尝试使用已按所述排列的列表时,输出仍然与问题中的代码不一致。这是使用将对已排序的搜索进行排序的顺序ID\u Arr
。因此,为无序的ID\u Arr
生成相同的输出。如果您更改Value\u Arr
,当然输出是不同的,我们使用searchsorted的结果来索引此数组@alaniwiI正在交换两个数组中每个数组的前两个元素:ID\u Arr=array([2,1,3,4,5])
和Value\u Arr=array([0.6,0.1,0.3,0.8,0.2])
。有问题的代码仍然给出数组([0.1,0.1,0.1,0.1,0.6,0.6,…])但是你的代码给出了数组([0.6,0.6,0.6,0.1,0.1,…])。@yatu我想你需要用argsort()索引进行索引。我不打算给出这个答案,因为它使用了更多的内存,可能不会更快,但我注意到d=dict(zip(ID_Arr,Value_Arr));打印([d[i]表示数据中的i])
将是等效的(尽管不使用numpy)。
# 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]