Numpy: Comment se débarrasser des minima le long de l'axe= 1, compte tenu des indices - de manière efficace?

StackOverflow https://stackoverflow.com/questions/9368264

  •  28-10-2019
  •  | 
  •  

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.

Était-ce utile?

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)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top