Capítulo 1. Trabajar con vectores, matricesy matrices en NumPy
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com
1.0 Introducción
NumPy es una herramienta fundacional de de la pila de aprendizaje automático de Python. NumPy permite realizar operaciones eficientes con las estructuras de datos que se utilizan a menudo en el aprendizaje automático: vectores, matrices y tensores. Aunque NumPy no es el tema central de este libro, aparecerá con frecuencia en los capítulos siguientes. Este capítulo cubre las operaciones NumPy más comunes con las que probablemente nos encontremos al trabajar en flujos de trabajo de aprendizaje automático.
1.1 Crear un vector
Solución
Utiliza NumPy para crear una matriz unidimensional:
# Load library
import
numpy
as
np
# Create a vector as a row
vector_row
=
np
.
array
([
1
,
2
,
3
])
# Create a vector as a column
vector_column
=
np
.
array
([[
1
],
[
2
],
[
3
]])
Debate
La principal estructura de datos de NumPy es la matriz multidimensional. Un vector no es más que una matriz con una sola dimensión. Para crear un vector, simplemente creamos una matriz unidimensional. Al igual que los vectores, estas matrices pueden representarse horizontalmente (es decir, filas) o verticalmente (es decir, columnas).
1.2 Crear una matriz
Debate
Para crear una matriz podemos utilizar una matriz bidimensional NumPy. En nuestra solución, la matriz contiene tres filas y dos columnas (una columna de 1s y otra de 2s).
De hecho, NumPy tiene una estructura de datos matricial específica:
matrix_object
=
np
.
mat
([[
1
,
2
],
[
1
,
2
],
[
1
,
2
]])
matrix([[1, 2], [1, 2], [1, 2]])
Sin embargo, la estructura de datos matrices no es recomendable por dos razones. En primer lugar, las matrices son la estructura de datos estándar de facto de NumPy. En segundo lugar, la inmensa mayoría de las operaciones de NumPy devuelven matrices, no objetos matriz.
Ver también
1.3 Crear una matriz dispersa
Solución
Crea una matriz dispersa:
# Load libraries
import
numpy
as
np
from
scipy
import
sparse
# Create a matrix
matrix
=
np
.
array
([[
0
,
0
],
[
0
,
1
],
[
3
,
0
]])
# Create compressed sparse row (CSR) matrix
matrix_sparse
=
sparse
.
csr_matrix
(
matrix
)
Debate
Una situación frecuente en el aprendizaje automático es tener una enorme cantidad de datos; sin embargo, la mayoría de los elementos de los datos son ceros. Por ejemplo, imagina una matriz en la que las columnas sean todas las películas de Netflix, las filas sean todos los usuarios de Netflix y los valores sean cuántas veces ha visto un usuario esa película en concreto. ¡Esta matriz tendría decenas de miles de columnas y millones de filas! Sin embargo, como la mayoría de los usuarios no ven la mayoría de las películas, la inmensa mayoría de los elementos serían cero.
Una matriz dispersa es una matriz en la que la mayoría de los elementos son 0. Las matrices dispersas sólo almacenan elementos distintos de cero y asumen que todos los demás valores serán cero, lo que supone un importante ahorro computacional. En nuestra solución, creamos una matriz NumPy con dos valores distintos de cero, y luego la convertimos en una matriz dispersa. Si visualizamos la matriz dispersa, podemos ver que sólo se almacenan los valores distintos de cero:
# View sparse matrix
(
matrix_sparse
)
(1, 1) 1 (2, 0) 3
Existen varios tipos de matrices dispersas. Sin embargo, en las matrices comprimidas de filas dispersas (CSR), (1, 1)
y (2, 0)
representan los índices (indexados a cero) de los valores distintos de cero 1
y 3
, respectivamente. Por ejemplo, el elemento 1
está en la segunda fila y la segunda columna. Podemos ver la ventaja de las matrices dispersas si creamos una matriz mucho mayor con muchos más elementos cero y luego comparamos esta matriz mayor con nuestra matriz dispersa original:
# Create larger matrix
matrix_large
=
np
.
array
([[
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
],
[
0
,
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
],
[
3
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
]])
# Create compressed sparse row (CSR) matrix
matrix_large_sparse
=
sparse
.
csr_matrix
(
matrix_large
)
# View original sparse matrix
(
matrix_sparse
)
(1, 1) 1 (2, 0) 3
# View larger sparse matrix
(
matrix_large_sparse
)
(1, 1) 1 (2, 0) 3
Como podemos ver, a pesar de que añadimos muchos más elementos cero en la matriz más grande, su representación dispersa es exactamente la misma que nuestra matriz dispersa original. Es decir, la adición de elementos cero no cambió el tamaño de la matriz dispersa.
Como ya se ha dicho, hay muchos tipos distintos de matrices dispersas, como la columna dispersa comprimida, la lista de listas y el diccionario de claves. Aunque una explicación de los distintos tipos y sus implicaciones queda fuera del alcance de este libro, merece la pena señalar que, aunque no existe el "mejor" tipo de matriz dispersa, sí hay diferencias significativas entre ellas, y debemos ser conscientes de por qué elegimos un tipo en lugar de otro.
1.4 Preasignar matrices NumPy
Solución
NumPy tiene funciones para generar vectores y matrices de cualquier tamaño utilizando 0s, 1s o valores de tu elección:
# Load library
import
numpy
as
np
# Generate a vector of shape (1,5) containing all zeros
vector
=
np
.
zeros
(
shape
=
5
)
# View the matrix
(
vector
)
array([0., 0., 0., 0., 0.])
# Generate a matrix of shape (3,3) containing all ones
matrix
=
np
.
full
(
shape
=
(
3
,
3
),
fill_value
=
1
)
# View the vector
(
matrix
)
array([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]])
Debate
Generar matrices preasignadas con datos es útil para varios fines, como hacer que el código tenga un mayor rendimiento o utilizar datos sintéticos para probar algoritmos. En muchos lenguajes de programación, preasignar una matriz de valores por defecto (como 0s) se considera una práctica habitual.
1.5 Seleccionar elementos
Solución
Las matrices NumPy facilitan la selección de elementos en vectores o matrices:
# Load library
import
numpy
as
np
# Create row vector
vector
=
np
.
array
([
1
,
2
,
3
,
4
,
5
,
6
])
# Create matrix
matrix
=
np
.
array
([[
1
,
2
,
3
],
[
4
,
5
,
6
],
[
7
,
8
,
9
]])
# Select third element of vector
vector
[
2
]
3
# Select second row, second column
matrix
[
1
,
1
]
5
Debate
Como la mayoría de las cosas en Python, las matrices de NumPy tienen índice cero, lo que significa que el índice del primer elemento es 0, no 1. Con esa salvedad, NumPy ofrece una amplia variedad de métodos para seleccionar (es decir, indexar y trocear) elementos o grupos de elementos en matrices:
# Select all elements of a vector
vector
[:]
array([1, 2, 3, 4, 5, 6])
# Select everything up to and including the third element
vector
[:
3
]
array([1, 2, 3])
# Select everything after the third element
vector
[
3
:]
array([4, 5, 6])
# Select the last element
vector
[
-
1
]
6
# Reverse the vector
vector
[::
-
1
]
array([6, 5, 4, 3, 2, 1])
# Select the first two rows and all columns of a matrix
matrix
[:
2
,:]
array([[1, 2, 3], [4, 5, 6]])
# Select all rows and the second column
matrix
[:,
1
:
2
]
array([[2], [5], [8]])
1.6 Describir una matriz
Solución
Utiliza los atributos shape
, size
, y ndim
de un objeto NumPy:
# Load library
import
numpy
as
np
# Create matrix
matrix
=
np
.
array
([[
1
,
2
,
3
,
4
],
[
5
,
6
,
7
,
8
],
[
9
,
10
,
11
,
12
]])
# View number of rows and columns
matrix
.
shape
(3, 4)
# View number of elements (rows * columns)
matrix
.
size
12
# View number of dimensions
matrix
.
ndim
2
Debate
Esto puede parecer básico (y lo es); sin embargo, una y otra vez será valioso comprobar la forma y el tamaño de una matriz, tanto para cálculos posteriores como simplemente como comprobación visceral tras una operación.
1.7 Aplicar funciones sobre cada elemento
Solución
Utiliza el método NumPy vectorize
:
# Load library
import
numpy
as
np
# Create matrix
matrix
=
np
.
array
([[
1
,
2
,
3
],
[
4
,
5
,
6
],
[
7
,
8
,
9
]])
# Create function that adds 100 to something
add_100
=
lambda
i
:
i
+
100
# Create vectorized function
vectorized_add_100
=
np
.
vectorize
(
add_100
)
# Apply function to all elements in matrix
vectorized_add_100
(
matrix
)
array([[101, 102, 103], [104, 105, 106], [107, 108, 109]])
Debate
El método vectorize
de NumPy convierte una función en una función que puede aplicarse a todos los elementos de una matriz o porción de una matriz. Cabe señalar que vectorize
es esencialmente un bucle for
sobre los elementos y no aumenta el rendimiento. Además, las matrices de NumPy nos permiten realizar operaciones entre matrices aunque sus dimensiones no sean las mismas (un proceso llamado difusión). Por ejemplo, podemos crear una versión mucho más sencilla de nuestra solución utilizando la difusión:
# Add 100 to all elements
matrix
+
100
array([[101, 102, 103], [104, 105, 106], [107, 108, 109]])
La difusión no funciona para todas las formas y situaciones, pero es una forma habitual de aplicar operaciones sencillas sobre todos los elementos de una matriz NumPy.
1.8 Encontrar los valores máximo y mínimo
Solución
Utiliza los métodos max
y min
de NumPy:
# Load library
import
numpy
as
np
# Create matrix
matrix
=
np
.
array
([[
1
,
2
,
3
],
[
4
,
5
,
6
],
[
7
,
8
,
9
]])
# Return maximum element
np
.
max
(
matrix
)
9
# Return minimum element
np
.
min
(
matrix
)
1
Debate
A menudo queremos conocer el valor máximo y mínimo de una matriz o subconjunto de una matriz. Esto se puede conseguir con los métodos max
y min
. Utilizando el parámetro axis
, también podemos aplicar la operación a lo largo de un eje determinado:
# Find maximum element in each column
np
.
max
(
matrix
,
axis
=
0
)
array([7, 8, 9])
# Find maximum element in each row
np
.
max
(
matrix
,
axis
=
1
)
array([3, 6, 9])
1.9 Calcular la media, la varianza y la desviación típica
Debate
Al igual que con max
y min
, podemos obtener fácilmente estadísticas descriptivas de toda la matriz o hacer cálculos a lo largo de un solo eje:
# Find the mean value in each column
np
.
mean
(
matrix
,
axis
=
0
)
array([ 4., 5., 6.])
1.10 Remodelar matrices
Solución
Utiliza la página reshape
de NumPy:
# Load library
import
numpy
as
np
# Create 4x3 matrix
matrix
=
np
.
array
([[
1
,
2
,
3
],
[
4
,
5
,
6
],
[
7
,
8
,
9
],
[
10
,
11
,
12
]])
# Reshape matrix into 2x6 matrix
matrix
.
reshape
(
2
,
6
)
array([[ 1, 2, 3, 4, 5, 6], [ 7, 8, 9, 10, 11, 12]])
Debate
reshape
nos permite reestructurar una matriz de modo que mantengamos los mismos datos pero los organicemos con un número diferente de filas y columnas. El único requisito es que la forma de la matriz original y la nueva contengan el mismo número de elementos (es decir, tengan el mismo tamaño). Podemos ver el tamaño de una matriz utilizando size
:
matrix
.
size
12
Un argumento útil en reshape
es -1
, que significa efectivamente "tantas como sean necesarias", por lo que reshape(1, -1)
significa una fila y tantas columnas como sean necesarias:
matrix
.
reshape
(
1
,
-
1
)
array([[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]])
Por último, si proporcionamos un número entero, reshape
devolverá una matriz unidimensional de esa longitud:
matrix
.
reshape
(
12
)
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
1.11 Transponer un vector o una matriz
Debate
La transposición es una operación habitual en álgebra lineal en la que se intercambian los índices de columna y fila de cada elemento. Un matiz que suele pasarse por alto fuera de una clase de álgebra lineal es que, técnicamente, un vector no puede transponerse porque no es más que una colección de valores:
# Transpose vector
np
.
array
([
1
,
2
,
3
,
4
,
5
,
6
])
.
T
array([1, 2, 3, 4, 5, 6])
Sin embargo, es habitual referirse a la transposición de un vector como la conversión de un vector fila en un vector columna (fíjate en el segundo par de corchetes) o viceversa:
# Transpose row vector
np
.
array
([[
1
,
2
,
3
,
4
,
5
,
6
]])
.
T
array([[1], [2], [3], [4], [5], [6]])
1.12 Aplanar una matriz
Debate
flatten
es un método sencillo para transformar una matriz en una matriz unidimensional. Alternativamente, podemos utilizar reshape
para crear un vector de filas:
matrix
.
reshape
(
1
,
-
1
)
array([[1, 2, 3, 4, 5, 6, 7, 8, 9]])
Otra forma habitual de aplanar matrices es el método ravel
. A diferencia de flatten
, que devuelve una copia de la matriz original, ravel
opera sobre el propio objeto original y, por tanto, es ligeramente más rápido. También nos permite aplanar listas de matrices, cosa que no podemos hacer con el método flatten
. Esta operación es útil para aplanar matrices muy grandes y acelerar el código:
# Create one matrix
matrix_a
=
np
.
array
([[
1
,
2
],
[
3
,
4
]])
# Create a second matrix
matrix_b
=
np
.
array
([[
5
,
6
],
[
7
,
8
]])
# Create a list of matrices
matrix_list
=
[
matrix_a
,
matrix_b
]
# Flatten the entire list of matrices
np
.
ravel
(
matrix_list
)
array([1, 2, 3, 4, 5, 6, 7, 8])
1.13 Hallar el rango de una matriz
Debate
El rango de una matriz son las dimensiones del espacio vectorial que abarcan sus columnas o filas. Encontrar el rango de una matriz es fácil en NumPy gracias a matrix_rank
.
Ver también
1.14 Obtener la diagonal de una matriz
Solución
Utiliza la página diagonal
de NumPy:
# Load library
import
numpy
as
np
# Create matrix
matrix
=
np
.
array
([[
1
,
2
,
3
],
[
2
,
4
,
6
],
[
3
,
8
,
9
]])
# Return diagonal elements
matrix
.
diagonal
()
array([1, 4, 9])
Debate
NumPy facilita la obtención de los elementos diagonales de una matriz condiagonal
. También es posible obtener una diagonal fuera de la diagonal principal utilizando el parámetro offset
:
# Return diagonal one above the main diagonal
matrix
.
diagonal
(
offset
=
1
)
array([2, 6])
# Return diagonal one below the main diagonal
matrix
.
diagonal
(
offset
=-
1
)
array([2, 8])
1.15 Calcular la traza de una matriz
Solución
Utiliza trace
:
# Load library
import
numpy
as
np
# Create matrix
matrix
=
np
.
array
([[
1
,
2
,
3
],
[
2
,
4
,
6
],
[
3
,
8
,
9
]])
# Return trace
matrix
.
trace
()
14
Debate
La traza de una matriz es la suma de los elementos diagonales y se utiliza a menudo en métodos de aprendizaje automático. Dada una matriz multidimensional NumPy, podemos calcular la traza utilizando trace
. Alternativamente, podemos devolver la diagonal de una matriz y calcular su suma:
# Return diagonal and sum elements
sum
(
matrix
.
diagonal
())
14
Ver también
1.16 Calcular productos de puntos
Debate
El producto punto de dos vectores, y se define como
donde es la elemento del vectory es el elemento elemento del vector. Podemos utilizar la función dot
de NumPy para calcular el producto punto. Como alternativa, en Python 3.5+ podemos utilizar el nuevo operador @
:
# Calculate dot product
vector_a
@
vector_b
32
1.17 Sumar y restar matrices
Solución
Utiliza NumPy's add
y subtract
:
# Load library
import
numpy
as
np
# Create matrix
matrix_a
=
np
.
array
([[
1
,
1
,
1
],
[
1
,
1
,
1
],
[
1
,
1
,
2
]])
# Create matrix
matrix_b
=
np
.
array
([[
1
,
3
,
1
],
[
1
,
3
,
1
],
[
1
,
3
,
8
]])
# Add two matrices
np
.
add
(
matrix_a
,
matrix_b
)
array([[ 2, 4, 2], [ 2, 4, 2], [ 2, 4, 10]])
# Subtract two matrices
np
.
subtract
(
matrix_a
,
matrix_b
)
array([[ 0, -2, 0], [ 0, -2, 0], [ 0, -2, -6]])
1.18 Multiplicar matrices
Solución
Utiliza la página dot
de NumPy:
# Load library
import
numpy
as
np
# Create matrix
matrix_a
=
np
.
array
([[
1
,
1
],
[
1
,
2
]])
# Create matrix
matrix_b
=
np
.
array
([[
1
,
3
],
[
1
,
2
]])
# Multiply two matrices
np
.
dot
(
matrix_a
,
matrix_b
)
array([[2, 5], [3, 7]])
Debate
Como alternativa, en Python 3.5+ podemos utilizar el operador @
:
# Multiply two matrices
matrix_a
@
matrix_b
array([[2, 5], [3, 7]])
Si queremos hacer una multiplicación por elementos, podemos utilizar el operador *
:
# Multiply two matrices element-wise
matrix_a
*
matrix_b
array([[1, 3], [1, 4]])
Ver también
1.19 Invertir una matriz
Solución
Utiliza el método de álgebra lineal de NumPy inv
:
# Load library
import
numpy
as
np
# Create matrix
matrix
=
np
.
array
([[
1
,
4
],
[
2
,
5
]])
# Calculate inverse of matrix
np
.
linalg
.
inv
(
matrix
)
array([[-1.66666667, 1.33333333], [ 0.66666667, -0.33333333]])
Debate
La inversa de una matriz cuadrada, A, es una segunda matriz, A-1, tal que:
donde I es la matriz de identidad . En NumPy podemos utilizar linalg.inv
para calcular A-1 si existe. Para ver esto en acción, podemos multiplicar una matriz por su inversa, y el resultado es la matriz identidad:
# Multiply matrix and its inverse
matrix
@
np
.
linalg
.
inv
(
matrix
)
array([[ 1., 0.], [ 0., 1.]])
Ver también
1.20 Generar valores aleatorios
Debate
NumPy ofrece una gran variedad de medios para generar números aleatorios, muchos más de los que se pueden abarcar aquí. En nuestra solución generamos flotantes; sin embargo, también es habitual generar enteros:
# Generate three random integers between 0 and 10
np
.
random
.
randint
(
0
,
11
,
3
)
array([3, 7, 9])
Alternativamente, podemos generar números extrayéndolos de una distribución (ten en cuenta que esto no es técnicamente aleatorio):
# Draw three numbers from a normal distribution with mean 0.0
# and standard deviation of 1.0
np
.
random
.
normal
(
0.0
,
1.0
,
3
)
array([-1.42232584, 1.52006949, -0.29139398])
# Draw three numbers from a logistic distribution with mean 0.0 and scale of 1.0
np
.
random
.
logistic
(
0.0
,
1.0
,
3
)
array([-0.98118713, -0.08939902, 1.46416405])
# Draw three numbers greater than or equal to 1.0 and less than 2.0
np
.
random
.
uniform
(
1.0
,
2.0
,
3
)
array([ 1.47997717, 1.3927848 , 1.83607876])
Por último, a veces puede ser útil devolver los mismos números aleatorios varias veces para obtener resultados predecibles y repetibles. Podemos hacerlo fijando la "semilla" (un número entero) del generador pseudoaleatorio. Los procesos aleatorios con la misma semilla producirán siempre el mismo resultado. Utilizaremos semillas a lo largo de este libro para que el código que veas en el libro y el que ejecutes en tu ordenador produzcan los mismos resultados.
Get Recetario de Aprendizaje Automático con Python, 2ª Edición now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.