Last active
February 15, 2022 03:48
-
-
Save robintux/4d32b67b368d341edf7cd92ad357f6f3 to your computer and use it in GitHub Desktop.
Una lista de celdas para Spyder (IPython) sobre algunas funcionalidades (basicas) de numpy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ============================================================================= | |
# Abraham Zamudio [GMMNS] | |
# 2020/05/20 | |
# Lima-Peru | |
# ============================================================================= | |
#%% | |
# ============================================================================= | |
# Numpy : Algunos ejemplos [PIT2020II] | |
# ============================================================================= | |
import numpy as np | |
# # Motivacion : | |
# Para datos numericos : Los arrays son mas rapidos y mas eficientes que las listas | |
#%% MatMul:Python | |
# ============================================================================= | |
# Modulos : | |
# random : https://docs.python.org/3/library/random.html | |
# time : https://docs.python.org/3/library/time.html | |
# Multiplicacion de matrices : usando python puro (Listas) | |
# ============================================================================= | |
import random | |
import time | |
start = time.time() | |
n = 200 | |
A = [] | |
for i in range(n): | |
row = [] | |
for j in range(n): | |
row.append(random.random()) | |
A.append(row) | |
B = [] | |
for i in range(n): | |
row = [] | |
for j in range(n): | |
row.append(random.random()) | |
B.append(row) | |
C = [] | |
for i in range(n): | |
row = [] | |
for j in range(n): | |
sum = 0 | |
for k in range(n): | |
sum += A[i][k] * B[k][j] | |
row.append(sum) | |
C.append(row) | |
stop = time.time() | |
print(stop - start) | |
#%% MatMul:Numpy | |
# Multiplicacion de matrices usando numpy | |
start = time.time() | |
n = 1000 | |
A = np.random.random((n, n)) | |
B = np.random.random((n, n)) | |
C = A @ B | |
stop = time.time() | |
print(stop - start) | |
#%% | |
# Creacion de arrays | |
# Existen varios caminos para crear arrays | |
# Usando listas | |
# Creamos una lista | |
vals_list = [1, 3, 2, 8] | |
# Creamos un objeto ndarray a partir de la lista | |
vals_array = np.array(vals_list) | |
print("vals_list: ", vals_list) | |
print("vals_array: ", vals_array) | |
# ndarray to list : metodo tolist | |
print(vals_array.tolist()) | |
#%% | |
# Existen muchas funciones para crear objetos ndarray | |
# np.arange : https://numpy.org/doc/1.18/reference/generated/numpy.arange.html | |
# np.linspace : https://numpy.org/doc/1.18/reference/generated/numpy.linspace.html | |
# Accedemos a la ayuda de la funcion arange : | |
help(np.arange) | |
# Rutinas para la creacion de arrays : | |
# https://numpy.org/doc/1.18/reference/routines.array-creation.html | |
#%% | |
# Otra forma de acceder a la ayuda | |
get_ipython().magic('pinfo np.arange') | |
get_ipython().magic('pinfo np.linspace') | |
#%% | |
# np.arange | |
# creamos un array con enteros : 0,1,...,9 | |
start = 0 | |
end = 10 # neesario para llegar al 0 | |
np.arange(start,end) | |
# Note la diferencia con imprimir usando la funcion print | |
print(np.arange(start,end)) | |
# Podemos omitir el argumento start si deseamos empezar en cero | |
end = 12 | |
print(np.arange(end)) | |
#%% | |
# Podemos modificar el tercer argumento (step size) mayor a 1 | |
# Preste atencion al resultado | |
start = 5 | |
end = 21 # Esto es : 17 + 4 | |
step = 4 | |
print(np.arange(start,end,step)) | |
#%% | |
# no es necesario ir hasta el 21, 18 estaría bien | |
start = 5 | |
end = 18 | |
step = 4 | |
print(np.arange(start,end,step)) | |
#%% | |
# np.linspace | |
start = 0 | |
end = 1 | |
num_points = 11 | |
print(np.linspace(start,end,num_points)) | |
print() | |
print(np.linspace(0,28,12)) | |
#%% | |
# Inicializamos arrays con algunos valores fijos | |
print(np.zeros(5)) | |
print() | |
print(np.ones(7)) | |
print() | |
print(np.empty(3)) | |
#%% | |
# Arrays de varias dimensiones | |
# Arrays (matrices) de dimensiones 5x5 | |
dim = (5,5) # Definimos una tupla | |
print(np.zeros(dim)) | |
print() | |
print(np.zeros((5,5))) | |
#%% | |
# Array 3D de dimension : 4x3x2 | |
dim = (4,3,2) | |
print(np.zeros(dim)) | |
#%% | |
# Tambien funciona en np.empty | |
# Data Types | |
# Recordemos que python es un lenguaje de programacion de tipado dinamico | |
# el tipo de dato de una variable puede ser modificado como se necesite | |
# | |
# .... que ocurre con los arrays de NUmpy ? | |
# .... Los objetos ndarray son tipados de manera estatica | |
# | |
# Entonces, | |
# ¿cuáles son los tipos de datos de las matrices que creamos anteriormente? | |
# ¿Cuáles son los tipos de datos disponibles? | |
# ¿Cómo especificamos qué tipo de datos queremos? | |
vals_list = [1,3,2,8] | |
vals_array = np.array(vals_list) | |
vals_arrayf = np.array(vals_list, dtype=np.float64) | |
print("vals_array: ", vals_array) | |
print("vals_arrayf: ", vals_arrayf) | |
print(type(vals_list)) | |
print(type(vals_array)) | |
print(type(vals_arrayf)) | |
# El argumento dtype es valido para muchas de las funciones de creacion de arrays | |
# Basta con acceder a la ayuda de cada una de las funciones para ver la funcionalidad | |
# de los argumentos | |
#%% | |
print('Enteros: ', vals_array) | |
print('Mas enteros: ', vals_array * 3) | |
print('Punto flotantes: ', vals_array / 3) | |
# También puede copiar un array y cambiar el dtype. | |
#%% | |
arr = np.arange(10.0) # no son enteros | |
x = arr.astype(int) # son enteros | |
print('arr: ', arr) | |
print('x: ', x) | |
#%% | |
# Accesando a los elementos de un array | |
# Ahora que tenemos vectores/matrices, ¿cómo obtenemos cosas de ellas? | |
# Indexado desde 0 | |
# Corchetes para acceder a los elementos | |
vals_arrayf = np.array([1, 3, 2, 8, 24, 0, -1, 12]) | |
print(vals_arrayf) | |
print() | |
print(vals_arrayf[0]) # this selects 0th element | |
print(vals_arrayf[3]) | |
# El uso de indices negativos tambien estan permitidos | |
print(vals_arrayf) | |
print(vals_arrayf[-1]) | |
print(vals_arrayf[-3]) | |
# ¿Qué pasa si quiero una sección/porcion de un vetor/matriz? | |
# Slicing de arrays | |
start_index = 1 | |
end_index = 4 # will stop BEFORE this index - think about np.arange | |
print(vals_arrayf) | |
print() | |
print(vals_arrayf[start_index:end_index]) | |
print(vals_arrayf[1:2]) | |
print(vals_arrayf) | |
print() | |
# esto te dará todos los elementos estrictamente entre 1 y 1 | |
print(vals_arrayf[1:1]) # ningun elemento | |
#%% | |
start = 2 | |
end = 37 # ir demasiado lejos está bien | |
print(vals_arrayf) | |
print() | |
print(vals_arrayf[start:end]) | |
# Si comienza desde el principio, no necesita poner 0: | |
print(vals_arrayf[0:3]) | |
print(vals_arrayf[:3]) | |
# Similar si quieres terminar en el último elemento: | |
print(vals_arrayf[1:8]) | |
print(vals_arrayf[1:]) | |
# ¡También puedes usar índices negativos! | |
print(vals_arrayf) | |
print() | |
print(vals_arrayf[2:-1]) | |
print() | |
print(vals_arrayf[:-2]) | |
# Además de un inicio y un final, también puede elegir un paso para el segmento. | |
start = 0 | |
end = 6 | |
step = 2 | |
print(vals_arrayf) | |
print() | |
print(vals_arrayf[start:end:step]) | |
# Las siguientes dos llamadas hacen lo mismo: | |
print(vals_arrayf[0:8:2]) | |
print(vals_arrayf[::2]) | |
# ¿Qué están haciendo estos dos ejemplos siguientes? | |
print(vals_arrayf) | |
print() | |
print(vals_arrayf[1::2]) | |
print(vals_arrayf[::-1]) | |
#%% | |
# Copias vs. Views (Cambiar accidentalmente el dato (matriz)) | |
# Debe tener cuidado con las matrices `numpy` si desea | |
# tratando de copiar parte de una matriz, o | |
# pasar un vector/matriz a una función | |
# | |
# Puede que te lleves una sorpresa desagradable si cambias un elemento. | |
simple = np.arange(5) | |
small = simple[:2] | |
print(simple) | |
print('') | |
print(small) | |
print('') | |
small[0] = 7 | |
print(small) | |
print('') | |
print(simple) # no debería haber cambiado, ¿verdad? | |
# Esto sucede porque small es algo llamado una "vista (view)" de "simple", en | |
# lugar de una copia. Esto ayuda a numpy a ahorrar memoria y a acelerar su | |
# programa, pero puede generar errores difíciles de comprender si no es su | |
# intención. En general, puede ser difícil saber si algo será una "vista" | |
# o una copia. | |
#%% | |
# Las funciones tampoco hacen copias de sus matrices de entrada. | |
def Algo(x): # no se retorna x | |
x[0] = 100 | |
Algo(simple) | |
print(simple) | |
# Si cree que está cambiando accidentalmente su matriz en otra parte de su código, | |
# puede copiarla para que sea segura. Esto ralentiza su programa y usa más memoria, | |
# pero puede ayudar a depurar y ahorrar muchos dolores de cabeza. | |
simple = np.arange(5) | |
print('before:') | |
print(simple) | |
my_copy = simple[:2].copy() | |
my_copy[1] = 10 | |
Algo(simple.copy()) | |
print('after:') | |
print(simple) | |
#%% | |
# Arrays (matrices) de varias dimensiones | |
# Nota: Hay una clase numpy.matrix, pero debe evitar usarla. Utilice matrices | |
# bidimensionales en su lugar. | |
# ¿Cómo creamos matrices multidimensionales? | |
# creacion desde listas multidimensionales | |
mat = np.array([[1,4,8],[3,2,9],[0,5,7]], float) | |
print(mat) | |
print('') | |
#%% | |
# Creacion de matrices especiales | |
print(np.zeros((2,3), dtype=float)) # ya viste esto ... pero esta vez estamos especificando el tipo | |
print('') | |
print(np.zeros_like(mat)) | |
print('') | |
# np.zeros_like crea na matriz con la misma forma, dimension, y tipo de datos | |
# de una matriz ya existente | |
print(np.identity(3, dtype=float)) | |
#%% | |
# ¿Cómo accedemos a los elementos de matrices multidimensionales? | |
print(mat) | |
print(mat[1,2]) | |
#%% | |
print(mat[0,0], mat[1,1], mat[2,2]) | |
print(mat) | |
print() | |
print(mat[2]) | |
# Puede hacer lo mismo con el slicing de la matriz: | |
print(mat[2,:]) | |
print(mat[:,1]) | |
print() | |
# lo obligamos a ser un vector de columna ... | |
print(mat[:,1:2]) | |
print() | |
print(mat[:,[1]]) | |
# Interpreta la siguiente linea de codigo | |
print(mat[:,:2]) | |
#%% | |
# puedes hacer esto con np.ones o np.zeros y slicing | |
N = 8 # Crea una matriz de tamaño NxN | |
# ¿Qué pasa si queremos una matriz de una forma (dimension) diferente? | |
# Esta puede ser una forma conveniente de inicializar matrices. | |
arr = np.arange(8) | |
two_four = arr.reshape(2, 4) | |
four_two = arr.reshape(4, 2) | |
eight_none = four_two.flatten() | |
print('array:') | |
print(arr.shape) | |
print('') | |
print('2 x 4:') | |
print(two_four) | |
print('') | |
print('4 x 2:') | |
print(four_two) | |
print('') | |
print('Regresamos al array:') | |
print(eight_none) | |
print(eight_none.shape) | |
#%% | |
# Algunos metodos de los objetos ndarray | |
# Veremos algunas funciones de arrays (objetos de tipo ndarray). Hay muchos más disponibles. | |
# La mejor manera de encontrar la función que desea es buscar en Google lo que desea y | |
# encontrar la documentación correspondiente (probablemente haya una función que haga lo | |
# que desea hacer, o en el peor de los casos tenga que combinar funcionalidad de varias | |
# funciones ). | |
new_mat = mat[:,:2] | |
print(new_mat) | |
# Shape (forma o dimension) del objeto ndarray | |
print(new_mat.shape) # en realidad no es una función, sino un metodo (atributo) | |
# Ordenacion de un array | |
# Dos diferentes metodos | |
# np.sort : https://numpy.org/doc/1.18/reference/generated/numpy.sort.html | |
# np.ndarray.sort : https://numpy.org/doc/1.18/reference/generated/numpy.ndarray.sort.html | |
# Una es una función numpy (llamada np.sort ()) y devuelve una copia de la matriz en orden ordenado. | |
# La otra es un metodo (atributo) que se le aplica al array y la ordena (en si misma) | |
# | |
# NOTAS Importantes | |
# Algunas funciones trabajan solo el mismo objeto ndarray, mientras que otras devuelven copias. | |
# Siempre recordar usar type, dir y mas comunmente leer/estudiar la documentacion | |
#%% | |
# Ejemplo de ordenacion | |
vals_arrayf = np.array([1, 3, 2, 8, 24, 0, -1, 12]) | |
print(np.sort(vals_arrayf)) # retorna una copia | |
print(vals_arrayf) | |
vals_arrayf.sort() # ordenamiento inplace | |
print(vals_arrayf) | |
#%% | |
# Verificamos pertenencia | |
print(9 in mat) | |
print(9 in vals_arrayf) | |
# Muchas operaciones elemento a elemento (elementwise) se realizan automáticamente | |
# con arrays. Éstas incluyen: | |
# adicion | |
# sustraccion | |
# multiplicacion | |
# division | |
# comparaciones | |
#%% | |
mat_2 = np.array([[1,3],[2,5]], float) | |
id_2 = np.identity(2, float) | |
print(mat_2) | |
print('') | |
print(id_2) | |
print('') | |
print('sum:') | |
print(mat_2 + id_2) | |
print('') | |
print('difference:') | |
print(mat_2 - id_2) | |
print('') | |
print('product:') | |
print(mat_2 * id_2) # OJO : NO es una multiplicacion matricial | |
print('') | |
print('quotient:') | |
print(id_2 / mat_2) | |
print('power:') | |
print(mat_2**3) | |
#%% | |
# Tambien puedes comparar valores | |
print(mat_2 == id_2) | |
print(' ') | |
print(mat_2 > id_2) | |
#%% | |
# Funciones variadas : Notar las operaciones elemento a elemento | |
print(np.exp(id_2)) | |
print() | |
print(np.abs(vals_arrayf)) | |
print() | |
print(np.log2(mat_2)) | |
print() | |
print(np.reciprocal(mat_2)) | |
#%% | |
# Funciones trigonometricas : | |
print(np.sin(mat_2)) | |
print(np.tan(id_2)) | |
#%% | |
# redondeo : | |
help(np.round) | |
print(np.round(np.sin(mat_2), 2)) | |
#%% | |
# También puede realizar operaciones entre arrays y números (variables escalares): | |
print(mat_2) | |
print() | |
print(mat_2 - 3) # restamos 3 a cada elemento de mat_2 | |
print() | |
print(mat_2*8) # Multiplicamos por 8 cada elemento de mat_2 | |
#%% | |
x = np.linspace(-1,1,30) | |
# Recordemos las matrices de comparación: | |
print(mat_2) | |
print(id_2) | |
print() | |
print(mat_2 == id_2) | |
print(' ') | |
print(mat_2 > id_2) | |
# Puede comparar matrices y usar la matriz booleana resultante para manipular | |
# las entradas de otra matriz | |
z = mat_2 > id_2 | |
print(z) | |
print() | |
print(mat_2) | |
print() | |
print(mat_2 * z) | |
# Esto podría ayudarlo a comprender lo que sucedió: | |
print(z*1) | |
#%% | |
x = np.linspace(-1,1,30) | |
# Broadcasting (Operaciones basadas en elementos en arrays de diferentes dimensiones | |
# No es necesario para esta demostracion, pero échale un vistazo si estás interesado. | |
# Cada operación de "broadcast" (transmision) se puede hacer usando bucles, pero la | |
# operacion de Broadcasting es más rápida. | |
# Ver : A Gentle Introuction to Broadcasting with Numpy Arrays | |
# https://machinelearningmastery.com/broadcasting-with-numpy-arrays/ | |
# para una detallada explicacion | |
# El caso más simple de broadcasting es sumar un solo número a cada elemento de una matriz | |
# Aquí está la forma matemáticamente correcta de agregar un número a cada elemento de | |
# una matriz | |
bmat = np.arange(12).reshape(4, 3) | |
print(bmat) | |
print() | |
z = 3*np.ones_like(bmat) # what is this doing? | |
print(z) | |
print() | |
print(bmat + z) | |
#%% | |
# Pero vimos que puede agregar un número directamente ... Numpy está | |
# "transmitiendo" (broadcasting) el valor | |
print(bmat) | |
print() | |
z = 3 | |
print(z) | |
print() | |
print(bmat + z) | |
# Consejo: familiarízate con Python y Numpy, y preocúpate por hacer el broadcasting | |
# más tarde. Solo recuerda que puedes agregar un solo número a una matriz, y que hay | |
# algo detrás de escenas | |
#%% | |
# Operaciones matematicas como metodos a objetos ndarray | |
bmat = np.array([6, 7, -12, 0, 3, 4, 21, 1, 1, 0, 2, 5]).reshape(4,3) | |
print(bmat) | |
print() | |
print(bmat.min()) | |
print(bmat.max()) | |
print(bmat.sum()) | |
# ¿Qué pasa si quiero el número más pequeño en cada fila? | |
# Todas estas operaciones de reducción toman un argumento opcional 'axis' que nos | |
# permite apuntar a una dimensión particular de la matriz. | |
print('Minimo para filas:') | |
print(bmat.min(axis=1)) | |
print('Minimo para columnas:') | |
print(bmat.max(axis=0)) | |
print('Suma (filas):') | |
print(bmat.sum(axis = 1)) | |
# Tenga en cuenta que cuando pasamos un argumento `axis`, perdemos esa dimensión de | |
# nuestra matriz, pero la forma no cambia. Entonces, una matriz (4, 3) se convierte | |
# en una matriz (3,) si pasamos `axis = 0`, y se convierte en una matriz (4,) si | |
# pasamos` axis = 1`. | |
# Otras reducciones | |
print(bmat) | |
print() | |
print('promedio aritmetico:') | |
print(bmat.mean()) | |
print() | |
print('Media (columnas):') | |
print(bmat.mean(axis = 0)) | |
#%% | |
print(bmat) | |
print() | |
print('producto:') | |
print(bmat.prod()) | |
print('producto - columna:') | |
print(bmat.prod(axis = 0)) | |
#%% | |
# Tratar arrays como matrices y vectores | |
# multiplicacion matricial y producto punto : | |
print(np.dot(mat_2, id_2)) | |
print('') | |
print(mat_2 @ id_2) | |
print('') | |
print(np.dot(vals_arrayf, np.array([0,2,6,1, 1, 2, 3, 4]))) | |
# Transpuesta | |
print(mat_2) | |
print() | |
print(np.transpose(mat_2)) | |
print() | |
print(mat_2.T) | |
#%% | |
# COnstantes de numpy | |
# LIsta de constantes: | |
# https://numpy.org/doc/stable/reference/constants.html | |
print(np.pi) # el famoso numero irracional | |
print(np.e) # numero de euler : np.exp(1) | |
print(np.inf) # infinit | |
print(np.NINF) # infinito negativo | |
print(np.nan) # not a number | |
#%% | |
# Numeros Pseudoaleatorios | |
# A menudo necesitaremos saber generar numeros pseudoaleatorios | |
# NUmpy puede generar numeros de una variedad de distribuciones | |
# inclusive puede generar vectores con las dimensiones que uno desee | |
# https://numpy.org/doc/1.18/reference/random/index.html | |
# Algunas funciones comunmente usadas son : | |
# np.random.rand | |
# np.random.randn | |
# np.random.randint | |
# Todas estas rutinas le dan la opción de generar una matriz de una dimension específica. | |
uniform_nums = np.random.rand(10) | |
print(uniform_nums) | |
print('') | |
normal_nums = np.random.randn(3, 5) | |
print(normal_nums) | |
print('') | |
integers = np.random.randint(0, 10, (4, 2)) | |
print(integers) | |
print('') | |
#%% | |
# ============================================================================= | |
# # Qué más hay en Numpy | |
# # ¡Hay muchas más funciones en Numpy! | |
# # Lea la documentación y busque las cosas en Google | |
# # ¡Probablemente alguien ya hizo su pregunta sobre Stack Exchange o Stack Overflow! | |
# ============================================================================= | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment