Сортировать парный массив из 3d-массива (заменить на l oop) - PullRequest
1 голос
/ 01 мая 2020

У меня есть следующий 3d массив:

import numpy as np

z = np.array([[[10,  2],
               [ 5,  3],
               [ 4,  4]],
              [[ 7,  6],
               [ 4,  2],
               [ 5,  8]]])

Я хочу отсортировать их по 3-му димму и 1-му значению.

В настоящее время я использую следующий код:

from operator import itemgetter

np.array([sorted(x,key=itemgetter(0)) for x in z])
array([[[ 4,  4],
        [ 5,  3],
        [10,  2]],

       [[ 4,  2],
        [ 5,  8],
        [ 7,  6]]])

Я хотел бы сделать код более эффективным / быстрым, удалив for l oop?

Ответы [ 3 ]

1 голос
/ 01 мая 2020

Для numpy одного вкладыша вы можете использовать numpy .argsort :

import numpy as np

a = np.array([[[10,  2],
               [ 5,  3],
               [ 4,  4]],
              [[ 7,  6],
               [ 4,  2],
               [ 5,  8]]])

a[np.arange(0,2)[:,None], a[:,:,0].argsort()]
array([[[ 4,  4],
        [ 5,  3],
        [10,  2]],
       [[ 4,  2],
        [ 5,  8],
        [ 7,  6]]])

Что для такого небольшого размера массива занимает примерно то же время, но при увеличении размер приведет к значительному улучшению, например:

from operator import itemgetter

a = np.random.randint(0,10, (2,100_000,2))

%timeit a[np.arange(0,2)[:,None], a[:,:,0].argsort()]
26.9 ms ± 351 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit [sorted(x,key=itemgetter(0)) for x in a]
327 ms ± 6.39 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
1 голос
/ 01 мая 2020

Вы можете использовать map() для достижения того же результата без for -l oop. И с функцией сортировки, определяемой пользователем, или лямбда, или частичной sorted:

  1. Сначала создав функцию сортировки:

    >>> def mysort(it):
    ...   return sorted(it, key=itemgetter(0))
    ...
    >>> list(map(mysort, z))
    [[[4, 4], [5, 3], [10, 2]], [[4, 2], [5, 8], [7, 6]]]
    
  2. То же, что и выше, но вместо этого используется лямбда:

    >>> list(map(lambda it: sorted(it, key=itemgetter(0)), z))
    [[[4, 4], [5, 3], [10, 2]], [[4, 2], [5, 8], [7, 6]]]
    
  3. С partial:

    >>> from functools import partial
    >>> psort = partial(sorted, key=itemgetter(0))
    >>> list(map(psort, z))
    [[[4, 4], [5, 3], [10, 2]], [[4, 2], [5, 8], [7, 6]]]
    

    Или частичное определено на месте:

    >>> list(map(partial(sorted, key=itemgetter(0)), z))
    [[[4, 4], [5, 3], [10, 2]], [[4, 2], [5, 8], [7, 6]]]
    
  4. Ваш вопрос содержит список списков, а не массив 3d numpy. Для numpy -ориентированных решений см. Этот ответ .

К вашему сведению, (2) и (3b) приблизительно эквивалентны, но имеют свои различия .
Среди вариантов 1-3 я предпочитаю лямбду в (2).

0 голосов
/ 01 мая 2020

Почему бы просто: np.sort(z,axis=1)?

import numpy as np

z = np.array([[[10,  2],
               [ 5,  3],
               [ 4,  4]],
              [[ 7,  6],
               [ 4,  2],
               [ 5,  8]]])

print(np.sort(z,axis=1))

[[[ 4  2]
  [ 5  3]
  [10  4]]

 [[ 4  2]
  [ 5  6]
  [ 7  8]]]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...