индексы Python Argsort, основанные на нескольких массивах - PullRequest
1 голос
/ 02 апреля 2012

В идеале я ищу функцию в чистом 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.Каждый массив состоит из 5 миллионов объектов, генерация сжатых версий массивов увеличивает требования к памяти как минимум в 3 раза. Использование понимания списка, такого как сортировка (.. key = lambda x: (names [x], ages [x]))) вызывает замедление, такое как сортировка занимает более минуты (и требования к памяти для создания этих промежуточных кортежей)

Пока я хочу сортировать только по одному массиву, это быстродостаточно, однако, поскольку список индексов не знает о других массивах, я не могу вызвать несколько операций «сортировки», как если бы у меня была сжатая версия двух списков.

Ответы [ 2 ]

3 голосов
/ 02 апреля 2012

Это лучшее, что я могу думать.Большинство int в Python являются одноэлементными, поэтому новый список, созданный первым вызовом 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
0 голосов
/ 08 апреля 2012

Я создал собственное решение, которое прекрасно работает.

Учитывая следующий набор данных:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...