Problema

Tengo una matriz 2D que contiene una serie de 0 y 1 que representan valores que se han empaquetado en bits. Necesito insertar un número arbitrario de ceros en puntos arbitrarios en cada fila para rellenar los valores empaquetados en bits en un múltiplo de 8 bits.

Tengo 3 vectores.

  1. Un vector que contiene índices en los que quiero insertar ceros
  2. Un vector que contiene el número de ceros que quiero insertar en cada punto del vector 1.
  3. Un vector que contiene el tamaño de cada cadena de bits que estoy rellenando. (¡Probablemente no necesite esto para resolverlo, pero podría ser divertido!)

Ejemplo

Tengo un vector que contiene índices para insertar antes: [0 6 14]

Y un vector que contiene el número de ceros que quiero insertar: [2 0 4]

Y un vector que tiene el tamaño de cada cadena de bits que estoy rellenando: [6, 8, 4]

El objetivo es insertar los ceros en cada fila de la matriz como tal:

[[0 0 0 0 0 1  0 0 0 0 0 0 0 1  0 0 0 1]
 [0 0 0 0 0 1  0 0 0 0 0 0 1 0  0 0 0 1]
 [0 0 0 0 1 0  0 0 0 0 0 0 1 0  0 0 1 0]
 [0 0 0 0 1 1  0 0 0 0 0 1 0 0  0 0 1 1]
 [0 0 0 1 0 0  0 0 0 0 0 1 0 0  0 1 0 0]
 [0 0 0 1 0 1  0 0 0 0 0 1 1 0  0 1 0 1]
 [0 0 0 1 1 0  0 0 0 0 0 1 1 0  0 1 1 0]
 [0 0 0 1 1 1  0 0 0 0 1 0 0 0  0 1 1 1]
 [0 0 1 0 0 0  0 0 0 0 1 0 0 0  1 0 0 0]
 [1 1 0 0 1 0  1 1 1 1 1 1 1 1  1 0 0 1]]

*Spaces added between columns to highlight insertion points.

Se convierte en:

  | |                               | | | |
  v v                               v v v v
[[0 0 0 0 0 0 0 1  0 0 0 0 0 0 0 1  0 0 0 0 0 0 0 1]
 [0 0 0 0 0 0 0 1  0 0 0 0 0 0 1 0  0 0 0 0 0 0 0 1]
 [0 0 0 0 0 0 1 0  0 0 0 0 0 0 1 0  0 0 0 0 0 0 1 0]
 [0 0 0 0 0 0 1 1  0 0 0 0 0 1 0 0  0 0 0 0 0 0 1 1]
 [0 0 0 0 0 1 0 0  0 0 0 0 0 1 0 0  0 0 0 0 0 1 0 0]
 [0 0 0 0 0 1 0 1  0 0 0 0 0 1 1 0  0 0 0 0 0 1 0 1]
 [0 0 0 0 0 1 1 0  0 0 0 0 0 1 1 0  0 0 0 0 0 1 1 0]
 [0 0 0 0 0 1 1 1  0 0 0 0 1 0 0 0  0 0 0 0 0 1 1 1]
 [0 0 0 0 1 0 0 0  0 0 0 0 1 0 0 0  0 0 0 0 1 0 0 0]
 [0 0 1 1 0 0 1 0  1 1 1 1 1 1 1 1  0 0 0 0 1 0 0 1]]

*Arrows denote inserted 0's

Estoy probando la forma más eficaz de hacer esto. Todos los vectores / matrices son matrices numerosas. He investigado el uso de numpy.insert pero no parece que tenga la capacidad de insertar varios valores en un índice determinado. También pensé en usar numpy.hstack y luego aplanar, pero no pude producir el resultado que quería.

Cualquier ayuda es muy apreciada!

3
MKC 8 may. 2021 a las 00:08

3 respuestas

La mejor respuesta

np.insert admite la inserción de varios valores en el mismo índice , solo tiene que proporcionar ese índice varias veces. Para que pueda obtener el resultado deseado de la siguiente manera:

indices = np.array([0, 6, 14])
n_zeros = np.array([2, 0, 4])

