2017-01-24 9 views
5

У меня есть четыре квадратных матриц с размерностью 3Nx3N, называются A, B, C и D.Оптимизация присваивания в массив из различных массивов - NumPy

Я хочу, чтобы объединить их в единой матрице. Код с для петель является следующее:

import numpy 
N = 3 
A = numpy.random.random((3*N, 3*N)) 
B = numpy.random.random((3*N, 3*N)) 
C = numpy.random.random((3*N, 3*N)) 
D = numpy.random.random((3*N, 3*N)) 

final = numpy.zeros((6*N, 6*N)) 

for i in range(N): 
    for j in range(N): 
     for k in range(3): 
      for l in range(3): 
       final[6*i + k][6*j + l] = A[3*i+k][3*j+l] 
       final[6*i + k + 3][6*j + l + 3] = B[3*i+k][3*j+l] 
       final[6*i + k + 3][6*j + l] = C[3*i+k][3*j+l] 
       final[6*i + k][6*j + l + 3] = D[3*i+k][3*j+l] 

Можно ли написать предыдущий для петель в numpythonic образом?

+0

(не по теме) | Я думал про себя: единственный раз, когда я слышал, кто-то сказал, что «numpythonic» был кем-то другим. Но потом я проверил, и это был ты тоже :) – miradulo

+1

@Mitch Почти * тоник *. – Divakar

+0

Да, я сражаюсь с разными способами создания для циклов в Numpythonic. Глаз - ошибка, он должен быть нулевым. – NunodeSousa

ответ

4

Большая проблема для практики array-slicing в многомерные тензоры/массивы!

Мы будем инициализировать выходной массив как многомерный массив 6D и просто разрезать его и назначить четыре массива, которые будут изменены как массивы 4D. Цель состоит в том, чтобы избежать какой-либо укладки/конкатенации, поскольку они были бы дорогими, особенно при работе с большими массивами, вместо этого работая с изменением входных массивов, что было бы просто просмотром.

Вот реализация -

out = np.zeros((N,2,3,N,2,3),dtype=A.dtype) 
out[:,0,:,:,0,:] = A.reshape(N,3,N,3) 
out[:,0,:,:,1,:] = D.reshape(N,3,N,3) 
out[:,1,:,:,0,:] = C.reshape(N,3,N,3) 
out[:,1,:,:,1,:] = B.reshape(N,3,N,3) 
out.shape = (6*N,6*N) 

Просто объяснить немного больше, мы имели:

  |------------------------ Axes for selecting A, B, C, D 
np.zeros((N,2,3,N,2,3),dtype=A.dtype) 
        |------------------------- Axes for selecting A, B, C, D 

Таким образом, были использованы эти две оси (второй и пятый) длин (2x2) = 4, чтобы выбрать между четыре входа.

время выполнения теста

подходы -

def original_app(A, B, C, D): 
    final = np.zeros((6*N,6*N),dtype=A.dtype) 
    for i in range(N): 
     for j in range(N): 
      for k in range(3): 
       for l in range(3): 
        final[6*i + k][6*j + l] = A[3*i+k][3*j+l] 
        final[6*i + k + 3][6*j + l + 3] = B[3*i+k][3*j+l] 
        final[6*i + k + 3][6*j + l] = C[3*i+k][3*j+l] 
        final[6*i + k][6*j + l + 3] = D[3*i+k][3*j+l] 
    return final 

def slicing_app(A, B, C, D): 
    out = np.zeros((N,2,3,N,2,3),dtype=A.dtype) 
    out[:,0,:,:,0,:] = A.reshape(N,3,N,3) 
    out[:,0,:,:,1,:] = D.reshape(N,3,N,3) 
    out[:,1,:,:,0,:] = C.reshape(N,3,N,3) 
    out[:,1,:,:,1,:] = B.reshape(N,3,N,3) 
    return out.reshape(6*N,6*N) 

тайминги и верификация -

In [147]: # Setup input arrays 
    ...: N = 200 
    ...: A = np.random.randint(11,99,(3*N,3*N)) 
    ...: B = np.random.randint(11,99,(3*N,3*N)) 
    ...: C = np.random.randint(11,99,(3*N,3*N)) 
    ...: D = np.random.randint(11,99,(3*N,3*N)) 
    ...: 

In [148]: np.allclose(slicing_app(A, B, C, D), original_app(A, B, C, D)) 
Out[148]: True 

In [149]: %timeit original_app(A, B, C, D) 
1 loops, best of 3: 1.63 s per loop 

In [150]: %timeit slicing_app(A, B, C, D) 
100 loops, best of 3: 9.26 ms per loop 
+0

