¿Cómo acceder a la columna i-ésima de una matriz multidimensional NumPy?

463

Supongamos que tengo:

test = numpy.array([[1, 2], [3, 4], [5, 6]])

test[i]me pone ITH línea de la matriz (por ejemplo [1, 2]). ¿Cómo puedo acceder a la i-ésima columna? (por ejemplo [1, 3, 5]) Además, ¿sería una operación costosa?

lpl
fuente

Respuestas:

687
>>> test[:,0]
array([1, 3, 5])

Similar,

>>> test[1,:]
array([3, 4])

le permite acceder a filas. Esto está cubierto en la Sección 1.4 (Indexación) de la referencia NumPy . Esto es rápido, al menos en mi experiencia. Ciertamente es mucho más rápido que acceder a cada elemento en un bucle.

mtrw
fuente
11
Esto crea una copia, es posible obtener una referencia, como obtengo una referencia a una columna, cualquier cambio en esta referencia se refleja en la matriz original.
exige el
@harmands Esto no crea una copia, crea una vista.
rinspy
69

Y si desea acceder a más de una columna a la vez, puede hacer lo siguiente:

>>> test = np.arange(9).reshape((3,3))
>>> test
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
>>> test[:,[0,2]]
array([[0, 2],
       [3, 5],
       [6, 8]])
Akavall
fuente
aunque, por supuesto, en este caso no solo estás accediendo a los datos; está devolviendo una copia (indexación elegante)
John Greenall
14
test[:,[0,2]]solo accede a los datos, por ejemplo, test[:, [0,2]] = somethingmodificaría la prueba y no crearía otra matriz. Pero copy_test = test[:, [0,2]], de hecho, crea una copia como usted dice.
Akavall
3
Esto crea una copia, ¿es posible obtener una referencia, como obtengo una referencia a algunas columnas, cualquier cambio en esta referencia se refleja en la matriz original?
exige el
@ harman786 podría simplemente reasignar la matriz modificada a la anterior.
Tamoghna Chowdhury
¿Por qué test[:,[0,2]]solo accede a los datos mientras test[:, [0, 2]][:, [0, 1]]no lo hace? Parece muy poco intuitivo que hacer lo mismo nuevamente tenga un resultado diferente.
mapf
65
>>> test[:,0]
array([1, 3, 5])

este comando le da un vector de fila, si solo desea recorrerlo, está bien, pero si desea apilar con alguna otra matriz con dimensión 3xN, tendrá

ValueError: all the input arrays must have same number of dimensions

mientras

>>> test[:,[0]]
array([[1],
       [3],
       [5]])

le proporciona un vector de columna, para que pueda realizar operaciones de concatenación o hstack.

p.ej

>>> np.hstack((test, test[:,[0]]))
array([[1, 2, 1],
       [3, 4, 3],
       [5, 6, 5]])
Nube
fuente
1
la indexación funciona también con más de una columna a la vez, por lo que el último ejemplo podría ser test [:, [0,1,0]] o test [:, [range (test.shape [1]) + [0]] ]
lib
55
+1 para especificar [:, [0]] vs [:, 0] para obtener un vector de columna en lugar de un vector de fila. Exactamente el comportamiento que estaba buscando. También +1 a lib para la nota de indexación adicional. Esta respuesta debe estar a la altura de la respuesta superior.
dhj
1
Esta respuesta debe ser elegida
Gusev Slava
22

También puede transponer y devolver una fila:

In [4]: test.T[0]
Out[4]: array([1, 3, 5])
Hotschke
fuente
He estado haciendo esto por un tiempo antes de buscar una forma más rápida de acceder a las columnas, me pregunto si esto es más rápido, más lento o igual que la prueba [:, [0]]
José Chamorro
6

Para obtener varias columnas independientes, simplemente:

> test[:,[0,2]]

obtendrás las columnas 0 y 2

Alberto Perez
fuente
2
¿En qué se diferencia esto de la respuesta de Akavall ?
Todos los trabajadores son esenciales
5

Aunque la pregunta ha sido respondida, permítanme mencionar algunos matices.

Digamos que está interesado en la primera columna de la matriz.

arr = numpy.array([[1, 2],
                   [3, 4],
                   [5, 6]])

Como ya sabe por otras respuestas, para obtenerlo en forma de "vector de fila" (matriz de formas (3,)), utilice el corte:

arr_c1_ref = arr[:, 1]  # creates a reference to the 1st column of the arr
arr_c1_copy = arr[:, 1].copy()  # creates a copy of the 1st column of the arr

Para verificar si una matriz es una vista o una copia de otra matriz, puede hacer lo siguiente:

arr_c1_ref.base is arr  # True
arr_c1_copy.base is arr  # False

ver ndarray.base .

Además de la diferencia obvia entre los dos (la modificación arr_c1_refafectará arr), el número de bytes para atravesar cada uno de ellos es diferente:

arr_c1_ref.strides[0]  # 8 bytes
arr_c1_copy.strides[0]  # 4 bytes

Ver avances . ¿Porque es esto importante? Imagine que tiene una matriz muy grande en Alugar de arr:

A = np.random.randint(2, size=(10000,10000), dtype='int32')
A_c1_ref = A[:, 1] 
A_c1_copy = A[:, 1].copy()

y desea calcular la suma de todos los elementos de la primera columna, es decir, A_c1_ref.sum()o A_c1_copy.sum(). Usar la versión copiada es mucho más rápido:

%timeit A_c1_ref.sum()  # ~248 µs
%timeit A_c1_copy.sum()  # ~12.8 µs

Esto se debe a la diferente cantidad de avances mencionados anteriormente:

A_c1_ref.strides[0]  # 40000 bytes
A_c1_copy.strides[0]  # 4 bytes

Aunque parezca que usar copias de columna es mejor, no siempre es así porque hacer una copia lleva tiempo y usa más memoria (en este caso, me llevó aproximadamente 200 µs crear el A_c1_copy ). Sin embargo, si necesitamos la copia en primer lugar, o si necesitamos hacer muchas operaciones diferentes en una columna específica de la matriz y estamos de acuerdo en sacrificar la memoria por la velocidad, entonces hacer una copia es el camino a seguir.

En el caso de que estemos interesados ​​en trabajar principalmente con columnas, podría ser una buena idea crear nuestra matriz en el orden de columna mayor ('F') en lugar del orden de fila mayor ('C') (que es el valor predeterminado ), y luego haga el corte como antes para obtener una columna sin copiarla:

A = np.asfortranarray(A)  # or np.array(A, order='F')
A_c1_ref = A[:, 1]
A_c1_ref.strides[0]  # 4 bytes
%timeit A_c1_ref.sum()  # ~12.6 µs vs ~248 µs

Ahora, realizar la operación de suma (o cualquier otra) en una vista de columna es mucho más rápido.

Finalmente, permítanme señalar que la transposición de una matriz y el uso de la división en filas es lo mismo que el uso de la división en columnas en la matriz original, porque la transposición se realiza simplemente intercambiando la forma y los pasos de la matriz original.

A.T[1,:].strides[0]  # 40000
X Æ A-12
fuente
3
>>> test
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

>>> ncol = test.shape[1]
>>> ncol
5L

Luego puede seleccionar la segunda - cuarta columna de esta manera:

>>> test[0:, 1:(ncol - 1)]
array([[1, 2, 3],
       [6, 7, 8]])
Mac
fuente