Вы находитесь на странице: 1из 28

2-Numpy

October 27, 2017

Curso de Python para Ingenieros Mecnicos


Por: Eduardo Vieira
Numpy - arreglos de datos multidimensionales

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:

In [276]: import numpy as np

En el paquete numpy la terminologa usada para vectores, matrices y conjuntos de datos de


dimensin mayor es la de un arreglo.

0.2 Creando arreglos de numpy


Existen varias formas para inicializar nuevos arreglos de numpy, por ejemplo desde

Listas o tuplas Python


Usando funciones dedicadas a generar arreglos numpy, como arange, linspace, etc.
Leyendo datos desde archivos

0.2.1 Desde lista


Por ejemplo, para crear nuevos arreglos de matrices y vectores desde listas Python podemos usar
la funcin numpy.array.

In [277]: # un vector: el argumento de la funcin array es una lista de Python


v = np.array([1,2,3,4])

Out[277]: array([1, 2, 3, 4])

1
In [278]: # una matriz: el argumento de la funcin array es una lista anidada de Python
M = np.array([[1, 2], [3, 4]])

Out[278]: array([[1, 2],


[3, 4]])

Los objetos v y M son ambos del tipo ndarray que provee el mdulo numpy.

In [279]: type(v), type(M)

Out[279]: (numpy.ndarray, numpy.ndarray)

La diferencia entre los arreglos v y M es slo su forma. Podemos obtener informacin de la


forma de un arreglo usando la propiedad ndarray.shape

In [280]: v.shape

Out[280]: (4,)

In [281]: M.shape

Out[281]: (2, 2)

El nmero de elementos de un arreglo puede obtenerse usando la propiedad ndarray.size:

In [282]: M.size

Out[282]: 4

Equivalentemente, podemos usar las funciones numpy.shape y numpy.size

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')

Se obtiene un error si intentamos asignar un valor de un tipo equivocado a un elemento de un


arreglo numpy:

In [286]: M[0,0] = "hola"

---------------------------------------------------------------------------

ValueError Traceback (most recent call last)

<ipython-input-286-fc4abc9a80ec> in <module>()
----> 1 M[0,0] = "hola"

ValueError: invalid literal for int() with base 10: 'hola'

Si lo deseamos, podemos definir explcitamente el tipo de datos de un arreglo cuando lo


creamos, usando el argumento dtype:

In [287]: M = np.array([[1, 2], [3, 4]], dtype=complex)

Out[287]: array([[ 1.+0.j, 2.+0.j],


[ 3.+0.j, 4.+0.j]])

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

In [288]: # crea un arreglo con valores en un rango

x = np.arange(0, 10, 1) # argumentos: desde, hasta, paso

Out[288]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [289]: x = np.arange(-1, 1, 0.1)

Out[289]: array([ -1.00000000e+00, -9.00000000e-01, -8.00000000e-01,


-7.00000000e-01, -6.00000000e-01, -5.00000000e-01,
-4.00000000e-01, -3.00000000e-01, -2.00000000e-01,
-1.00000000e-01, -2.22044605e-16, 1.00000000e-01,
2.00000000e-01, 3.00000000e-01, 4.00000000e-01,
5.00000000e-01, 6.00000000e-01, 7.00000000e-01,
8.00000000e-01, 9.00000000e-01])

linspace y logspace

In [290]: # usando linspace, ambos puntos finales SON incluidos. Formato: (desde, hasta, nmero
np.linspace(0, 10, 25)

Out[290]: array([ 0. , 0.41666667, 0.83333333, 1.25 ,


1.66666667, 2.08333333, 2.5 , 2.91666667,
3.33333333, 3.75 , 4.16666667, 4.58333333,
5. , 5.41666667, 5.83333333, 6.25 ,
6.66666667, 7.08333333, 7.5 , 7.91666667,
8.33333333, 8.75 , 9.16666667, 9.58333333, 10. ])

In [291]: # logspace tambin incluye el punto final. Por defecto base=10


