基于多个数组的python argsort索引

时间:2012-04-01 21:01:37

标签: python sorting

我正在寻找一个理想的纯python函数,类似于numpy.argsort,因为它只返回已排序索引的列表,同时保持原始数组不变,但它需要能够对多个包含的数据进行排序阵列。

示例:

>>> names = ['xavier', 'bob', 'billy', 'jene', 'samson']
>>> ages = [15, 32, 63, 32, 15]
>>>indexes = sort by ages and then by names
[4, 0, 1, 3, 2]
>>> for i in indexes:
>>>    print "Name", names[i]
>>>    print "Age", ages[i]

排序功能无法创建额外的数据结构,这意味着列表理解或zip等功能是不可能的。每个数组由500万个对象组成,生成数组的压缩版本将内存需求爆炸至少3倍。使用列表理解,例如sorted(.. key = lambda x :( names [x],ages [x] ))导致减速,例如排序需要一分钟才能完成(以及创建这些中间元组的内存要求)

到目前为止,只要我只想对单个数组进行排序就足够快了,但是由于索引列表不知道其他数组,我无法调用多个“排序”操作,就像我想的那样我有两个列表的压缩版本。

2 个答案:

答案 0 :(得分:3)

这是我能想到的最好的。 python中的大多数int都是单例,因此第一个sorted调用创建的新列表不应该创建更多的全新对象。第二个sorted调用应创建一个较小的列表,它取决于年龄的不同。

>>> import itertools, operator
>>> names = ['xavier', 'bob', 'billy', 'jene', 'samson']
>>> ages = [15, 32, 63, 32, 15]
>>> itemgetter = operator.itemgetter(1)
>>> sortedAges = sorted(enumerate(ages), key=itemgetter)
>>> for k, group in itertools.groupby(sortedAges, itemgetter):
...     g = sorted([(i, names[i]) for i, _ in group], key=itemgetter)
...     for i, name in g:
...         print 'Name:', name, 'Age:', ages[i]
... 
Name: samson Age: 15
Name: xavier Age: 15
Name: bob Age: 32
Name: jene Age: 32
Name: billy Age: 63

答案 1 :(得分:0)

我创建了自己的解决方案,效果很好。

给出以下数据集:

groups = reversed(range(5000000))
ages = [random.randrange(0, 120) for x in groups]
names = ['foobar-%d' % random.randrange(0, 5000) for x in groups]

columns = dict(names=names,ages=ages,groups=groups)

def sort_on(col):
    idxs = range(len(columns[col]))
    idxs.sort(key=lambda x:columns[col][x])
    return idxs