2016-11-29 157 views
1

我想使用从this answer解决方案的特定列(就地)排序numpy数组。在大多数情况下它的工作原理,但它不能在任何阵列的另一个数组一个观点:现在就地排序按列排序失败

In [35]: columnnum = 2 

In [36]: a = np.array([[1,2,3], [4,7,5], [9,0,1]]) 

In [37]: a 
Out[37]: 
array([[1, 2, 3], 
     [4, 7, 5], 
     [9, 0, 1]]) 

In [38]: b = a[:,(0, 2)] 

In [39]: b 
Out[39]: 
array([[1, 3], 
     [4, 5], 
     [9, 1]]) 

In [40]: a.view(','.join([a.dtype.str] * a.shape[1])).sort(order=['f%d' % columnnum], axis=0) 

In [41]: a 
Out[41]: 
array([[9, 0, 1], 
     [1, 2, 3], 
     [4, 7, 5]]) 

In [42]: b.view(','.join([b.dtype.str] * b.shape[1])).sort(order=['f%d' % columnnum], axis=0) 
ValueError: new type not compatible with array. 

它看起来像numpy的不支持的意见的意见,这使得一定的意义,但我无法弄清楚如何获得我需要的任何数组的视图,无论它本身是否为视图。到目前为止,我一直无法找到任何方式来获取关于我必须构建我需要的新视图的必要信息。

现在,我正在使用l = l[l[:,columnnum].argsort()]就地排序方法,它工作正常,但由于我在大型数据集上运行,因此我想避免argsort()调用的额外内存开销(列表的索引)。有没有办法获得关于视图的必要信息或按列进行分类?

+0

我的预感是你会走运。我对这些numpy的内部信息不是很了解,但是在我看来,就像你试图将视角超越可以在不复制数据的情况下所做的那样。 – BrenBarn

+0

@BrenBarn:可能。我只是想看看这里有没有人有任何聪明的黑客。我目前的解决方案只是错误的数据,无法查看,并告诉调用者首先做一个副本......丑陋的,但至少我可以提供一个有用的错误消息。 – Linuxios

回答

1
In [1019]: a=np.array([[1,2,3],[4,7,5],[9,0,1]]) 
In [1020]: b=a[:,(0,2)] 

这是您正在排序的a;具有3个字段的结构化数组。它使用相同的数据缓冲区,但将3个整数组解释为字段而不是列。

In [1021]: a.view('i,i,i') 
Out[1021]: 
array([[(1, 2, 3)], 
     [(4, 7, 5)], 
     [(9, 0, 1)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')]) 

通过同样的逻辑,试图viewb

In [1022]: b.view('i,i') 
/usr/local/bin/ipython3:1: DeprecationWarning: Changing the shape of non-C contiguous array by 
descriptor assignment is deprecated. To maintain 
the Fortran contiguity of a multidimensional Fortran 
array, use 'a.T.view(...).T' instead 
    #!/usr/bin/python3 
.... 
ValueError: new type not compatible with array. 

但是,如果使用3个字段,而不是2,它的工作原理(但具有相同的警告):

In [1023]: b.view('i,i,i') 
/usr/local/bin/ipython3:1: DeprecationWarning:... 
Out[1023]: 
array([[(1, 4, 9), (3, 5, 1)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')]) 

问题是bFortran order。检查b.flags

In [1026]: a.strides 
Out[1026]: (12, 4) 
In [1027]: b.strides 
Out[1027]: (4, 12) 

b是一个副本,而不是一个视图。我不知道,为什么这个建筑b改变了顺序。

听从警告,我可以这样做:

In [1047]: b.T.view('i,i,i').T 
Out[1047]: 
array([[(1, 4, 9), (3, 5, 1)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')]) 

默认复制(顺序c)中的b可被视为2个字段:

In [1042]: b1=b.copy() 
In [1043]: b1.strides 
Out[1043]: (8, 4) 
In [1044]: b1.view('i,i') 
Out[1044]: 
array([[(1, 3)], 
     [(4, 5)], 
     [(9, 1)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4')]) 

脚注上:https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html

高级索引结果的内存布局针对每个索引操作进行了优化,并且没有特定的内存ory命令可以被假定。

====================

在这种情况下b用高级索引构成,并且因此是一个拷贝,即使是真正的视图可能不是这样既可见:

In [1052]: a[:,:2].view('i,i') 
.... 
ValueError: new type not compatible with array. 

In [1054]: a[:,:2].copy().view('i,i') 
Out[1054]: 
array([[(1, 2)], 
     [(4, 7)], 
     [(9, 0)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4')]) 

的观点是选择值的子集: '我,我,X,I,I,X,I,I,X ...',和这不会转化为结构化的dtype。

a的结构化视图的作用: '(I,I,I),(I,I,I),...'

可以选择一种结构化阵列的字段的子集:

In [1059]: a1=a.view('i,i,i') 
In [1060]: a1 
Out[1060]: 
array([[(1, 2, 3)], 
     [(4, 7, 5)], 
     [(9, 0, 1)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')]) 
In [1061]: b1=a1[['f0','f2']] 
In [1062]: b1 
Out[1062]: 
array([[(1, 3)], 
     [(4, 5)], 
     [(9, 1)]], 
     dtype=[('f0', '<i4'), ('f2', '<i4')]) 

但是对于这样的视图你可以做什么是有限度的。值可以在a1中更改,并在ab1中查看。但是如果我尝试更改b1中的值,则会发生错误。 这是发展的边缘。

+0

感谢您的详细解答!那么我是否有理由认为检查'a.flags.c_contiguous'是否为'True'就足以保证数组能够以这种方式被查看? – Linuxios

+0

它可能是;我没有用过那种测试。 – hpaulj

+0

谢谢。我假设没有其他方法可以按列排序,是吗? – Linuxios