Supongamos que tengo una matriz booleana 2D muy grande (por el bien del ejemplo, tomemos dimensiones 4 líneas x 3 columnas):

toto = np.array([[True, True, False],
                [False, True, False],
                [True, False, False],
                [False, True, False]])

Quiero transformar toto para que contenga al menos un valor Verdadero por columna, dejando intactas otras columnas.

EDITAR: La regla es solo esta: si una columna es falsa, quiero introducir un Verdadero en una línea aleatoria.

Entonces, en este ejemplo, uno de los falsos en la tercera columna debería convertirse en verdadero.

¿Cómo harías eso de manera eficiente?

Gracias de antemano

-1
aka 28 feb. 2020 a las 23:16

2 respuestas

import numpy as np

toto = np.array([[False, True, False], [False, True, False],
                 [False, False, False], [False, True, False]])

# First we get a boolean array indicating columns that have at least one True value
mask = np.any(toto, axis=0)

# Now we invert the mask to get columns indexes (as boolean array) with no True value
mask = np.logical_not(mask)

# Notice that if we index with this mask on the colum dimension we get elements
# in all rows only in the columns containing no True value. The dimension is is
# "num_rows x num_columns_without_true"
toto[:, mask]

# Now we need random indexes for rows in the columns containing only false. That
# means an array of integers from zero to `num_rows - 1` with
# `num_columns_without_true` elements
row_indexes = np.random.randint(toto.shape[0], size=np.sum(mask))

# Now we can use both masks to select one False element in each column containing only False elements and set them to True
toto[row_indexes, mask] = True

Descargo de responsabilidad: mathfux fue más rápido con esencialmente la misma solución que la que estaba escribiendo (acepte su respuesta, entonces si esto es lo que estaba buscando), pero como estaba escribiendo con más comentarios, decidí publicar de todos modos.

0
darcamo 28 feb. 2020 a las 21:03

Puedes hacerlo así:

col_mask = ~np.any(toto, axis=0)
row_idx = np.random.randint(toto.shape[0], size=np.sum(col_mask))
toto[row_idx, col_mask]=True

col_mask es array([False, False, True]) de columnas modificables. row_idx es una matriz que consta de índices cambiables de filas.

0
mathfux 28 feb. 2020 a las 20:48