Arreglos
Arreglos
Arreglos
Introduccion
Las estructuras de datos que hemos visto hasta ahora (listas, tuplas, diccionarios,
conjuntos) permiten manipular datos de manera muy flexible. Combinándolas y
anidándolas, es posible organizar información de manera estructurada para
representar sistemas del mundo real.
La estructura de datos que sirve para almacenar estas grandes secuencias de números
(generalmente de tipo float) es el arreglo.
A la vez, los arreglos tienen muchas ventajas por sobre las listas, que iremos
descubriendo a medida que avancemos en la materia.
Los arreglos son los equivalentes en programación de las matrices y vectores de las
matemáticas. Precisamente, una gran motivación para usar arreglos es que hay mucha
teoría detrás de ellos que puede ser usada en el diseño de algoritmos para resolver
problemas verdaderamente interesantes.
Crear arreglos
El módulo que provee las estructuras de datos y las funciones para trabajar con arreglos
se llama NumPy, y no viene incluído con Python, por lo que hay que instalarlo por
separado.
Para usar las funciones provistas por NumPy, debemos importarlas al principio del
programa:
(Si no recuerda cómo usar el import, puede repasar la materia sobre módulos).
El tipo de datos de los arreglos se llama array. Para crear un arreglo nuevo, se puede
usar la función array pasándole como parámetro la lista de valores que deseamos
agregar al arreglo:
Todos los elementos del arreglo tienen exactamente el mismo tipo. Para crear un
arreglo de números reales, basta con que uno de los valores lo sea:
>>> a
array([6, 1, 3, 9, 8])
>>> a.astype(float)
array([ 6., 1., 3., 9., 8.])
>>> a.astype(complex)
array([ 6.+0.j, 1.+0.j, 3.+0.j, 9.+0.j, 8.+0.j])
Hay muchas formas de arreglos que aparecen a menudo en la práctica, por lo que
existen funciones especiales para crearlos:
>>> zeros(6)
array([ 0., 0., 0., 0., 0., 0.])
>>> ones(5)
array([ 1., 1., 1., 1., 1.])
>>> linspace(1, 2, 5)
array([ 1. , 1.25, 1.5 , 1.75, 2. ])
>>> a
array([55, 21, 19, 11, 9])
Note que si quisiéramos hacer estas operaciones usando listas, necesitaríamos usar un
ciclo para hacer las operaciones elemento a elemento.
>>> a < b
array([False, True, True, False], dtype=bool)
>>> a == c
array([ True, True, True, True], dtype=bool)
Para reducir el arreglo de booleanos a un único valor, se puede usar las funciones any y
all. any retorna True si al menos uno de los elementos es verdadero, mientras que all
retorna True sólo si todos lo son (en inglés, any signfica «alguno», y all significa «todos»):
>>> sin(x)
array([ 0. , 0.19509032, 0.38268343,
0.55557023, 0.70710678, 0.83146961,
0.92387953, 0.98078528, 1. ])
Como puede ver, los valores obtenidos crecen desde 0 hasta 1, que es justamente como
se comporta la función seno en el intervalo [0, π/2].
Aquí también se hace evidente otra de las ventajas de los arreglos: al mostrarlos en la
consola o al imprimirlos, los valores aparecen perfectamente alineados. Con las listas,
esto no ocurre:
>>> list(sin(x))
[0.0, 0.19509032201612825, 0.38268343236508978, 0.5555702330
1960218, 0.70710678118654746, 0.83146961230254524, 0.9238795
3251128674, 0.98078528040323043, 1.0]
Arreglos aleatorios
El módulo NumPy contiene a su vez otros módulos que proveen funcionalidad adicional
a los arreglos y funciones básicos.
El módulo numpy.random provee funciones para crear números aleatorios (es decir,
generados al azar), de las cuales la más usada es la función random, que entrega un
arreglo de números al azar distribuidos uniformemente entre 0 y 1:
>>> random(3)
array([ 0.53077263, 0.22039319, 0.81268786])
>>> random(3)
array([ 0.07405763, 0.04083838, 0.72962968])
>>> random(3)
array([ 0.51886706, 0.46220545, 0.95818726])
>>> a[0]
6.2
>>> a[1]
-2.3
>>> a[-2]
4.7
>>> a[3]
4.7
Una seccion del arreglo puede ser obtenida usando el operador de rebanado a[i:j]. Los
índices i y j indican el rango de valores que serán entregados:
>>> a
array([ 6.2, -2.3, 3.4, 4.7, 9.8])
>>> a[1:4]
array([-2.3, 3.4, 4.7])
>>> a[2:-2]
array([ 3.4])
>>> a[:2]
array([ 6.2, -2.3])
>>> a[2:]
array([ 3.4, 4.7, 9.8])
Un tercer índice puede indicar cada cuántos elementos serán incluídos en el resultado:
>>> a = linspace(0, 1, 9)
>>> a
array([ 0. , 0.125, 0.25 , 0.375, 0.5 , 0.625, 0.75 , 0.875, 1. ])
>>> a[1:7:2]
array([ 0.125, 0.375, 0.625])
>>> a[::3]
array([ 0. , 0.375, 0.75 ])
>>> a[-2::-2]
array([ 0.875, 0.625, 0.375, 0.125])
>>> a[::-1]
array([ 1. , 0.875, 0.75 , 0.625, 0.5 , 0.375, 0.25 , 0.125, 0. ])
Una manera simple de recordar cómo funciona el rebanado es considerar que los
índices no se refieren a los elementos, sino a los espacios entre los elementos:
Los métodos argmin y argmax entregan respectivamente la posición del mínimo y del
máximo:
>>> a.argmin()
4
>>> a.argmax()
2
>>> a.sum()
24.041592653589795
>>> a.prod()
-11393.086289208301