根据给定索引进行就地numpy数组排序

Jam*_*mes 3 python numpy

有些问题很接近,但我没有找到具体的答案.我正在尝试沿着给定的轴对一个numpy 3D数组进行一些就地排序.我不想简单的排序,我想根据我自己的索引求助数组.例如

a = np.random.rand((3,3,3))
Run Code Online (Sandbox Code Playgroud)

并且假设我想根据旧数组的以下索引求助最后一个维度:

new_order = [1,2,0]
Run Code Online (Sandbox Code Playgroud)

我希望能说:

a[:,:,new_order] = a
Run Code Online (Sandbox Code Playgroud)

但这并不像预期的那样.建议?

hpa*_*ulj 6

np.ndarray.sort 是唯一声称在适当的地方,并没有给你太多的控制权.

将订单索引放在正确的位置 - 但可能会产生不可预测的结果.显然,它正在进行某种顺序分配,左侧的早期分配可能会影响右侧的值.

In [719]: a=np.arange(12).reshape(3,4)
In [720]: a[:,[0,1,3,2]]=a
In [721]: a
Out[721]: 
array([[ 0,  1,  2,  2],
       [ 4,  5,  6,  6],
       [ 8,  9, 10, 10]])
Run Code Online (Sandbox Code Playgroud)

要做到这种分配可预测地需要某种缓冲.

In [728]: a[:,[0,1,3,2]]=a.copy()
In [729]: a
Out[729]: 
array([[ 0,  1,  3,  2],
       [ 4,  5,  7,  6],
       [ 8,  9, 11, 10]])
Run Code Online (Sandbox Code Playgroud)

权利的索引绕过这个,但这不是就地.变量a指向新对象.

In [731]: a=a[:,[0,1,3,2]]
In [732]: a
Out[732]: 
array([[ 0,  1,  3,  2],
       [ 4,  5,  7,  6],
       [ 8,  9, 11, 10]])
Run Code Online (Sandbox Code Playgroud)

但是,分配[:]可以解决这个问题:

In [738]: a=np.arange(12).reshape(3,4)
In [739]: a.__array_interface__
Out[739]: 
{'data': (181868592, False),   # 181... is the id of the data buffer
 'descr': [('', '<i4')],
 'shape': (3, 4),
 'strides': None,
 'typestr': '<i4',
 'version': 3}
In [740]: a[:]=a[:,[0,1,3,2]]
In [741]: a.__array_interface__
Out[741]: 
{'data': (181868592, False),  # same data buffer
 'descr': [('', '<i4')],
 'shape': (3, 4),
 'strides': None,
 'typestr': '<i4',
 'version': 3}
In [742]: a
Out[742]: 
array([[ 0,  1,  3,  2],
       [ 4,  5,  7,  6],
       [ 8,  9, 11, 10]])
Run Code Online (Sandbox Code Playgroud)

a.dataid相同的事实表明这是一个就地动作.但是用其他索引来测试它会很好,以确保它能够满足您的需求.

但是,"就地"排序是必要的吗?如果阵列非常大,可能需要避免内存错误.但我们必须测试替代方案,看看它们是否有效.

inplace如果有一些其他变量使用相同的数据也很重要.例如

b = a.T # a transpose
Run Code Online (Sandbox Code Playgroud)

随着a[:]=的行b会被重新排序.ab继续分享同样的data.随着a=,b没有变化. ab现在去耦.