result = np.insert(matrix,
                   np.repeat(indices, n_zeros),
                   0,
                   axis=1)
1
a_guest 7 may. 2021 a las 23:38

Formateó la matriz para usted (aunque podría ser más fácil trabajar con un ejemplo artificial):

matrix = nparray([[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1],
                  [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
                  [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0],
                  [0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1],
                  [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
                  [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1],
                  [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0],
                  [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1],
                  [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
                  [1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1]])
indices = np.array([0, 6, 14])
num_zeros = np.array([2, 0, 4])
pad = np.array([6, 8, 4])

Necesita asignar una nueva matriz para realizar esta operación. Crear matrices llenas de cero en numpy es muy barato. Entonces, comencemos con la asignación de una matriz llena de cero con nuestra forma de salida deseada:

out_shape = np.array(matrix.shape)
out_shape[1] += num_zeros.sum()
zeros = np.zeros(out_shape, dtype=matrix.dtype)

Ahora, escriba matrix en bloques continuos de memoria en zeros usando porciones:

meta = np.stack([indices, num_zeros])
meta = meta[:, meta[1] != 0] # throw away 0 slices
slices = meta.T.ravel().cumsum()
slices = np.append(cs, zeros.shape[1]) # for convenience

prev = 0
for start, end in zip(slices[1::2], slices[2::2]):
    zeros[:, slice(start,end)] = matrix[:, slice(prev, prev + end-start)]
    prev = end-start

Salida en zeros:

[[0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1]
 [0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1]
 [0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0]
 [0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1]
 [0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0]
 [0 0 0 0 0 1 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 1]
 [0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0]
 [0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1]
 [0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0]
 [0 0 1 1 0 0 1 0 1 1 1 1 1 1 1 1 0 0 0 0 1 0 0 1]]
1
Kevin 7 may. 2021 a las 22:12

Mi enfoque sería crear una matriz cero por adelantado y copiar las columnas en las ubicaciones correctas. La indexación es un poco complicada con respecto a la claridad, por lo que probablemente haya margen de mejora allí.


data = np.array(
  [[0, 0, 0, 0, 0, 1,  0, 0, 0, 0, 0, 0, 0, 1,  0, 0, 0, 1],
   [0, 0, 0, 0, 0, 1,  0, 0, 0, 0, 0, 0, 1, 0,  0, 0, 0, 1],
   [0, 0, 0, 0, 1, 0,  0, 0, 0, 0, 0, 0, 1, 0,  0, 0, 1, 0],
   [0, 0, 0, 0, 1, 1,  0, 0, 0, 0, 0, 1, 0, 0,  0, 0, 1, 1],
   [0, 0, 0, 1, 0, 0,  0, 0, 0, 0, 0, 1, 0, 0,  0, 1, 0, 0],
   [0, 0, 0, 1, 0, 1,  0, 0, 0, 0, 0, 1, 1, 0,  0, 1, 0, 1],
   [0, 0, 0, 1, 1, 0,  0, 0, 0, 0, 0, 1, 1, 0,  0, 1, 1, 0],
   [0, 0, 0, 1, 1, 1,  0, 0, 0, 0, 1, 0, 0, 0,  0, 1, 1, 1],
   [0, 0, 1, 0, 0, 0,  0, 0, 0, 0, 1, 0, 0, 0,  1, 0, 0, 0],
   [1, 1, 0, 0, 1, 0,  1, 1, 1, 1, 1, 1, 1, 1,  1, 0, 0, 1]])
insert_before = [0, 6, 14]
zero_pads = [0, 2, 4]

res = np.zeros((len(data), 8*len(zero_pads)), dtype=int)  

for i in range(len(zero_pads)):
    res[:, i*8+zero_pads[i]:(i+1)*8] = data[:, insert_before[i]:insert_before[i]+8-zero_pads[i]]


>>> res
array([[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 1],
       [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
       [0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1],
       [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0],
       [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1],
       [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0],
       [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1],
       [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0],
       [1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1]])
0
Woodford 7 may. 2021 a las 22:07