【问题标题】:Sort array of objects in numpy?在numpy中对对象数组进行排序?
【发布时间】:2017-01-05 10:52:10
【问题描述】:

如何在 Numpy 中根据两个或多个属性有效地对对象数组进行排序?

class Obj():
    def __init__(self,a,b):
        self.a = a
        self.b = b

arr = np.array([],dtype=Obj)        

for i in range(10):
    arr = np.append(arr,Obj(i, 10-i))

arr_sort = np.sort(arr, order=a,b) ???

谢谢,Willem-Jan

【问题讨论】:

  • numpy 是否支持数据类型的类:np.array([],dtype=Obj)
  • 我会使用列表而不是对象数组。列表追加速度更快。并且列表排序允许对关键参数进行排序。
  • 也许您正在寻找structured arrays。但它们并不直接与 Python 类一起使用。
  • dtype=Obj 被视为dtype=object,通用object dtype。这种数组的元素可以是任何东西,包括None

标签: arrays sorting object numpy


【解决方案1】:

order 参数仅适用于结构化数组:

In [383]: arr=np.zeros((10,),dtype='i,i')
In [385]: for i in range(10):
     ...:     arr[i] = (i,10-i)  
In [386]: arr
Out[386]: 
array([(0, 10), (1, 9), (2, 8), (3, 7), (4, 6), (5, 5), (6, 4), (7, 3), (8, 2), (9, 1)], 
      dtype=[('f0', '<i4'), ('f1', '<i4')])
In [387]: np.sort(arr, order=['f0','f1'])
Out[387]: 
array([(0, 10), (1, 9), (2, 8), (3, 7), (4, 6), (5, 5), (6, 4), (7, 3), (8, 2), (9, 1)], 
      dtype=[('f0', '<i4'), ('f1', '<i4')])
In [388]: np.sort(arr, order=['f1','f0'])
Out[388]: 
array([(9, 1), (8, 2), (7, 3), (6, 4), (5, 5), (4, 6), (3, 7), (2, 8),
       (1, 9), (0, 10)], 
      dtype=[('f0', '<i4'), ('f1', '<i4')])

对于二维数组,lexsort 提供类似的“有序”排序

In [402]: arr=np.column_stack((np.arange(10),10-np.arange(10)))
In [403]: np.lexsort((arr[:,1],arr[:,0]))
Out[403]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int32)
In [404]: np.lexsort((arr[:,0],arr[:,1]))
Out[404]: array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0], dtype=int32)

使用您的对象数组,我可以将属性提取到以下任一结构中:

In [407]: np.array([(a.a, a.b) for a in arr])
Out[407]: 
array([[ 0, 10],
       [ 1,  9],
       [ 2,  8],
      ....
       [ 7,  3],
       [ 8,  2],
       [ 9,  1]])
In [408]: np.array([(a.a, a.b) for a in arr],dtype='i,i')
Out[408]: 
array([(0, 10), (1, 9), (2, 8), (3, 7), (4, 6), (5, 5), (6, 4), (7, 3),
       (8, 2), (9, 1)], 
      dtype=[('f0', '<i4'), ('f1', '<i4')])

Python sorted 函数将适用于 arr(或其等效列表)

In [421]: arr
Out[421]: 
array([<__main__.Obj object at 0xb0f2d24c>,
       <__main__.Obj object at 0xb0f2dc0c>,
       ....
       <__main__.Obj object at 0xb0f35ecc>], dtype=object)
In [422]: sorted(arr, key=lambda a: (a.b,a.a))
Out[422]: 
[<__main__.Obj at 0xb0f35ecc>,
 <__main__.Obj at 0xb0f3570c>,
 ...
 <__main__.Obj at 0xb0f2dc0c>,
 <__main__.Obj at 0xb0f2d24c>]

您的 Obj 类缺少一个不错的 __str__ 方法。我必须使用 [(i.a, i.b) for i in arr] 之类的东西来查看 arr 元素的值。

正如我在评论中所说,对于这个例子,列表比对象数组好得多。

In [423]: alist=[]
In [424]: for i in range(10):
     ...:     alist.append(Obj(i,10-i))

list append 比重复的数组追加更快。与列表相比,对象数组并没有增加太多功能,尤其是在 1d 时,并且对象是这样的自定义类。您无法对 arr 进行任何数学运算,而且正如您所见,排序并不容易。

【讨论】:

    猜你喜欢
    • 2015-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-18
    相关资源
    最近更新 更多