Команда 'numpy.allclose (out, final)' возвращает True: это гарантирует, что это то, что мы хотим выполнить. –

+0

@GuillaumeJacquenot Спасибо за подтверждение! Добавлен тест времени выполнения вместе с частью проверки. – Divakar

1

вы можете просто Concat EM

CONCAT А и В по горизонтали CONCAT С и D по горизонтали

CONCAT конъюнкции AB с conjucntion компакт-диска вертикально

пример:

AB = numpy.concatenate([A,B],1) 
CD = numpy.concatenate([C,D],1) 
ABCD = numpy.concatenate([AB,CD],0) 

Надеюсь, что поможет :)

+0

Результат не тот, который ожидался: 'numpy.allclose (ABCD, final)' возвращает false –

+0

Вы пытались просто распечатать ABCD? это будет искомая матрица. вы можете (должны) проверить значения вручную, распечатывая матрицу, чтобы узнать, соответствует ли она ожидаемому. попробуйте с небольшими матрицами 2x2 в качестве примера/теста. – epattaro

+0

Вы на правильном пути. Мой ответ с 'bmat' делает этот тип' concatenate'. Но макет OP более сложный, требующий некоторой перестройки и замены осей. – hpaulj

2

Начну с парой общих наблюдений

numpy Для массивов мы обычно используем [,] синтаксис вместо [] [] окончательных [6 * я + к] [6 * J + л] окончательного [6 * + К, 6 * J + L]

Для новых массивов, построенных из других, мы часто используем такие вещи, как изменить и нарезку, так что мы можем добавить их вместе в виде блоков, а не с итеративными циклами

В качестве простого примера можно привести следующие отличия:

y = x[1:] - x[:-1] 

Что касается заголовка, «создание матрицы» является более четким. «load» имеет больше смысла считывать данные из файла, как в np.loadtxt.

=================

Так с N=1,

In [171]: A=np.arange(0,9).reshape(3,3) 
In [172]: B=np.arange(10,19).reshape(3,3) 
In [173]: C=np.arange(20,29).reshape(3,3) 
In [174]: D=np.arange(30,39).reshape(3,3) 

In [178]: final 
Out[178]: 
array([[ 0, 1, 2, 30, 31, 32], 
     [ 3, 4, 5, 33, 34, 35], 
     [ 6, 7, 8, 36, 37, 38], 
     [20, 21, 22, 10, 11, 12], 
     [23, 24, 25, 13, 14, 15], 
     [26, 27, 28, 16, 17, 18]]) 

который может быть создан одним вызовом bmat:

In [183]: np.bmat([[A,D],[C,B]]).A 
Out[183]: 
array([[ 0, 1, 2, 30, 31, 32], 
     [ 3, 4, 5, 33, 34, 35], 
     [ 6, 7, 8, 36, 37, 38], 
     [20, 21, 22, 10, 11, 12], 
     [23, 24, 25, 13, 14, 15], 
     [26, 27, 28, 16, 17, 18]]) 

bmat использует смесь hstack и vstack. Он также производит np.matrix, поэтому требуется .A. Решение @Divakar's должно быть быстрее.

Это не соответствует N = 3. Блоки 3x3 не работают. Но расширение массива до 6d (как это делает Дивакар) и замена некоторых осей, приводит к тому, что субблоки находятся в правильном порядке.

Для N=3:

In [57]: block=np.bmat([[A,D],[C,B]]) 
In [58]: b1=block.A.reshape(2,3,3,2,3,3) 
In [59]: b2=b1.transpose(1,0,2,4,3,5) 
In [60]: b3=b2.reshape(18,18) 
In [61]: np.allclose(b3,final) 
Out[61]: True 

В быстрых тестов времени (N = 3), мой подход составляет около половины скорости slicing_app.

В любопытстве bmat работает со строкой ввода: np.bmat('A,D;C,B'). Это потому, что np.matrix пытался, лет назад, дать ощущение MATLAB.

1

Еще один способ сделать это, используя view_as_blocks:

from skimage.util import view_as_blocks 

def by_blocks(): 
    final = numpy.empty((6*N,6*N)) 
    a,b,c,d,f= [view_as_blocks(X,(3,3)) for X in [A,B,C,D,final]] 
    f[0::2,0::2]=a 
    f[1::2,1::2]=b 
    f[1::2,0::2]=c 
    f[0::2,1::2]=d 
    return final 

Вам просто нужно думать поблочно, позволяя view_as_blocks управлять шагами и фигурами для вас. Это так же быстро, как и другие решения numpy.

 Смежные вопросы

  • Нет связанных вопросов^_^