np.logspace(0, 10, 11, base=np.e) # produce e elevado a cada valor en linspace(0, 10,

Out[291]: array([ 1.00000000e+00, 2.71828183e+00, 7.38905610e+00,


2.00855369e+01, 5.45981500e+01, 1.48413159e+02,
4.03428793e+02, 1.09663316e+03, 2.98095799e+03,
8.10308393e+03, 2.20264658e+04])

mgrid

In [292]: x, y = np.mgrid[0:5, 0:5] # similar a meshgrid en MATLAB

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

Out[294]: array([[0, 1, 2, 3, 4],


[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]])

Datos aleatorios

In [295]: from numpy import random

In [296]: # nmeros aleatorios uniformes en [0,1]


random.rand(2,5)

Out[296]: array([[ 0.74208045, 0.97663397, 0.98082991, 0.35896545, 0.02454537],


[ 0.96586593, 0.32859173, 0.5399538 , 0.83979162, 0.83768707]])

In [297]: # nmeros aleatorios con distribucin estndar normal (distribucin gaussiana de medi
random.randn(2,5)

Out[297]: array([[-0.04658636, 1.26353421, -0.24494335, 0.66768628, 1.01476726],


[-0.02779681, 0.45573482, -2.22038057, 0.00995936, 1.32385413]])

diag

In [298]: # una matriz diagonal


np.diag([1,2,3])

Out[298]: array([[1, 0, 0],


[0, 2, 0],
[0, 0, 3]])

In [300]: # diagonal desplazada desde la diagonal principal


np.diag([1,2,3], k=1)

Out[300]: array([[0, 1, 0, 0],


[0, 0, 2, 0],
[0, 0, 0, 3],
[0, 0, 0, 0]])

5
ceros y unos

In [301]: np.zeros((3,3))

Out[301]: array([[ 0., 0., 0.],


[ 0., 0., 0.],
[ 0., 0., 0.]])

In [302]: np.ones((3,3))

Out[302]: array([[ 1., 1., 1.],


[ 1., 1., 1.],
[ 1., 1., 1.]])

0.3 Entrada/Salida desde/hasta archivos


0.3.1 Valores separados por coma (Comma-separated values, CSV)
Un formato muy comn para archivos de datos es el de valores separados por comas, o formatos
relacionados, como por ejemplo TSV (tab-separated values, valores separados por tabs). Para leer
datos desde tales archivos a un arreglo Numpy podemos usar la funcin numpy.genfromtxt. Por
ejemplo,

In [303]: data = np.genfromtxt('stockholm_td_adj.dat') # asigna los datos del archivo al arreg

In [304]: data.shape

Out[304]: (77431, 7)

In [305]: # qu hace esta lnea?. La respuesta mas adelante


%matplotlib inline
import matplotlib.pyplot as plt

In [306]: fig, ax = plt.subplots(figsize=(14,4))


ax.plot(data[:,0]+data[:,1]/12.0+data[:,2]/365, data[:,5])
ax.axis('tight')
ax.set_title('temperaturas en Estocolmo')
ax.set_xlabel(u'ao')
ax.set_ylabel(u'temperatura (C)');

6
Usando numpy.savetxt podemos almacenar un arreglo Numpy a un archivo en formato CSV:

In [307]: M = random.rand(3,3)

Out[307]: array([[ 0.57607811, 0.57379336, 0.94826872],


[ 0.2655032 , 0.28584834, 0.40613708],
[ 0.92467302, 0.57783605, 0.21239031]])

In [308]: np.savetxt("matriz-aleatoria.csv", M)

In [309]: np.savetxt("matriz-aleatoria.csv", M, fmt='%.5f') # fmt especifica el formato

0.4 Ms propiedades de los arreglos Numpy


In [310]: M.itemsize # los bits de cada elemento

Out[310]: 8

In [311]: M.nbytes # nmero de bytes

Out[311]: 72

In [312]: M.ndim # nmero de dimensiones

Out[312]: 2

0.5 Manipulando arreglos


0.5.1 Indexando
Podemos indexar elementos en un arreglo usando parntesis cuadrados e ndices:

In [313]: # v es un vector, tiene por lo tanto slo una dimensin, y requiere un ndice
v[0]

Out[313]: 1

In [314]: # M es una matriz, es decir un arreglo bidimensional, requiere dos ndices


M[1,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]

Out[316]: array([ 0.2655032 , 0.28584834, 0.40613708])

Puede obtenerse lo mismo usando : en el lugar de un ndice:

In [317]: M[1,:] # fila 1

Out[317]: array([ 0.2655032 , 0.28584834, 0.40613708])

In [318]: M[:,1] # columna 1

Out[318]: array([ 0.57379336, 0.28584834, 0.57783605])

Podemos asignar nuevos valores a los elementos de un arreglo usando el indexado:

In [319]: M[0,0] = 1

In [320]: M

Out[320]: array([[ 1. , 0.57379336, 0.94826872],


[ 0.2655032 , 0.28584834, 0.40613708],
[ 0.92467302, 0.57783605, 0.21239031]])

In [321]: # tambin funciona para filas y columnas completas


M[1,:] = 0
M[:,2] = -1

In [322]: M

Out[322]: array([[ 1. , 0.57379336, -1. ],


[ 0. , 0. , -1. ],
[ 0.92467302, 0.57783605, -1. ]])

0.6 Corte de ndices


Corte (slicing) de ndices es el nombre para la sintaxis M[desde:hasta:paso] para extraer una
parte de un arreglo:

In [323]: A = np.array([1,2,3,4,5])
A

Out[323]: array([1, 2, 3, 4, 5])

In [324]: A[1:3]

Out[324]: array([2, 3])

8
Los cortes de ndices son mutables: si se les asigna un nuevo valor el arreglo original es modi-
ficado:

In [325]: A[1:3] = [-2,-3]

Out[325]: array([ 1, -2, -3, 4, 5])

Podemos omitir cualquiera de los tres parmetros en M[desde:hasta:paso]:

In [326]: A[::] # desde, hasta y paso asumen los valores por defecto

Out[326]: array([ 1, -2, -3, 4, 5])

In [327]: A[::2] # el paso es 2, desde y hasta se asumen desde el comienzo hasta el fin del arr

Out[327]: array([ 1, -3, 5])

In [328]: A[:3] # primeros tres elementos

Out[328]: array([ 1, -2, -3])

In [329]: A[3:] # elementos desde el ndice 3

Out[329]: array([4, 5])

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

In [331]: A[-1] # el ltimo elemento del arreglo

Out[331]: 5

In [332]: A[-3:] # los ltimos 3 elementos

Out[332]: array([3, 4, 5])

El corte de ndices funciona exactamente del mismo modo para arreglos multidimensionales:

In [333]: A = np.array([[n+m*10 for n in range(5)] for m in range(5)])

Out[333]: 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]])

9
In [334]: # un bloque parte del arreglo original
A[1:4, 1:4]

Out[334]: array([[11, 12, 13],


[21, 22, 23],
[31, 32, 33]])

In [335]: # elemento por medio


A[::2, ::2]

Out[335]: array([[ 0, 2, 4],


[20, 22, 24],
[40, 42, 44]])

0.6.1 Indexado Fancy


Se llama indexado fancy cuando una arreglo o una lista es usado en lugar de un ndice:

In [336]: indices_fila = [1, 2, 3]


A[indices_fila]

Out[336]: array([[10, 11, 12, 13, 14],


[20, 21, 22, 23, 24],
[30, 31, 32, 33, 34]])

In [337]: indices_col = [1, 2, -1] # recuerde que el ndice -1 corresponde al ltimo elemento
A[indices_fila, indices_col]

Out[337]: array([11, 22, 34])

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 [338]: B = np.array([n for n in range(5)])


B

Out[338]: array([0, 1, 2, 3, 4])

In [339]: masc_fila = np.array([True, False, True, False, False])


B[masc_fila]

Out[339]: array([0, 2])

