Sélection de lignes et de colonnes spécifiques à partir du tableau Nummpy

je suis devenu fou en essayant de comprendre quelle chose stupide je fais mal ici.

J'utilise NumPy, et j'ai des indices de ligne spécifiques et des indices de colonne spécifiques que je veux sélectionner. Voici le résumé de mon problème:

import numpy as np

a = np.arange(20).reshape((5,4))
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [ 8,  9, 10, 11],
#        [12, 13, 14, 15],
#        [16, 17, 18, 19]])

# If I select certain rows, it works
print a[[0, 1, 3], :]
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [12, 13, 14, 15]])

# If I select certain rows and a single column, it works
print a[[0, 1, 3], 2]
# array([ 2,  6, 14])

# But if I select certain rows AND certain columns, it fails
print a[[0,1,3], [0,2]]
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# ValueError: shape mismatch: objects cannot be broadcast to a single shape

pourquoi cela se produit-il? Est-ce que je devrais être capable de choisir les 1ère, 2ème, et 4ème lignes, et 1ère et 3ème colonnes? Le résultat que j'attends est:

a[[0,1,3], [0,2]] => [[0,  2],
                      [4,  6],
                      [12, 14]]
47
demandé sur smci 2014-04-08 07:52:52

3 réponses

l'indexation de fantaisie exige que vous fournissiez tous les indices pour chaque dimension. Vous offrant 3 indices pour le premier, et seulement 2 pour la seconde, d'où l'erreur. Vous voulez faire quelque chose comme ceci:

>>> a[[[0, 0], [1, 1], [3, 3]], [[0,2], [0,2], [0, 2]]]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

C'est bien sûr une douleur d'écrire, de sorte que vous pouvez laisser de radiodiffusion de vous aider:

>>> a[[[0], [1], [3]], [0, 2]]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

C'est beaucoup plus simple à faire si vous indexez avec des tableaux, pas des listes:

>>> row_idx = np.array([0, 1, 3])
>>> col_idx = np.array([0, 2])
>>> a[row_idx[:, None], col_idx]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])
44
répondu Jaime 2014-04-08 04:59:26

comme Toan le suggère, un hack simple serait de simplement sélectionner les lignes en premier, puis de sélectionner les colonnes sur .

>>> a[[0,1,3], :]            # Returns the rows you want
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [12, 13, 14, 15]])
>>> a[[0,1,3], :][:, [0,2]]  # Selects the columns you want as well
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

[Edit] La méthode intégrée: np.ix_

j'ai récemment découvert que numpy vous donne un one-liner pour faire exactement ce que @Jaime a suggéré, mais sans avoir à utiliser la syntaxe de radiodiffusion (qui souffre d'un manque de lisibilité). À partir de la documentation:

en utilisant ix_ on peut rapidement construire des tableaux d'index qui indexeront le la croix du produit. a[np.ix_([1,3],[2,5])] renvoie le tableau [[a[1,2] a[1,5]], [a[3,2] a[3,5]]].

Si vous l'utiliser comme ceci:

>>> a = np.arange(20).reshape((5,4))
>>> a[np.ix_([0,1,3], [0,2])]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

Et la façon dont il fonctionne, c'est qu'il prend soin d'aligner les tableaux de la façon dont Jaime suggéré, afin de radiodiffusion se passe correctement:

>>> np.ix_([0,1,3], [0,2])
(array([[0],
        [1],
        [3]]), array([[0, 2]]))

aussi, comme le dit MikeC dans un commentaire,np.ix_ a l'avantage de renvoyer une vue, ce que ma première réponse (pré-édition) n'a pas fait. Ce signifie que vous pouvez maintenant assign pour le tableau indexé:

>>> a[np.ix_([0,1,3], [0,2])] = -1
>>> a    
array([[-1,  1, -1,  3],
       [-1,  5, -1,  7],
       [ 8,  9, 10, 11],
       [-1, 13, -1, 15],
       [16, 17, 18, 19]])
35
répondu Praveen 2017-06-28 22:50:36

UTILISATION:

 >>> a[[0,1,3]][:,[0,2]]
array([[ 0,  2],
   [ 4,  6],
   [12, 14]])

OU:

>>> a[[0,1,3],::2]
array([[ 0,  2],
   [ 4,  6],
   [12, 14]])
4
répondu Toan Nguyen 2014-04-08 07:39:43