Numpy: Comment se débarrasser des minima le long de l'axe= 1, compte tenu des indices - de manière efficace?
Question
Étant donné une matrice A avec une forme (1000000,6)
, j'ai compris comment obtenir la valeur minimale la plus à droite pour chaque ligne et je l'ai implémentée dans cette fonction:
def calculate_row_minima_indices(h): # h is the given matrix.
"""Returns the indices of the rightmost minimum per row for matrix h."""
flipped = numpy.fliplr(h) # flip the matrix to get the rightmost minimum.
flipped_indices = numpy.argmin(flipped, axis=1)
indices = numpy.array([2]*dim) - flipped_indices
return indices
indices = calculate_row_minima_indices(h)
for col, row in enumerate(indices):
print col, row, h[col][row] # col_index, row_index and value of minimum which should be removed.
Chaque ligne a un minimum.Donc, ce que j'ai besoin de savoir, c'est de supprimer l'entrée avec le minimum et de réduire la matrice avec shape (1000000,6)
en une matrice avec shape (1000000,5)
.
Je générerais une nouvelle matrice avec une dimension inférieure et la remplirais avec les valeurs que je veux qu'elle porte en utilisant une boucle for, mais j'ai peur du runtime. Y a-t-il donc une manière intégrée ou une astuce pour réduire la matrice des minima par ligne?
Cette information est peut-être utile: les valeurs sont toutes supérieures ou égales à 0,0.
La solution
En supposant que vous ayez suffisamment de mémoire pour contenir un masque booléen de la forme de votre tableau d'origine ainsi que du nouveau tableau, voici une façon de le faire:
import numpy as np
def main():
np.random.seed(1) # For reproducibility
data = generate_data((10, 6))
indices = rightmost_min_col(data)
new_data = pop_col(data, indices)
print 'Original data...'
print data
print 'Modified data...'
print new_data
def generate_data(shape):
return np.random.randint(0, 10, shape)
def rightmost_min_col(data):
nrows, ncols = data.shape[:2]
min_indices = np.fliplr(data).argmin(axis=1)
min_indices = (ncols - 1) - min_indices
return min_indices
def pop_col(data, col_indices):
nrows, ncols = data.shape[:2]
col_indices = col_indices[:, np.newaxis]
row_indices = np.arange(ncols)[np.newaxis, :]
mask = col_indices != row_indices
return data[mask].reshape((nrows, ncols-1))
if __name__ == '__main__':
main()
Cela donne:
Original data...
[[5 8 9 5 0 0]
[1 7 6 9 2 4]
[5 2 4 2 4 7]
[7 9 1 7 0 6]
[9 9 7 6 9 1]
[0 1 8 8 3 9]
[8 7 3 6 5 1]
[9 3 4 8 1 4]
[0 3 9 2 0 4]
[9 2 7 7 9 8]]
Modified data...
[[5 8 9 5 0]
[7 6 9 2 4]
[5 2 4 4 7]
[7 9 1 7 6]
[9 9 7 6 9]
[1 8 8 3 9]
[8 7 3 6 5]
[9 3 4 8 4]
[0 3 9 2 4]
[9 7 7 9 8]]
L'une des astuces les moins lisibles que j'utilise ici consiste à exploiter la diffusion de numpy pendant les comparaisons de tableaux.À titre d'exemple rapide, considérez ce qui suit:
import numpy as np
a = np.array([[1, 2, 3]])
b = np.array([[1],[2],[3]])
print a == b
Cela donne:
array([[ True, False, False],
[False, True, False],
[False, False, True]], dtype=bool)
Donc, si nous connaissons l'index de colonne de l'élément que nous voulons supprimer, nous pouvons vectoriser l'opération pour un tableau d'index de colonne, ce que fait pop_col
.
Autres conseils
vous pouvez utiliser un tableau de masques booléens pour faire la sélection, mais l'utilisation de la mémoire est un peu grande.
import numpy
h = numpy.random.randint(0, 10, (20, 6))
flipped = numpy.fliplr(h) # flip the matrix to get the rightmost minimum.
flipped_indices = numpy.argmin(flipped, axis=1)
indices = 5 - flipped_indices
mask = numpy.ones(h.shape, numpy.bool)
mask[numpy.arange(h.shape[0]), indices] = False
result = h[mask].reshape(-1, 5)