In [340]: # lo mismo
masc_fila = np.array([1,0,1,0,0], dtype=bool)
B[masc_fila]

Out[340]: array([0, 2])

10
Esta caracterstica es muy til para seleccionar en forma condicional elementos de un arreglo,
usando por ejemplo los operadores de comparacin:

In [341]: x = np.arange(0, 10, 0.5)


x

Out[341]: array([ 0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. ,


5.5, 6. , 6.5, 7. , 7.5, 8. , 8.5, 9. , 9.5])

In [342]: masc = (5 < x) * (x < 7.5)

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]

Out[343]: array([ 5.5, 6. , 6.5, 7. ])

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):

In [344]: indices = np.where(masc)

indices

Out[344]: (array([11, 12, 13, 14]),)

In [345]: x[indices] # este indexado es equivalente al indexado fancy x[masc]

Out[345]: array([ 5.5, 6. , 6.5, 7. ])

diag Con la funcin diag podemos extraer la diagonal y las subdiagonales de un arreglo:

In [346]: np.diag(A)

Out[346]: array([ 0, 11, 22, 33, 44])

In [347]: np.diag(A, -1)

Out[347]: array([10, 21, 32, 43])

11
take La funcin take es similar al indexado fancy descrito anteriormente:

In [348]: v2 = np.arange(-3,3)
v2

Out[348]: array([-3, -2, -1, 0, 1, 2])

In [349]: indices_fila = [1, 3, 5]


v2[indices_fila] # indexado fancy

Out[349]: array([-2, 0, 2])

In [350]: v2.take(indices_fila)

Out[350]: array([-2, 0, 2])

Pero la funcin take tambin funciona sobre listas y otros objetos:

In [351]: np.take([-3, -2, -1, 0, 1, 2], indices_fila)

Out[351]: array([-2, 0, 2])

choose Construye un arreglo tomando elementos desde varios arreglos:

In [352]: cuales = [1, 0, 1, 0]


posibilidades = [[-2,-2,-2,-2], [5,5,5,5]]

np.choose(cuales, posibilidades)

Out[352]: array([ 5, -2, 5, -2])

0.8 lgebra lineal


El vectorizar el cdigo es la clave para realizar clculos numricos eficientes usando
Python/Numpy. Esto significa que la mayor parte de un programa debera ser formulado en
trminos de operaciones con matrices y vectores, como por ejemplo la multiplicacin de matrices.

0.8.1 Operaciones escalar-arreglo


Podemos usar los operadores aritmticos usuales para multiplicar, sumar, restar, y dividir arreglos
por nmeros (escalares):

In [353]: v1 = np.arange(0, 5)

In [354]: 2*v1

Out[354]: array([0, 2, 4, 6, 8])

In [355]: v1 + 2

Out[355]: array([2, 3, 4, 5, 6])

12
In [356]: A * 2, A + 2

Out[356]: (array([[ 0, 2, 4, 6, 8],


[20, 22, 24, 26, 28],
[40, 42, 44, 46, 48],
[60, 62, 64, 66, 68],
[80, 82, 84, 86, 88]]), array([[ 2, 3, 4, 5, 6],
[12, 13, 14, 15, 16],
[22, 23, 24, 25, 26],
[32, 33, 34, 35, 36],
[42, 43, 44, 45, 46]]))

0.8.2 Operaciones elemento a elemento entre arreglos


Cuando sumamos, sustraemos, multiplicados y dividimos dos arreglos, el comportamiento por
defecto es operar elemento a elemento:

In [357]: A * A # multiplicacin elemento a elemento

Out[357]: array([[ 0, 1, 4, 9, 16],


[ 100, 121, 144, 169, 196],
[ 400, 441, 484, 529, 576],
[ 900, 961, 1024, 1089, 1156],
[1600, 1681, 1764, 1849, 1936]])

In [358]: v1 * v1

Out[358]: array([ 0, 1, 4, 9, 16])

Si multiplicamos arreglos con formas compatibles, obtenemos una multiplicacin elemento a


elemento de cada fila:

In [359]: A.shape, v1.shape

