Vectorizar la expansión de matriz numpy

Estoy tratando de encontrar una manera de vectorizar una operación donde tomo 1 matriz numpy y aumente cada elemento en 4 puntos nuevos. Actualmente lo estoy haciendo con Python loop. Primero déjame explicarte el algoritmo.

input_array = numpy.array([1, 2, 3, 4]) 

Quiero ‘expandir’ o ‘extender’ cada elemento de esta matriz a 4 puntos. Entonces, el elemento cero (valor 1) se expandirá a estos 4 puntos:

 [0, 1, 1, 0] 

Esto sucedería para que cada elemento terminara con una matriz final de:

 [0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0] 

Me gustaría hacer que el código sea un poco genérico para poder realizar esta ‘expansión’ de una manera diferente. Por ejemplo:

 input_array = numpy.array([1, 2, 3, 4]) 

Esta vez, cada punto se expande agregando + = .2 a cada punto. Entonces, la matriz final sería:

 [.8, .8, 1.2, 1.2, 1.8, 1.8, 2.2, 2.2, 2.8, 2.8, 3.2, 3.2, 3.8, 3.8, 4.2, 4.2] 

El código que estoy usando actualmente se ve así. Es un enfoque bastante ingenuo que funciona pero parece que habría una manera de acelerarlo para arreglos grandes:

 output = [] for x in input_array: output.append(expandPoint(x)) output = numpy.concatenate(output) def expandPoint(x): return numpy.array([0, x, x, 0]) def expandPointAlternativeStyle(x): return numpy.array([x - .2, x - .2, x + .2, x + .2]) 

Parece que quieres querer hacer operaciones input_array entre input_array y la matriz que contiene los elementos extendidos. Para estos, puede utilizar la broadcasting .

Para el primer ejemplo, parece que estás realizando la elementwise multiplication

 In [424]: input_array = np.array([1, 2, 3, 4]) ...: extend_array = np.array([0, 1, 1, 0]) ...: In [425]: (input_array[:,None] * extend_array).ravel() Out[425]: array([0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0]) 

Para el segundo ejemplo, parece que estás realizando elementwise addition

 In [422]: input_array = np.array([1, 2, 3, 4]) ...: extend_array = np.array([-0.2, -0.2, 0.2, 0.2]) ...: In [423]: (input_array[:,None] + extend_array).ravel() Out[423]: array([ 0.8, 0.8, 1.2, 1.2, 1.8, 1.8, 2.2, 2.2, 2.8, 2.8, 3.2, 3.2, 3.8, 3.8, 4.2, 4.2]) 

No estoy seguro de la lógica de su algoritmo, pero creo que si desea que cada punto se extend alrededor de él y luego los ponga en cola todos juntos, lo mejor sería boost la dimensión y luego tomar la versión aplanada; para su primer ejemplo:

 >>> x = np.array([1,2,3,4]) >>> x array([1, 2, 3, 4]) >>> y = np.empty((len(x), 4)) >>> y[:, [0, 3]] = 0 >>> y[:, 1:3] = x[:, None] >>> y array([[ 0., 1., 1., 0.], [ 0., 2., 2., 0.], [ 0., 3., 3., 0.], [ 0., 4., 4., 0.]]) >>> y.reshape((4*len(x),)) # Flatten it back array([ 0., 1., 1., 0., 0., 2., 2., 0., 0., 3., 3., 0., 0., 4., 4., 0.]) 

La forma en que haga que ese genérico dependa de su algoritmo, que no estoy seguro de seguir … Pero esto debería darle algunos consejos para comenzar.

Edit : Como han dicho otros, puedes hacer todo eso con productos externos de una manera mucho más concisa, que probablemente coincidirá con tu algoritmo más de cerca, por ejemplo, haciendo que YXD responda de manera sencilla:

 >>> (x[:, None] * np.array([0,1,1,0])[None, :]).flatten() array([0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0]) 

Sin embargo, el principio aún debe ir en una dimensión superior (2) antes de expandirlo en su dimensión original (1)

Para el primer ejemplo, puede usar np.kron

 >>> a = np.array([0, 1, 1, 0]) >>> np.kron(input_array, a) array([0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0]) 

Para el segundo ejemplo, puede usar np.repeat y np.tile

 >>> b = np.array([-0.2, -0.2, 0.2, 0.2]) >>> np.repeat(input_array, b.size) + np.tile(b, input_array.size) array([ 0.8, 0.8, 1.2, 1.2, 1.8, 1.8, 2.2, 2.2, 2.8, 2.8, 3.2, 3.2, 3.8, 3.8, 4.2, 4.2]) 

Para el primer ejemplo, puede hacer un producto externo de la entrada y la plantilla y remodelar el resultado:

 input_array = np.array([1, 2, 3, 4]) template = np.array([0, 1, 1, 0]) np.multiply.outer(input_array, template) # array([[0, 1, 1, 0], # [0, 2, 2, 0], # [0, 3, 3, 0], # [0, 4, 4, 0]]) result = np.multiply.outer(input_array, template).ravel() # array([0, 1, 1, 0, 0, 2, 2, 0, 0, 3, 3, 0, 0, 4, 4, 0]) 

De manera similar para su segundo ejemplo, puede usar np.add.outer

 np.add.outer(input_array, [-0.2, -0.2, 0.2, 0.2]).ravel() # array([ 0.8, 0.8, 1.2, 1.2, 1.8, 1.8, 2.2, 2.2, 2.8, 2.8, 3.2, 3.2, 3.8, 3.8, 4.2, 4.2]) 

Ver: