web-dev-qa-db-fra.com

Sélection de lignes et de colonnes spécifiques du tableau NumPy

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

J'utilise NumPy et j'ai des index de lignes spécifiques et des index de colonnes spécifiques que je souhaite sélectionner. Voici l'essentiel 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 arrive-t-il? Je devrais sûrement pouvoir sélectionner les 1ère, 2ème et 4ème lignes et les 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]]
67
Mike C

L'indexation de fantaisie nécessite que vous fournissiez tous les index pour chaque dimension. Vous fournissez 3 index pour le premier et seulement 2 pour le second, d’où l’erreur. Vous voulez faire quelque chose comme ça:

>>> 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 pénible à écrire, vous pouvez donc laisser la radiodiffusion vous aider:

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

C'est beaucoup plus simple 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]])
62
Jaime

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

_>>> 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]])
_

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

J'ai récemment découvert que numpy vous donne la possibilité de faire exactement ce que @Jaime a suggéré, mais sans avoir à utiliser la syntaxe de diffusion (qui souffre d'un manque de lisibilité). De la docs:

En utilisant ix_, on peut rapidement construire des tableaux d’index qui indexeront le produit croisé. a[np.ix_([1,3],[2,5])] renvoie le tableau _[[a[1,2] a[1,5]], [a[3,2] a[3,5]]]_.

Donc, vous l'utilisez 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 cela fonctionne est qu’il prend en charge l’alignement des tableaux comme Jaime l’a suggéré, pour que la diffusion se déroule correctement:

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

De plus, 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’avait pas. Cela signifie que vous pouvez maintenant affecter au 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]])
_
53
Praveen

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]])
5
Toan Nguyen