Out[359]: ((5, 5), (5,))

In [360]: A * v1

Out[360]: array([[ 0, 1, 4, 9, 16],


[ 0, 11, 24, 39, 56],
[ 0, 21, 44, 69, 96],
[ 0, 31, 64, 99, 136],
[ 0, 41, 84, 129, 176]])

0.8.3 lgebra matricial


Y la multiplicacin de matrices? Podemos realizarla de dos formas. Podemos usar la funcin dot,
que aplica una multiplicacin matriz-matriz, matriz-vector o un producto interno entre vectores a
sus dos argumentos:

13
In [361]: np.dot(A, A)

Out[361]: array([[ 300, 310, 320, 330, 340],


[1300, 1360, 1420, 1480, 1540],
[2300, 2410, 2520, 2630, 2740],
[3300, 3460, 3620, 3780, 3940],
[4300, 4510, 4720, 4930, 5140]])

Desde Python 3.5 se pueden multiplicar matrices usando el operador @

In [362]: A @ A

Out[362]: array([[ 300, 310, 320, 330, 340],


[1300, 1360, 1420, 1480, 1540],
[2300, 2410, 2520, 2630, 2740],
[3300, 3460, 3620, 3780, 3940],
[4300, 4510, 4720, 4930, 5140]])

In [363]: A @ v1

Out[363]: array([ 30, 130, 230, 330, 430])

In [364]: v1 @ v1

Out[364]: 30

Alternativamente, podemos transformar el arreglo al tipo matrix. Esto cambia el compor-


tamiento de los operadores aritmticos estndar +, -, * al de lgebra de matrices.

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

Out[367]: matrix([[ 300, 310, 320, 330, 340],


[1300, 1360, 1420, 1480, 1540],
[2300, 2410, 2520, 2630, 2740],
[3300, 3460, 3620, 3780, 3940],
[4300, 4510, 4720, 4930, 5140]])

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

---------------------------------------------------------------------------

ValueError Traceback (most recent call last)

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

ValueError: shapes (5,5) and (6,1) not aligned: 5 (dim 1) != 6 (dim 0)

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 [374]: C = np.matrix([[1j, 2j], [3j, 4j]])


C

Out[374]: matrix([[ 0.+1.j, 0.+2.j],


[ 0.+3.j, 0.+4.j]])

In [375]: np.conjugate(C)

Out[375]: matrix([[ 0.-1.j, 0.-2.j],


[ 0.-3.j, 0.-4.j]])

Hermtico conjugado: transpuesta + conjugado

In [376]: C.H

Out[376]: matrix([[ 0.-1.j, 0.-3.j],


[ 0.-2.j, 0.-4.j]])

Podemos extraer las partes reales e imaginarias de un arreglo con elementos complejos usando
real y imag:

In [377]: np.real(C) # lo mismo que: C.real

Out[377]: matrix([[ 0., 0.],


[ 0., 0.]])

In [378]: np.imag(C) # lo mismo que: C.imag

Out[378]: matrix([[ 1., 2.],


[ 3., 4.]])

Podemos tambin extraer el mdulo y el argumento complejo

In [379]: np.angle(C+1) # Atencin usuarios de MATLAB, se usa angle en lugar de arg

Out[379]: array([[ 0.78539816, 1.10714872],


[ 1.24904577, 1.32581766]])

In [380]: abs(C)

Out[380]: matrix([[ 1., 2.],


[ 3., 4.]])

16
0.8.5 Clculos con matrices
Inversa
In [381]: np.linalg.inv(C) # equivalente a C.I

Out[381]: matrix([[ 0.+2.j , 0.-1.j ],


[ 0.-1.5j, 0.+0.5j]])

In [382]: C.I * C

Out[382]: matrix([[ 1.00000000e+00+0.j, 0.00000000e+00+0.j],


[ 2.22044605e-16+0.j, 1.00000000e+00+0.j]])

Determinante
In [383]: np.linalg.det(C)

Out[383]: (2.0000000000000004+0j)

In [384]: np.linalg.det(C.I)

