Tranche d'index Numpy sans perdre les informations de dimension

98

J'utilise numpy et je souhaite indexer une ligne sans perdre les informations de dimension.

import numpy as np
X = np.zeros((100,10))
X.shape        # >> (100, 10)
xslice = X[10,:]
xslice.shape   # >> (10,)  

Dans cet exemple, xslice est maintenant à 1 dimension, mais je veux qu'il soit (1,10). Dans R, j'utiliserais X [10,:, drop = F]. Y a-t-il quelque chose de similaire dans numpy. Je n'ai pas pu le trouver dans la documentation et je n'ai pas vu une question similaire posée.

Merci!

mindmatters
la source

Réponses:

59

C'est probablement le plus facile à faire x[None, 10, :]ou de manière équivalente (mais plus lisible) x[np.newaxis, 10, :].

Quant à savoir pourquoi ce n'est pas la valeur par défaut, personnellement, je trouve que le fait d'avoir constamment des tableaux avec des dimensions singleton devient très vite ennuyeux. Je suppose que les développeurs numpy ressentaient la même chose.

De plus, numpy gère très bien les tableaux de diffusion, il y a donc généralement peu de raisons de conserver la dimension du tableau d'où provient la tranche. Si vous l'avez fait, alors des choses comme:

a = np.zeros((100,100,10))
b = np.zeros(100,10)
a[0,:,:] = b

soit ne fonctionnerait pas, soit serait beaucoup plus difficile à mettre en œuvre.

(Ou du moins, c'est mon hypothèse sur le raisonnement du développeur numpy derrière la suppression des informations de dimension lors du découpage)

Joe Kington
la source
6
@Lisa: x[None, 10]fera ce que vous voulez.
naught101
Ouaip. Mettez vos Nones à côté des dims que vous hachez.
Mad Physicist
1
L'exemple manque de crochets supplémentaires pour le tuple dans l'affectation à b; ça devrait être b = np.zeros((100,10)).
Jerzy
Quelle est la raison d'utiliser 3 indices au total au lieu de seulement deux? Je veux dire X[10,None](en utilisant votre code comme exemple).
greenoldman
8
" il y a généralement peu de raisons de conserver la dimension du tableau " ... Eh bien, ce sera certainement, complètement, et complètement bousiller la multiplication matricielle ( np.matmul()ou@ ). Je viens de me brûler.
Jean-François Corbett
89

Une autre solution est de faire

X[[10],:]

ou

I = array([10])
X[I,:]

La dimensionnalité d'un tableau est préservée lorsque l'indexation est effectuée par une liste (ou un tableau) d'index. C'est bien car cela vous laisse le choix entre garder la dimension et serrer.

gnebehay
la source
2
Ceci copie les données du tableau
Par
Ce n'est pas toujours le cas. Voir: x = np.array([[1,2,3,4]]) si vous le découpez ensuite avec x[[0],[1,2]] vous obtenez le unidimensionnel.Mon array([2, 3]) avis est que lors de la sélection de vecteurs de colonnes ou de lignes, il est préférable de simplifier la tranche, puis de l'utiliser np.reshape, donc dans mon exemple, ce seraitnp.reshape(x[0,[1,2]],[1,2])
Alexander
1
d'autres, faites attention à un point-virgule à la fin - c'est important, X[[10]]serait interprété comme X[10]et la forme sera plus petite; de même, X[[10, 20]] == X[10, 20]et la forme est encore plus petite
Ben Usman
1
Attention : ne mélangez pas cette méthode d'indexation avec une indexation entière! Si vous aviez ade la forme (10, 20, 30), alors a[0, :, [0]]aura la forme (1, 20), non (20, 1), car dans ces derniers sont diffusés des index à a[[0], :, [0]]ce qui n'est souvent pas tout à fait ce que vous attendez! Alors que a[0, :, :1]vous donnera (20, 1)comme prévu. De plus, voir le commentaire ci-dessus pour un cas de bord étrange avec un seul index. Dans l'ensemble, il semble que cette méthode comporte trop de cas extrêmes.
Ben Usman
30

J'ai trouvé quelques solutions raisonnables.

1) utiliser numpy.take(X,[10],0)

2) Utilisez cette étrange indexation X[10:11:, :]

Idéalement, cela devrait être la valeur par défaut. Je n'ai jamais compris pourquoi les dimensions sont jamais abandonnées. Mais c'est une discussion pour numpy ...

mindmatters
la source
1
Les 'dimensions' sont supprimées lors de l'indexation des listes Python alist[0]et conservées lors de leur découpage.
hpaulj
4
L'option 2 (qui peut être écrite comme slice(n, n+1)pour l'extraction d'index n) devrait être la réponse acceptée, car c'est la seule qui s'étend naturellement au cas à n dimensions.
norok2
L'option 2 semble pouvoir être écrite comme X[10:11, :]dans Python 3.7.5 (c'est-à-dire sans les deux points supplémentaires après le 11)
Joe
6

Voici une alternative que j'aime mieux. Au lieu d'indexer avec un seul nombre, indexez avec une plage. Autrement dit, utilisez X[10:11,:]. (Notez que 10:11n'inclut pas 11).

import numpy as np
X = np.zeros((100,10))
X.shape        # >> (100, 10)
xslice = X[10:11,:]
xslice.shape   # >> (1,10)

Cela facilite également la compréhension avec plus de dimensions, non None jonglage et de déterminer quel axe utiliser quel index. Il n'est pas non plus nécessaire de faire une comptabilité supplémentaire concernant la taille du tableau, juste i:i+1pour celles ique vous auriez utilisées dans l'indexation régulière.

b = np.ones((2, 3, 4))
b.shape # >> (2, 3, 4)
b[1:2,:,:].shape  # >> (1, 3, 4)
b[:, 2:3, :].shape .  # >> (2, 1, 4)
Andrew Schwartz
la source
0

Ceci est particulièrement ennuyeux si vous indexez par un tableau qui peut être de longueur 1 au moment de l'exécution. Pour ce cas, il y a np.ix_:

some_array[np.ix_(row_index,column_index)]
Jthorpe
la source