Python 使用第二个数组中的顺序对numpy数组进行就地排序
设两个数组:Python 使用第二个数组中的顺序对numpy数组进行就地排序,python,numpy,numpy-ndarray,Python,Numpy,Numpy Ndarray,设两个数组:A的形状(n,*m),和B的形状(n,)。是否有一种方法可以使用排序B的顺序对a进行排序 使用B对A进行排序很容易,但这并没有到位: A = A[np.argsort(B)] 评论: A和B有不同的数据类型,A可以有两个以上的维度。因此,它们不能堆叠使用ndarray.sort() A占用大量空间,这就是为什么需要对其进行适当排序的原因。因此,任何需要两倍于A所占用空间的解决方案都会破坏这一目的 这个问题的标题可能听起来有关联,但问题本身并不十分清楚,答案与我的问题不符 如果可
A的形状(n,*m)
,和B的形状(n,)
。是否有一种方法可以使用排序B
的顺序对a
进行排序
使用B
对A
进行排序很容易,但这并没有到位:
A = A[np.argsort(B)]
评论:
A
和B
有不同的数据类型,A
可以有两个以上的维度。因此,它们不能堆叠使用ndarray.sort()
A
占用大量空间,这就是为什么需要对其进行适当排序的原因。因此,任何需要两倍于A
所占用空间的解决方案都会破坏这一目的
- 这个问题的标题可能听起来有关联,但问题本身并不十分清楚,答案与我的问题不符
如果可以预先将A
设置为结构化数组,其数据类型由形状(m,)
的子数组和相同类型的标量(例如,np.int32
)组成,则可以根据B
对其进行排序。例如:
import numpy as np
B = np.array([3, 1, 2])
A = np.array([[10, 11], [20, 21], [30, 31]])
(n, m) = A.shape
dt = np.dtype([('a', np.int32, (m, )), ('b', int)])
A2 = np.array([(a, b) for a, b in zip(A, B)], dtype=dt)
A2.sort(order='b')
print A2
下面是一个通过在索引数组中遵循循环来工作的解决方案。它可以选择使用pythran进行编译,如果行很小(10个元素为80倍),则会有显著的加速;如果行很大,则会有较小的加速(1000个元素为30%)
为了使它与pythran兼容,我必须将它简化一点,这样它只接受2D数组,并且只沿轴0排序
代码:
使用编译版本运行示例。如上所述,编译只需要用于小行,对于较大的行,纯python应该足够快
>>> from timeit import timeit
>>> import numpy as np
>>> import take_inplace
>>>
>>> a = np.random.random((1000, 10))
>>> idx = a[:, 4].argsort()
>>>
>>> take_inplace.take_inplace(a, idx)
>>>
# correct
>>> np.all(np.arange(1000) == a[:, 4].argsort())
True
>>>
# speed
>>> timeit(lambda: take_inplace.take_inplace(a, idx), number=1000)
0.011950935004279017
>>>
# for comparison
>>> timeit(lambda: a[idx], number=1000)
0.02985276997787878
看起来这只是一个高级索引任务,A[arr,:]
,索引A
的行。那一定是一份拷贝。即使您使用A[:]=…
将新值写回“A
”,数据也会有一个临时缓冲区。@hpaulj:的确,我想知道是否有一种方法可以做到这一点,而无需索引,也无需创建这样的缓冲区。这非常有效,非常感谢!我用n、*m=a.shape
替换了take_in place
的第一行,这样a
可以有两个或更多维度。
>>> from timeit import timeit
>>> import numpy as np
>>> import take_inplace
>>>
>>> a = np.random.random((1000, 10))
>>> idx = a[:, 4].argsort()
>>>
>>> take_inplace.take_inplace(a, idx)
>>>
# correct
>>> np.all(np.arange(1000) == a[:, 4].argsort())
True
>>>
# speed
>>> timeit(lambda: take_inplace.take_inplace(a, idx), number=1000)
0.011950935004279017
>>>
# for comparison
>>> timeit(lambda: a[idx], number=1000)
0.02985276997787878