2 Numpy
2 Numpy
2 Numpy
0.1 Introduccin
El paquete (mdulo) numpy es usado en casi todos los clculos numricos usando Python. Es un
paquete que provee a Python de estructuras de datos vectoriales, matriciales, y de rango mayor,
de alto rendimiento. Est implementado en C y Fortran, de modo que cuando los clculos son
vectorizados (formulados con vectores y matrices), el rendimiento es muy bueno.
Para usar numpy necesitamos importar el mdulo usando, por ejemplo:
1
In [278]: # una matriz: el argumento de la funcin array es una lista anidada de Python
M = np.array([[1, 2], [3, 4]])
Los objetos v y M son ambos del tipo ndarray que provee el mdulo numpy.
In [280]: v.shape
Out[280]: (4,)
In [281]: M.shape
Out[281]: (2, 2)
In [282]: M.size
Out[282]: 4
In [283]: np.shape(M)
Out[283]: (2, 2)
In [284]: np.size(M)
Out[284]: 4
Hasta el momento el arreglo numpy.ndarray luce como una lista Python (anidada). Entonces,
por qu simplemente no usar listas para hacer clculos en lugar de crear un tipo nuevo de ar-
reglo?
Existen varias razones:
Las listas Python son muy generales. Ellas pueden contener cualquier tipo de objeto. Sus
tipos son asignados dinmicamente. Ellas no permiten usar funciones matemticas tales
como la multiplicacin de matricies, el producto escalar, etc. El implementar tales funciones
para las listas Python no sera muy eficiente debido a la asignacin dinmica de su tipo.
2
Los arreglos Numpy tienen tipo esttico y homogneo. El tipo de elementos es determinado
cuando se crea el arreglo.
Los arreglos Numpy son eficientes en el uso de memoria.
Debido a su tipo esttico, se pueden desarrollar implementaciones rpidas de funciones
matemticas tales como la multiplicacin y la suma de arreglos numpy usando lenguajes
compilados (se usan C y Fortran).
Usando la propiedad dtype (tipo de dato) de un ndarray, podemos ver qu tipo de dato con-
tiene un arreglo:
In [285]: M.dtype
Out[285]: dtype('int64')
---------------------------------------------------------------------------
<ipython-input-286-fc4abc9a80ec> in <module>()
----> 1 M[0,0] = "hola"
Algunos tipos comunes que pueden ser usados con dtype son: int, float, complex, bool,
object, etc.
Podemos tambin definir explcitamente el nmero de bit de los tipos de datos, por ejemplo:
int64, int16, float64, complex64.
Usando funciones que generan arreglos En el caso de arreglos ms grandes no es prctico ini-
cializar los datos manualmente, usando listas Python explcitas. En su lugar, podemos usar una
de las muchas funciones en numpy que generan arreglos de diferentes formas. Algunos de los ms
comunes son:
3
arange
linspace y logspace
In [290]: # usando linspace, ambos puntos finales SON incluidos. Formato: (desde, hasta, nmero
np.linspace(0, 10, 25)
mgrid
In [293]: x
4
Out[293]: array([[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1],
[2, 2, 2, 2, 2],
[3, 3, 3, 3, 3],
[4, 4, 4, 4, 4]])
In [294]: y
Datos aleatorios
In [297]: # nmeros aleatorios con distribucin estndar normal (distribucin gaussiana de medi
random.randn(2,5)
diag
5
ceros y unos
In [301]: np.zeros((3,3))
In [302]: np.ones((3,3))
In [304]: data.shape
Out[304]: (77431, 7)
6
Usando numpy.savetxt podemos almacenar un arreglo Numpy a un archivo en formato CSV:
In [307]: M = random.rand(3,3)
In [308]: np.savetxt("matriz-aleatoria.csv", M)
Out[310]: 8
Out[311]: 72
Out[312]: 2
In [313]: # v es un vector, tiene por lo tanto slo una dimensin, y requiere un ndice
v[0]
Out[313]: 1
Out[314]: 0.28584833605487769
Si omitimos un ndice de una arreglo multidimensional Numpy entrega la fila completa (o, en
general, al arreglo de dimensin N-1 correspondiente)
In [315]: M
7
Out[315]: array([[ 0.57607811, 0.57379336, 0.94826872],
[ 0.2655032 , 0.28584834, 0.40613708],
[ 0.92467302, 0.57783605, 0.21239031]])
In [316]: M[1]
In [319]: M[0,0] = 1
In [320]: M
In [322]: M
In [323]: A = np.array([1,2,3,4,5])
A
In [324]: A[1:3]
8
Los cortes de ndices son mutables: si se les asigna un nuevo valor el arreglo original es modi-
ficado:
In [326]: A[::] # desde, hasta y paso asumen los valores por defecto
In [327]: A[::2] # el paso es 2, desde y hasta se asumen desde el comienzo hasta el fin del arr
Los ndices negativos se cuentan desde el fin del arreglo (los ndices positivos desde el
comienzo):
In [330]: A = np.array([1,2,3,4,5])
Out[331]: 5
El corte de ndices funciona exactamente del mismo modo para arreglos multidimensionales:
9
In [334]: # un bloque parte del arreglo original
A[1:4, 1:4]
In [337]: indices_col = [1, 2, -1] # recuerde que el ndice -1 corresponde al ltimo elemento
A[indices_fila, indices_col]
Podemos tambin usar mscaras de ndices: Si la mscara de ndice es un arreglo Numpy con
tipo de dato booleano (bool), entonces un elemento es seleccionado (True) o no (False) dependi-
endo del valor de la mscara de ndice en la posicin de cada elemento:
In [340]: # lo mismo
masc_fila = np.array([1,0,1,0,0], dtype=bool)
B[masc_fila]
10
Esta caracterstica es muy til para seleccionar en forma condicional elementos de un arreglo,
usando por ejemplo los operadores de comparacin:
masc
Out[342]: array([False, False, False, False, False, False, False, False, False,
False, False, True, True, True, True, False, False, False,
False, False], dtype=bool)
In [343]: x[masc]
0.7 Funciones para extraer informacin desde arreglos y para crear nuevos arreglos
where Las mscaras de ndices pueden ser convertidas en posiciones de ndices usando la fun-
cin where (dnde):
indices
diag Con la funcin diag podemos extraer la diagonal y las subdiagonales de un arreglo:
In [346]: np.diag(A)
11
take La funcin take es similar al indexado fancy descrito anteriormente:
In [348]: v2 = np.arange(-3,3)
v2
In [350]: v2.take(indices_fila)
np.choose(cuales, posibilidades)
In [353]: v1 = np.arange(0, 5)
In [354]: 2*v1
In [355]: v1 + 2
12
In [356]: A * 2, A + 2
In [358]: v1 * v1
In [360]: A * v1
13
In [361]: np.dot(A, A)
In [362]: A @ A
In [363]: A @ v1
In [364]: v1 @ v1
Out[364]: 30
In [365]: M = np.matrix(A)
v = np.matrix(v1).T # aplica la traspuesta, convirtindolo en vector columna
In [366]: v
Out[366]: matrix([[0],
[1],
[2],
[3],
[4]])
In [367]: M*M
In [368]: M*v
14
Out[368]: matrix([[ 30],
[130],
[230],
[330],
[430]])
In [369]: # productor interior
v.T * v
Out[369]: matrix([[30]])
In [370]: # con objetos matriciales, el lgebra matricial estndar es usada
v + M*v
Out[370]: matrix([[ 30],
[131],
[232],
[333],
[434]])
Si intentamos sumar, restar, o multiplicar objetos con formas incompatibles, obtendremos un
error:
In [371]: v = np.matrix([1,2,3,4,5,6]).T
In [372]: np.shape(M), np.shape(v)
Out[372]: ((5, 5), (6, 1))
In [373]: M * v
---------------------------------------------------------------------------
<ipython-input-373-995fb48ad0cc> in <module>()
----> 1 M * v
~/anaconda3/lib/python3.6/site-packages/numpy/matrixlib/defmatrix.py in __mul__(self, o
307 if isinstance(other, (N.ndarray, list, tuple)) :
308 # This promotes 1-D vectors to row vectors
--> 309 return N.dot(self, asmatrix(other))
310 if isscalar(other) or not hasattr(other, '__rmul__') :
311 return N.dot(self, other)
Vea tambin las funciones relacionadas: inner, outer, cross, kron, tensordot. Por ejemplo,
introduzca help(kron).
15
0.8.4 Transformaciones de arreglos/matrices
Antes hemos usado .T para transponer un vector v. Podemos tambin usar la funcin transpose
para conseguir el mismo resultado.
Otras funciones matemticas que transforman objetos matriciales son:
In [375]: np.conjugate(C)
In [376]: C.H
Podemos extraer las partes reales e imaginarias de un arreglo con elementos complejos usando
real y imag:
In [380]: abs(C)
16
0.8.5 Clculos con matrices
Inversa
In [381]: np.linalg.inv(C) # equivalente a C.I
In [382]: C.I * C
Determinante
In [383]: np.linalg.det(C)
Out[383]: (2.0000000000000004+0j)
In [384]: np.linalg.det(C.I)
Out[384]: (0.49999999999999972+0j)
Out[385]: (77431, 7)
media
In [386]: # la temperatura est almacenada en la columna 3
np.mean(data[:,3])
#data[:,3].mean()
Out[386]: 6.1971096847515854
La temperatura diaria promedio en Estocolmo en los ltimos 200 aos ha sido aproximada-
mente 6.2 C.
17
min and max
In [388]: # valor mnimo del promedio diario de temperatura. Lo mismo que min(data[:,3])
data[:,3].min()
Out[388]: -25.800000000000001
In [389]: # valor mximo del promedio diario de temperatura. Lo mismo que max(data[:,3])
data[:,3].max()
Out[389]: 28.300000000000001
Out[391]: 55
Out[392]: 3628800
Out[395]: 110
18
0.8.7 Clculos con subconjuntos de un arreglo
Podemos calcular usando subconjuntos de los datos de un arreglo usando el indexado, indexado
fancy, y los otros mtodos para extraer datos desde un arreglo (descrito ms arriba).
Por ejemplo, consideremos nuevamente los datos de temperatura de Estocolmo:
El formato de los datos es: ao, mes, da, temperatura promedio diaria, mnima, mxima,
lugar.
Si estamos interesados slo en la temperatura promedio de un mes particular, Febrero por
ejemplo, podemos crear una mscara de ndice y seleccionar slo los datos de ese mes usando:
Out[397]: array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.,
12.])
Out[399]: -3.2121095707365961
Estas funciones ponen a nuestra disposicin herramientas muy poderosas para procesar datos.
Por ejemplo, para extraer las temperaturas promedio mensuales para cada mes del ao slo nece-
sitamos unas pocas lneas de cdigo:
fig, ax = plt.subplots()
ax.bar(meses, media_mensual)
ax.set_xlabel("Mes")
ax.set_ylabel("Temperatura promedio mensual");
19
0.8.8 Clculos con datos multidimensionales
Cuando se aplican funciones como min, max, etc., a arreglos multidimensionales, a veces se desea
aplicarlas al arreglo completo, y en otras ocasiones slo por filas o columnas. Podemos especificar
cmo se comportan estas funciones usando el argumento axis (eje):
In [401]: m = random.rand(3,3)
m
Out[401]: array([[ 0.75964058, 0.52813348, 0.55087764],
[ 0.55293618, 0.75439197, 0.7252032 ],
[ 0.40130512, 0.12776119, 0.44002286]])
In [402]: # mximo global
m.max()
Out[402]: 0.75964057545662989
In [403]: # mximo en cada columna
m.max(axis=0)
Out[403]: array([ 0.75964058, 0.75439197, 0.7252032 ])
In [404]: # mximo en cada fila
m.max(axis=1)
Out[404]: array([ 0.75964058, 0.75439197, 0.44002286])
Muchas otras funciones y mtodos de las clases array y matrix aceptan el argumento (op-
tional) axis.
20
0.9 Cambiando la forma, redimensionando y apilando arreglos
La forma de un arreglo Numpy puede ser modificada sin copiar las datos involucrados, lo que
hace que esta operacin sea rpida, incluyo con arreglos grandes.
In [405]: A
In [406]: n, m = A.shape
In [407]: B = A.reshape((1,n*m))
B
Out[407]: array([[ 0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31,
32, 33, 34, 40, 41, 42, 43, 44]])
Out[408]: array([[ 5, 5, 5, 5, 5, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31,
32, 33, 34, 40, 41, 42, 43, 44]])
In [409]: A # la variable original es tambin cambiada. B slo constituye una forma distinta de
In [410]: B = A.flatten()
Out[410]: array([ 5, 5, 5, 5, 5, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31,
32, 33, 34, 40, 41, 42, 43, 44])
In [411]: B[0:5] = 10
21
Out[411]: array([10, 10, 10, 10, 10, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31,
32, 33, 34, 40, 41, 42, 43, 44])
In [412]: A # ahora A no ha cambiado, ya que los datos de B han sido duplicados desde A
In [413]: v = np.array([1,2,3])
v
In [414]: np.shape(v)
Out[414]: (3,)
Out[415]: array([[1],
[2],
[3]])
Out[416]: (3, 1)
In [418]: v[np.newaxis,:].shape
Out[418]: (1, 3)
22
tile y repeat
concatenate
In [425]: np.vstack((a,b))
In [426]: np.hstack((a,b.T))
23
0.10 Copy y "deep copy"
Para alcarzar un alto desemo, las asignaciones en Python usualmente no copian los objetos
involucrados. Esto es importante cuando se pasan objetos a funciones, para as evitar uso excesivo
de memoria copiando cuando no es necesario (trmino tcnico: paso por referencia)
In [430]: A
Si queremos evitar este comportamiento, para as obtener un nuevo objecto B copiado desde
A, pero totalmente independiente de A, necesitamos realizar una "copia produnfa" ("deep copy")
usando la funcin copy:
In [431]: B = np.copy(A)
In [433]: A
24
0.11 Iterando sobre elementos de un arreglo
Generalmente, deseamos evitar iterar sobre los elementos de un arreglo donde sea posible (a
cualquier precio!). La razn es que en un lenguaje interpretado como Python (o MATLAB), las
iteraciones son realmente lentas comparadas con las operaciones vectorizadas.
Sin embargo, algunas veces es ineludible. En tales cases el bucle Python for es la forma ms
conveniente para iterar sobre un arreglo:
In [434]: v = np.array([1,2,3,4])
for elemento in v:
print(elemento)
1
2
3
4
for fila in M:
print("fila", fila)
fila [1 2]
1
2
fila [3 4]
3
4
Cuando necesitamos iterar sobre cada elemento de un arreglo y modificar sus elementos, es
conveniendo usar la funcin enumerate para obtener tanto el elemento como su ndice en el bucle
for:
ind_fila 0 fila [1 2]
ind_colu 0 elemento 1
25
ind_colu 1 elemento 2
ind_fila 1 fila [3 4]
ind_colu 0 elemento 3
ind_colu 1 elemento 4
In [439]: Theta(np.array([-3,-2,-1,0,1,2,3]))
---------------------------------------------------------------------------
<ipython-input-439-d55419725688> in <module>()
----> 1 Theta(np.array([-3,-2,-1,0,1,2,3]))
<ipython-input-438-d6359217b50a> in Theta(x)
3 implementacin escalar de la funcin escaln de Heaviside.
4 """
----> 5 if x >= 0:
6 return 1
7 else:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.
26
Ok, eso no funcion porque no definimos la funcin Theta de modo que pueda manejar argu-
mentos vectoriales...
Para obtener una version vectorizada de Theta podemos usar la funcin vectorize de Numpy.
En muchos casos, puede vectorizar automticamente una funcin:
In [440]: Theta_vec = np.vectorize(Theta)
In [441]: Theta_vec(np.array([-3,-2,-1,0,1,2,3]))
Out[441]: array([0, 0, 0, 1, 1, 1, 1])
Podemos tambin implementar la funcin de modo que desde el comienzo acepte un argu-
mento vectorial (esto requiere ms esfuerzo, pero mejorar el rendimiento):
In [442]: def Theta(x):
"""
Implementacin preparada para vectores de la funcin escaln de Heaviside.
"""
return 1 * (x >= 0)
In [443]: Theta(np.array([-3,-2,-1,0,1,2,3]))
Out[443]: array([0, 0, 0, 1, 1, 1, 1])
In [444]: # y tambin funciona para escalares!
Theta(-1.2), Theta(2.6)
Out[444]: (0, 1)
27
0.14 Conversin de tipo
Como los arreglos de Numpy son de tipo esttico, el tipo de un arrglo no puede ser cambiado luego
de que es creado. Sin embarg, podemos convertir explcitamente un arreglo de un tipo a otro
usando las funciones astype (ver tambin las funciones similares asarray). Esto crea un nuevo
arreglo de un nuevo tipo:
In [448]: M.dtype
Out[448]: dtype('int64')
In [449]: M2 = M.astype(float)
M2
In [450]: M2.dtype
Out[450]: dtype('float64')
In [451]: M3 = M.astype(bool)
M3
28