Out[384]: (0.49999999999999972+0j)

0.8.6 Clculos con datos


A menudo es til almacenar datos en arreglos Numpy. Numpy provee funciones para realizar
clculos estadsticos de los datos en un arreglo.
Por ejemplo, calculemos algunas propiedades de los datos de la temperatura de Estocolmo
que discutimos anteriormente.

In [385]: # recuerde, los datos de la temperatura estn almacenados en la variable data


np.shape(data)

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.

Desviacin estndar y varianza


In [387]: np.std(data[:,3]), np.var(data[:,3])

Out[387]: (8.2822716213405734, 68.596023209663414)

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

sum, prod, and trace

In [390]: d = 1 + np.arange(0, 10)


d

Out[390]: array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

In [391]: # suma todos los elementos


np.sum(d)

Out[391]: 55

In [392]: # multiplica todos los elementos


np.prod(d)

Out[392]: 3628800

In [393]: # suma acumulativa


np.cumsum(d)

Out[393]: array([ 1, 3, 6, 10, 15, 21, 28, 36, 45, 55])

In [394]: # producto acumulativo


np.cumprod(d)

Out[394]: array([ 1, 2, 6, 24, 120, 720, 5040,


40320, 362880, 3628800])

In [395]: # lo mismo que: diag(A).sum()


np.trace(A)

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:

In [396]: !head -n 3 stockholm_td_adj.dat

1800 1 1 -6.1 -6.1 -6.1 1


1800 1 2 -15.4 -15.4 -15.4 1
1800 1 3 -15.0 -15.0 -15.0 1

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:

In [397]: np.unique(data[:,1]) # la columna mes asume valores entre 1 y 12

Out[397]: array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.,
12.])

In [398]: masc_feb = (data[:,1] == 2) # los parntesis () son opcionales


masc_feb

Out[398]: array([False, False, False, ..., False, False, False], dtype=bool)

In [399]: # los datos de temperatura estn en la columna 3


np.mean(data[masc_feb,3])

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:

In [400]: meses = np.arange(1,13)


media_mensual = [np.mean(data[data[:,1] == mes, 3]) for mes in meses]

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

Out[405]: 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]])

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

In [408]: B[0,0:5] = 5 # modifica el arreglo

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

Out[409]: 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]])

Podemos tambin usar la funcin flatten para transformar un arreglo multidimensional a un


vector. A diferencia de reshape esta funcin crea una copia de los datos.

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

Out[412]: 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]])

0.9.1 Agregando una dimensin adicional: newaxis


Con newaxis, podemos insertar una nueva dimension en un arreglo, por ejemplo, para convertir
un vector en la fila o columna de una matriz:

In [413]: v = np.array([1,2,3])
v

Out[413]: array([1, 2, 3])

In [414]: np.shape(v)

Out[414]: (3,)

In [415]: # crea una matriz con el vector v como su columna


v[:, np.newaxis]

Out[415]: array([[1],
[2],
[3]])

In [416]: # matriz columna


v[:,np.newaxis].shape

Out[416]: (3, 1)

In [417]: # matriz fila


v[np.newaxis,:]

Out[417]: array([[1, 2, 3]])

In [418]: v[np.newaxis,:].shape

Out[418]: (1, 3)

0.9.2 Apilando y repitiendo arreglos


Podemos crear vectores y matrices ms grandes a partir de otras ms pequeas usando las fun-
cionesn repeat (repetir), tile (teselar, "embaldosar"), vstack (apilar verticalmente), hstack (api-
lar horizontalmente), y concatenate (concatenar):

22
tile y repeat

In [419]: a = np.array([[1, 2], [3, 4]])


a

Out[419]: array([[1, 2],


[3, 4]])

In [420]: # repite cada elemente 3 veces


np.repeat(a, 3)

Out[420]: array([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4])

In [421]: # repite la matriz 3 veces


np.tile(a, 3)

Out[421]: array([[1, 2, 1, 2, 1, 2],


[3, 4, 3, 4, 3, 4]])

concatenate

