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