Перестановки индекса Python NumPy ndarray во всех измерениях (номер переменной переменной) - PullRequest
0 голосов
/ 03 июля 2018

«M» - это пустая ndarray, размерность которой «dim» является переменной (ранее сгенерированной), но каждое измерение имеет одинаковый размер «size». В моем коде это будет больше похоже на dim = 5, size = 7.

напр .: (dim = 3, размер = 4).

M = np.arange(size**dim).reshape((size,)*dim)

[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]
  [12 13 14 15]]

 [[16 17 18 19]
  [20 21 22 23]
  [24 25 26 27]
  [28 29 30 31]]

 [[32 33 34 35]
  [36 37 38 39]
  [40 41 42 43]
  [44 45 46 47]]

 [[48 49 50 51]
  [52 53 54 55]
  [56 57 58 59]
  [60 61 62 63]]]

И у меня есть собственный генератор перестановок 'per', который генерирует конкретные перестановки (не случайные) диапазона (размера).

print(next(per))
(1,0,3,2)

Моя потребность: преобразовать M, перемещая его элементы в соответствии с тем количеством перестановок, которое мне нужно. В примере: 21 (1 перестановка для первого измерения, 4 для второго, 16 для третьего - обобщенная: размер ** d для d в перестановках диапазона (dim)). Мои перестановки не случайны, но они независимы, отличаются друг от друга.

Результат может быть:

[[[36 39 37 38]
  [33 34 32 35]
  [46 44 45 47]]
  [41 43 40 42]
 [[9  10 11 8]
  [2  1  3  0]
  [6  7  5  4]
  [13 12 14 15]]
 [[56 59 57 58]
  [63 61 62 60]
  [53 54 52 55]
  [51 50 49 48]]
 [[28 30 29 31]
  [27 25 24 26]
  [17 18 16 19]
  [23 21 20 22]]]

Как я могу сделать это напрямую из M в виде массива, при этом мой код остается динамическим?

Ответы [ 2 ]

0 голосов
/ 11 июля 2018

Благодаря блестящим ответам Пола Панцера мне удалось решить этот вопрос. Последний ответ Павла замечательный и полностью обобщенный (даже с неквадратными матрицами!). Мой первоначальный вопрос был немного менее общим, так как моей целью было, чтобы моя перестановка всех измерений работала для квадратных матриц. Я упростил и сократил код, поэтому делюсь им здесь:

import numpy as np
from itertools import islice,count

size,dim = 4,3

per = (np.random.permutation(size) for _ in count())
idx = *(np.reshape((*islice(per, size**d),),[size]*(d+1)+[1]*(dim-d-1)) for d in range(dim)),

a = np.arange(size**dim).reshape((size,)*dim)
print(a[idx])
0 голосов
/ 03 июля 2018

Это упражнение в вещании:

>>> import numpy as np
>>> from itertools import islice
>>> 
>>> A = np.arange(27).reshape(3,3,3)
>>> def per(n):
...     while True:
...         yield np.random.permutation(n)
... 
>>> pg = per(3)
>>> 
>>> p0 = next(pg)[..., None, None]
>>> p1 = np.array([p for p in islice(pg, 3)])[..., None]
>>> p2 = np.array([[p for p in islice(pg, 3)] for _ in range(3)])
>>> 
>>> p0
array([[[2]],

       [[1]],

       [[0]]])
>>> p1
array([[[1],
        [0],
        [2]],

       [[1],
        [0],
        [2]],

       [[0],
        [2],
        [1]]])
>>> p2
array([[[1, 0, 2],
        [0, 2, 1],
        [0, 1, 2]],

       [[2, 1, 0],
        [1, 2, 0],
        [2, 1, 0]],

       [[1, 2, 0],
        [2, 1, 0],
        [2, 1, 0]]])
>>> A[p0, p1, p2]
array([[[22, 21, 23],
        [18, 20, 19],
        [24, 25, 26]],

       [[14, 13, 12],
        [10, 11,  9],
        [17, 16, 15]],

       [[ 1,  2,  0],
        [ 8,  7,  6],
        [ 5,  4,  3]]])

Общее время:

import numpy as np
from itertools import islice

def per(n=None):
    while True:
        n = (yield n if n is None else np.random.permutation(n)) or n

def sweep(shp):
    pg = per()
    pg.send(None)
    redshp = len(shp)*[1]
    sz = 1
    for j, k in enumerate(shp):
        pg.send(k)
        redshp[j] = k
        yield np.reshape((*islice(pg, sz),), redshp)
        sz *= k

# example
a = np.arange(24).reshape((2,3,4))
idx = *sweep(a.shape),
for i in idx:
    print(i)
print(a[idx])
...