Crea una matriz con x ceros y el rest.

Me gustaría poder crear una instancia rápida de una matriz donde las primeras celdas en una fila (número variable de) son 0, y el rest son unas.

Imagina que queremos una matriz de 3×4.

He instanciado la matriz primero como todos:

ones = np.ones([4,3]) 

Entonces imagina que tenemos una matriz que anuncia cuántos ceros iniciales hay:

 arr = np.array([2,1,3,0]) # first row has 2 zeroes, second row 1 zero, etc 

Resultado requerido:

 array([[0, 0, 1], [0, 1, 1], [0, 0, 0], [1, 1, 1]]) 

Obviamente, esto también se puede hacer de la manera opuesta, pero consideraría el enfoque donde 1 es un valor predeterminado y los ceros serían reemplazados.

¿Cuál sería la mejor manera de evitar un bucle tonto?

Aquí hay una forma. n es el número de columnas en el resultado. El número de filas está determinado por len(arr) .

 In [29]: n = 5 In [30]: arr = np.array([1, 2, 3, 0, 3]) In [31]: (np.arange(n) >= arr[:, np.newaxis]).astype(int) Out[31]: array([[0, 1, 1, 1, 1], [0, 0, 1, 1, 1], [0, 0, 0, 1, 1], [1, 1, 1, 1, 1], [0, 0, 0, 1, 1]]) 

Hay dos partes en la explicación de cómo funciona esto. Primero, ¿cómo crear una fila con m ceros y nm unos? Para eso, usamos np.arange para crear una fila con valores [0, 1, …, n-1] `:

 In [35]: n Out[35]: 5 In [36]: np.arange(n) Out[36]: array([0, 1, 2, 3, 4]) 

A continuación, compare esa matriz con m :

 In [37]: m = 2 In [38]: np.arange(n) >= m Out[38]: array([False, False, True, True, True], dtype=bool) 

Eso da una serie de valores booleanos; los primeros valores de m son falsos y el rest son verdaderos. Al convertir esos valores en enteros, obtenemos una matriz de 0s y 1s:

 In [39]: (np.arange(n) >= m).astype(int) Out[39]: array([0, 0, 1, 1, 1]) 

Para realizar esto sobre una matriz de valores m (su arr ), usamos difusión ; Esta es la segunda idea clave de la explicación.

Tenga en cuenta lo que arr[:, np.newaxis] da:

 In [40]: arr Out[40]: array([1, 2, 3, 0, 3]) In [41]: arr[:, np.newaxis] Out[41]: array([[1], [2], [3], [0], [3]]) 

Es decir, arr[:, np.newaxis] forma de arr en una matriz arr[:, np.newaxis] con forma (5, 1). ( arr.reshape(-1, 1) podría haber sido usado en su lugar). Ahora, cuando comparamos esto con np.arange(n) (una matriz 1-d con longitud n ), la difusión se activa:

 In [42]: np.arange(n) >= arr[:, np.newaxis] Out[42]: array([[False, True, True, True, True], [False, False, True, True, True], [False, False, False, True, True], [ True, True, True, True, True], [False, False, False, True, True]], dtype=bool) 

Como @RogerFan señala en su comentario, esto es básicamente un producto externo de los argumentos, utilizando la operación >= .

Un lanzamiento final para escribir int da el resultado deseado:

 In [43]: (np.arange(n) >= arr[:, np.newaxis]).astype(int) Out[43]: array([[0, 1, 1, 1, 1], [0, 0, 1, 1, 1], [0, 0, 0, 1, 1], [1, 1, 1, 1, 1], [0, 0, 0, 1, 1]]) 

No tan conciso como quería (estaba experimentando con mask_indices ), pero esto también hará el trabajo:

 >>> n = 3 >>> zeros = [2, 1, 3, 0] >>> numpy.array([[0] * zeros[i] + [1]*(n - zeros[i]) for i in range(len(zeros))]) array([[0, 0, 1], [0, 1, 1], [0, 0, 0], [1, 1, 1]]) >>> 

Funciona muy simple: concatena multiplicado el número requerido de veces, listas de un elemento [0] y [1] , creando la matriz fila por fila.