python - Интуиция и идея преобразования массива 4D в 2D в NumPy




arrays multidimensional-array (2)

Общая идея для nd to nd трансформации

Идея такого преобразования заключается в использовании двух вещей:

  • Остановить оси (с помощью numpy.transpose или numpy.moveaxis или numpy.rollaxis если требуемый порядок перестановок является свернутым, или numpy.swapaxes если нужно поменять местами только две оси) и

  • Переформуйте.

Перестановка осей: получить заказ так, чтобы выровненная версия соответствовала выровненной версии вывода. Так что, если вы как-то используете его дважды, посмотрите снова, потому что вы не должны.

Изменить форму : разделить оси или привести конечный результат к нужной форме. Разделение осей необходимо в основном на старте, когда входной сигнал имеет более слабое затемнение, и нам нужно разделить на блоки. Опять же, вам не нужно это более двух раз.

Следовательно, обычно у нас было бы три шага:

    [ Reshape ]      --->  [ Permute axes ]   --->  [ Reshape ]

 Create more axes             Bring axes             Merge axes
                          into correct order

Метод обратного слежения

Самый безопасный способ решить, учитывая вход и выход, - это то, что можно назвать методом обратного отслеживания, то есть разделить оси входа (при переходе от меньшего к большему) или разделить оси выходного сигнала ( при переходе от большего к меньшему). Идея расщепления состоит в том, чтобы привести число тусклых частей меньшего и того же числа к большему. Затем изучите шаги вывода и сопоставьте его со входом, чтобы получить требуемый порядок перестановок. Наконец, в конце может потребоваться изменение формы (путь по умолчанию или порядок C), если последний является меньшим, для объединения осей.

Если и вход, и выход имеют одинаковое количество тусклых димов, то нам нужно было бы разделить оба и разбить на блоки и изучить их шаги друг против друга. В таких случаях у нас должен быть дополнительный входной параметр размеров блока, но это, вероятно, не по теме.

пример

Давайте использовать этот конкретный случай, чтобы продемонстрировать, как применять эти стратегии. Здесь вход 4D , а выход 2D . Так что, скорее всего, нам не понадобится изменение формы для разделения. Итак, нам нужно начать с перестановки осей. Так как конечный результат не 4D , а 2D , нам нужно изменить форму в конце.

Теперь вход здесь:

In [270]: a
Out[270]: 
array([[[[ 0,  0],
         [ 0,  0]],

        [[ 5, 10],
         [15, 20]]],


       [[[ 6, 12],
         [18, 24]],

        [[ 7, 14],
         [21, 28]]]])

Ожидаемый результат:

In [271]: out
    Out[271]: 
    array([[ 0,  5,  0, 10],
           [ 6,  7, 12, 14],
           [ 0, 15,  0, 20],
           [18, 21, 24, 28]])

Кроме того, это преобразование от большего к меньшему, поэтому метод обратного отслеживания включал бы разделение вывода и изучение его strides и сопоставление с соответствующими значениями на входе:

                    axis = 3
                   ---      -->          

                    axis = 1                    
                   ------>           
axis=2|  axis=0|   [ 0,  5,  0, 10],        

               |   [ 6,  7, 12, 14],
               v  
      |            [ 0, 15,  0, 20],
      v
                   [18, 21, 24, 28]])

Следовательно, необходимый перестановочный порядок равен (2,0,3,1) :

In [275]: a.transpose((2, 0, 3, 1))
Out[275]: 
array([[[[ 0,  5],
         [ 0, 10]],

        [[ 6,  7],
         [12, 14]]],


       [[[ 0, 15],
         [ 0, 20]],

        [[18, 21],
         [24, 28]]]])

Затем просто измените форму до ожидаемой:

In [276]: a.transpose((2, 0, 3, 1)).reshape(4,4)
Out[276]: 
array([[ 0,  5,  0, 10],
       [ 6,  7, 12, 14],
       [ 0, 15,  0, 20],
       [18, 21, 24, 28]])

Больше примеров

Я выкопал свою историю и нашел несколько Q&As основанных на преобразованиях. Они могут служить другими примерами, хотя и с меньшим объяснением (в основном). Как упоминалось ранее, самое большее два изменения reshapes и самое большее одно swapaxes / transpose сделали работу везде. Они перечислены ниже:

При реализации Kronecker-product по педагогическим причинам (без использования очевидного и легкодоступного np.kron() ) я получил 4-мерный массив в качестве промежуточного результата, который я должен изменить, чтобы получить окончательный результат.

Но я все еще не могу обернуть голову вокруг преобразования этих многомерных массивов. У меня есть этот массив 4D :

array([[[[ 0,  0],
         [ 0,  0]],

        [[ 5, 10],
         [15, 20]]],


       [[[ 6, 12],
         [18, 24]],

        [[ 7, 14],
         [21, 28]]]])

Это имеет форму (2, 2, 2, 2) и я хотел бы изменить его на (4,4) . Можно подумать, что это очевидно связано с

np.reshape(my4darr, (4,4))

Но приведенное выше изменение не дает ожидаемого результата, который:

array([[ 0,  5,  0, 10],
       [ 6,  7, 12, 14],
       [ 0, 15,  0, 20],
       [18, 21, 24, 28]])

Как видите, все элементы в ожидаемом результате присутствуют в массиве 4D . Я просто не могу освоить правильное изменение формы по мере необходимости. В дополнение к ответу, некоторые объяснения того, как сделать reshape для таких многомерных массивов, были бы действительно полезны. Спасибо!


Похоже, вы ищете transpose последующей reshape .

x.transpose((2, 0, 3, 1)).reshape(np.prod(x.shape[:2]), -1)

array([[ 0,  5,  0, 10],
       [ 6,  7, 12, 14],
       [ 0, 15,  0, 20],
       [18, 21, 24, 28]])

Чтобы помочь вам понять, почему требуется транспонирование, давайте проанализируем ваш вывод неправильной формы (полученный одним вызовом reshape ), чтобы понять, почему он неправильный.

Простая 2D-версия этого результата (без какой-либо транспозиции) выглядит так:

x.reshape(4, 4)

array([[ 0,  0,  0,  0],
       [ 5, 10, 15, 20],
       [ 6, 12, 18, 24],
       [ 7, 14, 21, 28]])

Теперь рассмотрим этот вывод относительно ожидаемого результата -

array([[ 0,  5,  0, 10],
       [ 6,  7, 12, 14],
       [ 0, 15,  0, 20],
       [18, 21, 24, 28]])

Вы заметите, что ваш фактический результат получен Z-образным обходом вашего вывода неправильной формы -

start
    | /|     /| /|
    |/ |    / |/ |
      /    /    / 
     /    /    /
    | /| /    | /|
    |/ |/     |/ |
                 end

Это означает, что вы должны перемещаться по массиву различными шагами, чтобы получить реальный результат. В заключение, просто изменить форму недостаточно. Вы должны транспонировать исходный массив таким образом, чтобы эти Z-подобные элементы были сделаны смежными друг с другом, чтобы при последующем вызове изменения формы вы получили нужный результат.

Чтобы понять, как правильно транспонировать, вы должны проследить элементы вдоль входа и выяснить, по каким осям нужно перейти, чтобы добраться до каждой из них на выходе. Транспозиция следует соответственно. Ответ Дивакара отлично объясняет это.





reshape