Esta práctica es una introducción para recordar algunas nociones de Python
que nos serán útiles este curso.
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. Lo usaremos en unos pocos ejercicios donde no es posible hacerlo con Spyder
.
Ipython notebook: es un entorno interactivo en el que se combinan ejecución de código, texto enriquecido, fórmulas matemáticas, gráficos y "rich media". Con él han sido realizadas las prácticas de laboratorio.
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
.
Ipython notebook: abrir la consola e ir a la carpeta donde hemos guardado el código (o queremos guardar el código) y ejecutar ipython notebook
. Se abrirá una ventana nueva del navegador por defecto, donde podemos leer los ficheros existentes con sufijo ipynb
o crear ficheros nuevos.
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 NumPy (numerical python) y Matplotlib (python plotting).
La organización en módulos permite espacios de variables locales. No hay relación entre los nombres en los diferentes espacios de variables. Por ejemplo, si los usuarios tienen la precaución de usar como prefijo de la función el del módulo correspondiente, se podrÃa definir la función maximiza
con dos módulos diferentes sin que se confundieran.
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
La sintaxis de Python tiene algunas reglas y convenciones que intentan mejorar la legibilidad del código y la consistencia a lo largo de un amplio espectro de código Python. Por ejemplo:
Spyder
, esto lo realiza el editor.for i in range(0,3):
print 'i = ', i
for j in ['a','b']:
print 'j = ', j
Longitud máxima de lÃnea. El lÃmite es de 79 caracteres por lÃnea.
Import. Import
va siempre en la parte de arriba del fichero, en lÃneas separadas, después de los comentarios del módulo. Y debe agruparse en el orden siguiente: librerÃa estandar, módulos de terceros, aplicaciones locales/librerÃas especÃficas. Importaciones del tipo from <module> import *
deben evitarse porque entonces no está claro el módulo del que proceden las aplicaciones y confundir tanto a lectores como a herramientas automáticas.
Convenciones para los nombres
Espacios en blanco en expresiones. Evitar espacios en blanco en las siguientes situaciones:
Para mayor información, mirar Style Guide for Python Code
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.arange( 1, 10, 2 )
print a
print b
print c
print d
Los Ãndices comienzan en cero. El Ãndice -1
da el último elemento del array.
print a[0], b[0,0], b[0][0]
print d[-1]
ndim
: número de dimensiones del array
shape
: número de elementos en cada dimensión
print 'dim = ', b.ndim, '; shape = ', b.shape
Usaremos principalmente los tipos estandar int*
y float*
(además de otros tipos estandar como boolean
):
print a.dtype
print b.dtype
Estos tipos pueden cambiar dentro del programa
a32 = a.astype('int32')
print a32.dtype
Los operadores aritméticos se aplican en los arrays elemento a elemento. ¡En las listas Python funcionan de forma diferente!
a = np.array([1, 2, 3, 4])
b = np.array([(1.5, 2, 3, PI)])
print a+b
a1 = [1, 2, 3, 4]
b1 = [1.5, 2, 3, PI]
print a1+b1
A diferencia de otros lenguajes, el operador *
se aplica elemento a elemento en los arrays NumPy. El producto de matrices se realiza utilizando la función dot
:
A = np.array( [[1, 1], [0, 1]] )
B = np.array( [[2, 3], [1, 4]] )
print A*B
print A.dot(B)
print np.dot(A,B)
Muchas operaciones, como calcular la suma de todos los elementos de un array, se implementan como métodos de las clase ndarray:
print B.max()
print B.max(axis=0)
print B.max(axis=1)
print A.sum()
a = np.arange(10)**3
print a
print a[2:5]
print a[2:5:2]
b = np.array([0, 1, 5, -1])
print a[b]
Análogamente para arrays multidimensionales:
a = np.array([[1, 2, 4], [3, -1, 2]])
print a[0]
print a[1,2]
print a[:2, :2]
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], b[0]
b[0] = 10
print a[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], b[0]
b[0] = 0
print a[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)
Podemos definir funciones de dos formas:
f1 = lambda x: x ** 3
f2 = lambda x,y: x+y
print f1(2)
print f2(1,1)
def f3(x):
if (x>2):
return 0
else:
return 1
print f3(-1)
print f3(3)
Pero si definimos la función de esta manera no funciona con arrays:
print a
print f3(a)
Podemos modificar la función de la manera siguiente
def f3(x):
return np.where(x>2, 0, 1)
print f3(a)
Para más información, ver Numpy Quickstart tutorial
Usamos el paquete Matplotlib para hacer plots sencillos. La segunda lÃnea del código siguiente se usa sólo en Notebooks pero no en lÃnea de comando o en Spyder.
import matplotlib.pyplot as plt
%matplotlib inline
x=np.linspace(-1,2) # definimos la malla
f = lambda x : x**3 - 2*x**2 + 1 # definimos la función
OX=0*f(x)
plt.figure(1)
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.show()
plt.figure(2)
plt.plot(x,np.sin(2*x),x,np.cos(3*x))
plt.xlabel('x')
plt.ylabel('y')
plt.title('El seno y el coseno')
plt.show()
hW, hH = 600, 300
hFreq = 10.5
# Malla en el cuadrado [-1,1]x[-1,1]
x = np.linspace( -1, 1, 30) # columnas (Ancho)
y = np.linspace( -1, 1, 30) # filas (alto)
[X,Y] = np.meshgrid(x,y)
A = np.exp(-(X**2+Y**2)/10)
plt.imshow(A);
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
Z = np.sin(X*2*np.pi)*np.cos(Y*2*np.pi)
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,)
plt.show()