In [422]: b = np.array([[5, 6]])

In [423]: np.concatenate((a, b), axis=0)

Out[423]: array([[1, 2],


[3, 4],
[5, 6]])

In [424]: np.concatenate((a, b.T), axis=1)

Out[424]: array([[1, 2, 5],


[3, 4, 6]])

hstack and vstack

In [425]: np.vstack((a,b))

Out[425]: array([[1, 2],


[3, 4],
[5, 6]])

In [426]: np.hstack((a,b.T))

Out[426]: array([[1, 2, 5],


[3, 4, 6]])

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 [427]: A = np.array([[1, 2], [3, 4]])

Out[427]: array([[1, 2],


[3, 4]])

In [428]: # ahora B apunta al mismo arreglo que A


B = A

In [429]: # cambiar B afecta a A


B[0,0] = 10

Out[429]: array([[10, 2],


[ 3, 4]])

In [430]: A

Out[430]: array([[10, 2],


[ 3, 4]])

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 [432]: # ahora A no cambia si modificamos B


B[0,0] = -5

Out[432]: array([[-5, 2],


[ 3, 4]])

In [433]: A

Out[433]: array([[10, 2],


[ 3, 4]])

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

In [435]: M = np.array([[1,2], [3,4]])

for fila in M:
print("fila", fila)

for elemento in fila:


print(elemento)

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:

In [436]: for ind_fila, fila in enumerate(M):


print("ind_fila", ind_fila, "fila", fila)

for ind_colu, elemento in enumerate(fila):


print("ind_colu", ind_colu, "elemento", elemento)

# actualiza la matriz: eleva al cuadrado cada elemento


M[ind_fila, ind_colu] = elemento**2

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 [437]: # cada elemento en M est ahora al cuadrado


M

Out[437]: array([[ 1, 4],


[ 9, 16]])

0.12 Vectorizando funciones


Como se ha mencionado en varias ocasiones, para obtener un buen rendimiento deberamos tratar
de evitar realizar bucles sobre los elementos de nuestros vectores y matrices, y en su lugar usar
algoritmos vectorizados. El primer paso para convertir un algoritmo escalar a uno vectorizado es
asegurarnos que las funciones que escribamos funcionen con argumentos vectoriales.

In [438]: def Theta(x):


"""
implementacin escalar de la funcin escaln de Heaviside.
"""
if x >= 0:
return 1
else:
return 0

In [439]: Theta(np.array([-3,-2,-1,0,1,2,3]))

---------------------------------------------------------------------------

ValueError Traceback (most recent call last)

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

0.13 Usando arreglos en sentencias condicionales


Cuando se usan arreglos en sentencias condicionales, por ejemplo en sentencias if y otras expre-
siones booleanas, necesitamos usar any o bien all, que requiere que todos los elementos de un
arreglo se evalen con True:
In [445]: M
Out[445]: array([[ 1, 4],
[ 9, 16]])
In [446]: if (M > 5).any():
print("al menos un elemento de M es mayor que 5")
else:
print("ningn elemento de M es mayor que 5")
al menos un elemento de M es mayor que 5

In [447]: if (M > 5).all():


print("todos los elementos de M son mayores que 5")
else:
print("no todos los elementos de M son mayores que 5")
no todos los elementos de M son mayores que 5

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

Out[449]: array([[ 1., 4.],


[ 9., 16.]])

In [450]: M2.dtype

Out[450]: dtype('float64')

In [451]: M3 = M.astype(bool)

M3

Out[451]: array([[ True, True],


[ True, True]], dtype=bool)

0.15 Lectura adicional


Numpy
http://scipy.org/Tentative_NumPy_Tutorial
http://scipy.org/NumPy_for_Matlab_Users - Una gua de Numpy para usuario de MAT-
LAB.

In [452]: # Esta celda da el estilo al notebook


from IPython.core.display import HTML
css_file = './css/aeropython.css'
HTML(open(css_file, "r").read())

Out[452]: <IPython.core.display.HTML object>

28

Вам также может понравиться