En este curso, trabajaremos con Python de tres formas distintas:
spyder: es un entorno interactivo para escribir código Python que facilita la edición y el debugging de una forma sencilla. Lo utilizaremos para escribir el código de los ejercicios.
consola: es la interación básica con Python.
jupyter notebook: es un entorno interactivo en el que se combinan ejecución de código, texto enriquecido, fórmulas matemáticas, gráficos, videos, animaciones, etc. Con él han sido realizados estos guiones de prácticas.
Ejecutar el código (asumiendo que los paths son correctos):
spyder: Puede abrirse o bien desde un lanzador de Spyder en el escritorio o desde el menú de Inicio. En cualquier caso, siempre se puede abrir spyder
desde la línea de comandos tecleando spyder
.
consola: Simplemente abrir la consola y ejecutar python
. Así entraríamos en python en línea de comandos. También se puede usar la consola para ejecutar un programa python tecleando python programa_python.py
.
jupyter notebook: abrir la consola e ir a la carpeta donde hemos guardado el código (o queremos guardar el código) y ejecutar jupyter notebook
. Se abrirá una ventana nueva del navegador por defecto, donde podemos leer los ficheros existentes con sufijo ipynb
o crear ficheros nuevos.
Para estas prácticas usaremos la distribución Anaconda con Python 3.
Python es un lenguaje muy versatil que puede realizar tareas muy distintas. En este curso nos centraremos en algoritmos numéricos que se pueden implementar con Python.
Python es modular. Un módulo es un programa que contiene, entre otras cosas, las definiciones de las variables y las funciones. A menudo, los módulos se agrupan en paquetes para una determinada aplicación. Por ejemplo, utilizaremos mayormente los paquetes:
Un programa típico python empieza importando módulos de los paquetes. Por ejemplo
import numpy as np
Aquí hemos importado todos los módulos de numpy
y nos referiremos a él con el prefijo np
:
print(np.pi)
Hay variaciones de la orden import
. Por ejemplo, si sólo queremos cargar la definición de $\pi$ usaremos
from numpy import pi as PI
print(PI)
El objeto principal de NumPy es el array multidimensional homogéneo. Es una tabla de elementos (habitualmente números), todos del mismo tipo, indexados por una tupla de enteros positivos. En NumPy las dimensiones se llaman ejes. El número de ejes es el rango.
Hay muchas formas de crear un array NumPy. Por ejemplo,
a = np.array([1, 2, 3, 4])
b = np.array([(1.5, 2, 3), (4, 5, 6)])
c = np.zeros((3, 4))
d = np.ones((2, 3))
e = np.arange(1, 10, 2)
f = np.arange(1., 10, 2)
g = np.linspace(1, 9, 5)
print('a\n',a,'\n')
print('b\n',b,'\n')
print('c\n',c,'\n')
print('d\n',d,'\n')
print('e\n',e,'\n')
print('f\n',f,'\n')
print('g\n',g)
Los índices comienzan en cero. El índice -1
da el último elemento del array.
En arange
, los valores se generan en el intervalo [1,10). Es decir, 1 está incluído pero 10 no lo está. El último índice es el paso. Es similar a range
pero mientras este genera una lista, arange
genera un array numpy.
print('a[0] = ', a[0], '\nb[0,0] = ',b[0,0], '\nb[0][0] = ',b[0][0])
print('e[-1] = ',e[-1])
len
: número de elementos de un array de dimensión uno (vector) of número de filas en un array de dimensión dos (matriz).
ndim
: número de dimensiones del array (1 para vector, 2 para matriz).
shape
: número de elementos en cada dimensión (número de filas y columnas para una matriz).
print('len(a) = ', len(a),'\nb.ndim = ', b.ndim, '\nb.shape = ', b.shape)
Los operadores aritméticos se aplican en los arrays elemento a elemento. ¡Las listas Python funcionan de forma diferente!
a = np.array([1, 2, 3, 4])
b = np.array([(1.5, 2, 3, 5)])
a1 = [1, 2, 3, 4]
b1 = [1.5, 2, 3, 5]
print('a+b array numpy')
print(a+b)
print('\na1+b1 lista')
print(a1+b1)
Por otra parte
print('a = \n', a)
print('\n3+a = \n', 3+a)
print('\n3*a = \n', 3*a)
print('\n3/a = \n', 3/a)
print('\na/2 = \n', a/2)
A diferencia de otros lenguajes, el operador *
se aplica elemento a elemento en los arrays NumPy.
A = np.array( [[1, 1], [0, 1]] )
B = np.array( [[2, 3], [1, 4]] )
print('A')
print(A)
print('\nB')
print(B)
print('\nA*B')
print(A*B)
Si queremos multiplicar las matrices utilizamos la función np.dot
C = np.dot(A,B)
print('\nAB')
print(C)
Es parecido al utilizado en Python. Por ejemplo
a = np.arange(10)
print('a\n', a)
print('\na[1]\n', a[1])
print('\na[1:8]\n', a[1:8])
print('\na[1:8:2]\n', a[1:8:2])
print('\na[1:]\n', a[1:])
print('\na[:8]\n', a[:8])
print('\na[::2]\n', a[::2])
print('\na[-1]\n', a[-1])
print('\na[:-1]\n', a[:-1])
print('\na[0]\n', a[0])
print('\na[1:]\n', a[1:])
print('\na[::-1]\n', a[::-1])
print('\na[::-2]\n', a[::-2])
print('\na[7:1:-2]\n', a[7:1:-2])
%run slicing1
b = np.array([0, 1, 5, -1])
print('\na[b]\n',a[b])
Análogamente para arrays multidimensionales:
n = 6
s = n*n
a = np.arange(s)
a = np.reshape(a,(n,n))
print('a = \n', a)
print('\033[91m \na[1,3] = \n', a[1,3])
print('\033[92m \na[:,5] = \n', a[:,5])
print('\033[94m \na[4,:] = \n', a[4,:])
print('\033[95m \na[1:3, 0:2] = \n', a[1:3, 0:2])
%run slicing2
print('\033[91m \na[0,1:5] = \n', a[0,1:5])
print('\033[92m \na[4:,4:] = \n', a[4:,4:])
print('\033[94m \na[2::2,::2] = \n', a[2::2,::2])
%run slicing3
Cuando operamos y manipulamos arrays, algunas veces, sus datos se copian en un nuevo array, mientras que otras no. Esto crea confusión en los principiantes. Veamos tres ejemplos:
Sin copia: Una asignación sencilla no crea copia de los arrays o sus datos.
a = np.arange(12)
b = a
print('a[0] = ', a[0], '\nb[0] = ',b[0])
b[0] = 10
print('a[0] = ', a[0], '\nb[0] = ',b[0])
Con copia: el método copy
realiza una copia completa del array y de sus datos.
b = a.copy()
print('a[0] = ', a[0], '\nb[0] = ',b[0])
b[0] = 0
print('a[0] = ', a[0], '\nb[0] = ',b[0])
NumPy contiene las funciones matemáticas elementales con sus nombres habituales. Por ejemplo
print(np.sin(PI/2))
print(np.exp(-1))
print(np.arctan(np.inf))
print(np.sqrt(4))
Si se aplican a un array numpy, el resultado es un array numpy.
a = np.linspace(2,4,5)
print('a =\n', a)
print('\nnp.sqrt(a) =\n', np.sqrt(a))
Podemos definir funciones de dos formas:
f1 = lambda x: x**3
f2 = lambda x,y: x+y
print('f1(2) = ', f1(2))
print('f2(1,1) = ', f2(1,1))
def f3(x):
if x > 2:
return 0
else:
return 1
print('f3(-1) = ', f3(-1))
print('f3(3) = ',f3(3))
Para más información, ver Numpy Quickstart tutorial
Usamos el paquete Matplotlib para hacer plots.
import matplotlib.pyplot as plt
x = np.linspace(-1,2) # malla
f = lambda x : x**3 - 2*x**2 + 1 # función
OX = 0*x # eje OX
plt.figure()
plt.plot(x,f(x)) # dibujar la función
plt.plot(x,OX,'k-') # dibujar el eje X
plt.xlabel('x')
plt.ylabel('y')
plt.title('función')
plt.show()
Creamos una malla para la coordenada $x$ y otra para la coordenada $y$. Es decir, por ejemplo, 20 puntos igualmente espaciados entre $-1$ y $1$ para cada coordenada.
xgrid = np.linspace(-1,1,20)
ygrid = np.linspace(-1,1,20)
Creamos ahora dos matrices que contienen la malla bidimensional
X, Y = np.meshgrid(xgrid,ygrid)
Definimos la función de dos variables
g = lambda x,y: x**2 + y**2
Y representamos la función usando diferentes colores para cada intervalo de valores de la función
plt.figure()
plt.contourf(X,Y,g(X,Y), cmap='jet')
plt.colorbar()
plt.show()
También podemos representarla como una superficie
from mpl_toolkits.mplot3d import Axes3D
fig1 = plt.figure(figsize=(10,5))
ax1 = plt.axes(projection ='3d')
ax1.plot_surface(X, Y, g(X,Y), cmap='jet')
plt.show()
O como una malla
fig2 = plt.figure(figsize=(10,5))
ax2 = plt.axes(projection ='3d')
ax2.plot_wireframe(X, Y, g(X,Y))
plt.show()
Crea e imprime los siguientes vectores y matrices numpy:
$$a = (1, \;3, \;7)\qquad b = \left( \begin{array}{rrr} 2&4&3 \\ 0&1&6 \\ \end{array} \right)\qquad c = (1, \;1, \;1) \qquad d = (0, \;0, \;0, \;0) $$$$e= \left(\begin{array}{rr} 0&0 \\ 0&0 \\ 0&0 \end{array} \right) \qquad f= \left( \begin{array}{rrrr} 1&1&1&1 \\ 1&1&1&1 \\ 1&1&1&1 \\ \end{array}\right)$$
%run Ejercicio1
Utilizando primero la orden arange
y luego linspace
crea los vectores:
Usar
np.set_printoptions(precision=2,suppress=True)
para que el formato no sea exponencial y use dos dígitos.
%run Ejercicio2
arange
, crea el vector%run Ejercicio3
A partir de un vector $a=(1,2,3)$ crear un vector $b=(0,1,2,3,0)$
%run Ejercicio4
Se considera la matriz
$$ A= \left( \begin{array}{rrrr} 2&1&3&4 \\ 9&8&5&7 \\ 6&-1&-2&-8 \\ -5&-7&-9&-6 \\ \end{array}\right) $$Obtén a partir de $A$ las submatrices:
$$a=\left( \begin{array}{r} 2 \\ 9 \\ 6 \\ -5 \end{array}\right) \qquad b=\left( \begin{array}{rrrr} 6&-1&-2&-8 \end{array}\right) \qquad c=\left( \begin{array}{rr} 2&1\\ 9&8 \\ \end{array}\right) $$$$ d=\left( \begin{array}{rr} -2&-8\\ -9&-6 \\ \end{array}\right) \qquad e=\left( \begin{array}{rr} 8&5\\ -1&-2 \\ \end{array}\right) \qquad f=\left( \begin{array}{rrr} 1&3&4 \\ 8&5&7 \\ -1&-2&-8 \\ -7&-9&-6 \\ \end{array}\right) \qquad g=\left( \begin{array}{rr} 8&5 \\ -1&-2 \\ -7&-9 \\ \end{array}\right)$$%run Ejercicio5
%run Ejercicio6
%run Ejercicio7