python – 使用第二个数组作为参考对numpy数组的元素进行分类

假设我有一个具有有限数量的唯一值的数组.说

data = array([30, 20, 30, 10, 20, 10, 20, 10, 30, 20, 20, 30, 30, 10, 30])

而且我还有一个参考数组,其中包含数据中的所有唯一值,无需重复且按特定顺序排列.说

reference = array([20, 10, 30])

我想创建一个数组,其形状与包含参考数组中索引的数据的数据相同,其中数据数组中的每个元素都被找到.

换句话说,有了数据和引用,我想创建一个数组索引,以便以下成立.

data = reference[indexes]

计算索引的次优方法是使用for循环,就像这样

indexes = np.zeros_like(data, dtype=int)
for i in range(data.size):
    indexes[i] = np.where(data[i] == reference)[0]

但我会感到惊讶的是,没有一个numpythonic(因而更快!)的方式来做这个…任何想法?

谢谢!

最佳答案
我们有数据和参考 –

In [375]: data
Out[375]: array([30, 20, 30, 10, 20, 10, 20, 10, 30, 20, 20, 30, 30, 10, 30])

In [376]: reference
Out[376]: array([20, 10, 30])

暂时,让我们考虑一个排序版本的参考 –

In [373]: np.sort(reference)
Out[373]: array([10, 20, 30])

现在,我们可以使用np.searchsorted来查找此排序版本中每个数据元素的位置,如下所示 –

In [378]: np.searchsorted(np.sort(reference), data, side='left')
Out[378]: array([2, 1, 2, 0, 1, 0, 1, 0, 2, 1, 1, 2, 2, 0, 2], dtype=int64)

如果我们运行原始代码,预期的输出结果是 –

In [379]: indexes
Out[379]: array([2, 0, 2, 1, 0, 1, 0, 1, 2, 0, 0, 2, 2, 1, 2])

可以看出,搜索排序输出很好,除了它的0必须是1,而1必须改为0.现在,我们已经进入计算,参考的排序版本.因此,要做0到1和反之,我们需要引入用于排序参考的索引,即np.argsort(引用).这基本上是矢量化无循环或无字典方法!所以,最终的实现看起来像这样 –

# Get sorting indices for reference
sort_idx = np.argsort(reference)

# Sort reference and get searchsorted indices for data in reference
pos = np.searchsorted(reference[sort_idx], data, side='left')

# Change pos indices based on sorted indices for reference
out = np.argsort(reference)[pos]

运行时测试 –

In [396]: data = np.random.randint(0,30000,150000)
     ...: reference = np.unique(data)
     ...: reference = reference[np.random.permutation(reference.size)]
     ...: 
     ...: 
     ...: def org_approach(data,reference):
     ...:     indexes = np.zeros_like(data, dtype=int)
     ...:     for i in range(data.size):
     ...:         indexes[i] = np.where(data[i] == reference)[0]
     ...:     return indexes
     ...: 
     ...: def vect_approach(data,reference):
     ...:     sort_idx = np.argsort(reference)
     ...:     pos = np.searchsorted(reference[sort_idx], data, side='left')       
     ...:     return sort_idx[pos]
     ...: 

In [397]: %timeit org_approach(data,reference)
1 loops, best of 3: 9.86 s per loop

In [398]: %timeit vect_approach(data,reference)
10 loops, best of 3: 32.4 ms per loop

验证结果 –

In [399]: np.array_equal(org_approach(data,reference),vect_approach(data,reference))
Out[399]: True

转载注明原文:python – 使用第二个数组作为参考对numpy数组的元素进行分类 - 代码日志