NumPy es el módulo básico para la computación científica y la ciencia de datos en Python. Su objeto más usado son los arreglos multidimensionales, los cuales tienen las siguientes características:
Esta es la forma canónica en que se importa Numpy y se crea un arreglo
In [1]:
import numpy as np
In [2]:
data = [0.,2,4,6]
a = np.array(data)
In [3]:
a
Out[3]:
La forma de un arreglo:
In [4]:
a.shape
Out[4]:
El número de dimensiones del arreglo:
In [5]:
a.ndim
Out[5]:
El número de elementos del arreglo:
In [6]:
a.size
Out[6]:
El número de bytes que ocupa el arreglo:
In [7]:
a.nbytes
Out[7]:
El atributo dtype
describe el "tipo de datos" (data type) de los elementos:
In [8]:
a.dtype
Out[8]:
Los arreglos pueden ser creaados con listas or tuplas anidadas:
In [9]:
data = [[0.0, 2.0, 4.0, 6.0], [1.0, 3.0, 5.0, 7.0]]
b = np.array(data)
In [10]:
b
Out[10]:
In [11]:
b.shape, b.ndim, b.size, b.nbytes
Out[11]:
La función arange
es similar a la función range
de Python, pero crea un arreglo, no un iterador:
In [12]:
c = np.arange(0.0, 10.0, 1.0) # paso entre valores de 1.0
c
Out[12]:
La función linspace
es similar, pero permite especificar el número de puntos:
In [13]:
e = np.linspace(0.0, 5.0, 11) # 11 points
e
Out[13]:
También hay funciones zeros
y ones
:
In [14]:
np.zeros((3,3))
Out[14]:
In [15]:
np.ones((3,3))
Out[15]:
Los arreglos tienen un atributo dtype
que guarda el tipo de datos de cada elemento. Puede ser definido:
dtype
a una función de creación de arreglosEste es un arreglo de tipo entero:
In [16]:
a = np.array([0, 1, 2, 3])
In [17]:
a, a.dtype
Out[17]:
Todas las funciones de creación de arreglos aceptan un argumento opcional dtype
para cambiar el tipo de los datos del arreglo:
In [18]:
c = np.arange(0, 10, 2, dtype=np.float)
c
Out[18]:
También es posible usar el método astype
para crear una copia del arreglo con un dtype
dado:
In [19]:
d = c.astype(dtype=np.int)
d
Out[19]:
La documentación de NumPy sobre dtypes (en inglés) describe todas las formas que existen para especificar dtypes.
Las operaciones matemáticas básicas son elemento a elemento para:
Por ejemplo, a continuacuón creamos un arreglo vacío y lo llenamos con un valor
In [20]:
a = np.empty((3,3))
a.fill(0.1)
a
Out[20]:
In [21]:
c = np.ones((3,3))
c
Out[21]:
La multiplicacion por escalar es elemento a elemento:
In [22]:
b = 2 * c
b
Out[22]:
La adición es elemento a elemento:
In [23]:
a + b
Out[23]:
La multiplicación es elemento a elemento (no como la multiplicacion de matrices en algebra lineal).
In [24]:
a * b
Out[24]:
La división es elemento a elemento:
In [25]:
a / b
Out[25]:
Como también lo son las potencias:
In [26]:
a**2
Out[26]:
El indexado y rebanado proveen una forma eficiente de obtener los valores de un arreglo y de modificarlos.
In [27]:
np.random.seed(0)
In [28]:
# de esta manera forzamos a python que el output de cada celda tenga maximo dos cifras decimales
%precision 2
Out[28]:
In [29]:
a = np.random.rand(9, 9)
In [30]:
a
Out[30]:
Al igual que las listas y tuplas de Python, los arreglos de NumPy tienen un indexado que empieza en cero y utilizan los corchetes ([]
) para obtener y definir valores:
In [31]:
a[0,0]
Out[31]:
In [32]:
a[0,4]
Out[32]:
In [33]:
a[4,0]
Out[33]:
Un índice de -1
se refiere al último elemento a lo largo de un eje:
In [34]:
a[-1,-1]
Out[34]:
Para extraer la columna 0 usa se la sintaxis :
, que denota todos los elementos a lo largo de un eje.
In [35]:
a[:,0]
Out[35]:
La última fila se extrae así:
In [36]:
a[-1,:]
Out[36]:
También se pueden rebanar rangos, así:
In [37]:
a[0:2,0:2]
Out[37]:
La asignación también funciona con rebanados:
In [38]:
a[0:5,0:5] = 1.0
In [39]:
a
Out[39]:
Es importante notar como aún cuando asignamos el valor a una porción, el arreglo original fue modificado. Esto demuestra que los rebanados son vistas de los mismos datos, no una copia de los mismos.
Los arreglos pueden ser indexados usando otros arreglos que tienen valores booleanos.
In [40]:
edades = np.array([23, 56, 67, 89, 23, 56, 27, 12, 8, 72])
generos = np.array(['m', 'm', 'f', 'f', 'm', 'f', 'm', 'm' ,'m', 'f'])
Las expresiones booleanas que involucran arreglos crean nuevos arreglos con un tipo de datos bool
y el resultado elemento a elemento de expresiones de la forma:
In [41]:
edades > 30
Out[41]:
In [42]:
generos == 'm'
Out[42]:
Las expresiones booleanas proveen una forma extremadamente rápida y flexible de consultar los contenidos de arreglos:
In [43]:
(edades > 10) & (edades < 50)
Out[43]:
Es posible usar un arreglo booleano para para indexar el arreglo original u otro arreglo. Por ejemplo, la siguiente expresión seleccciona las edades de todas las mujeres en el arreglo generos
:
In [44]:
mascara = (generos == 'f')
edades[mascara]
Out[44]:
In [45]:
edades[edades > 30]
Out[45]:
In [46]:
a = np.random.rand(3,4)
In [47]:
a
Out[47]:
el atributo T
contiene la transpuesta del arreglo original:
In [48]:
a.T
Out[48]:
El método reshape
puede ser usado para cambiar la forma y el número de dimensiones de un arreglo:
In [49]:
a.reshape(2,6)
Out[49]:
In [50]:
a.reshape(6,2)
Out[50]:
El método ravel
convierte un arreglo de cualquier número de dimensiones en uno de una sola dimensión:
In [51]:
a.ravel()
Out[51]:
Las funciones universales, o "ufuncs," son funciones que toman y retornan arreglos o números. Éstas tienen las siguientes características:
for
en Python.Esta es una secuencia lineal de valores
In [52]:
t = np.linspace(0.0, 4*np.pi, 100)
t
Out[52]:
Este es el resultado de la función seno aplicada a todos los elementos del arreglo:
In [53]:
np.sin(t)
Out[53]:
Como muestran los siguientes ejemplos, múltiples ufuncs pueden ser usadas para crear complejas expresiones matemáticas que pueden ser calculadas eficientemente:
In [54]:
np.exp(np.sqrt(t))
Out[54]:
In [55]:
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('ggplot')
In [56]:
plt.plot(t, np.exp(-0.1*t)*np.sin(t))
Out[56]:
En general, siempre se debería intentar utilizar las ufuncs en lugar de ciclos for. Esta clase de cálculos basados en arreglos se conocen como vectorizados.
In [57]:
edades = np.array([23, 56, 67, 89, 23, 56, 27, 12, 8, 72])
generos = np.array(['m', 'm', 'f', 'f', 'm', 'f', 'm', 'm', 'm', 'f'])
Numpy tiene un conjunto básico de métodos y funciones para calcular cantidades básicas sobre ciertos datos.
In [58]:
edades.min(), edades.max()
Out[58]:
Calcular la media:
In [59]:
edades.mean()
Out[59]:
Calcular la varianza y la desviación estandar:
In [60]:
edades.var(), edades.std()
Out[60]:
La función bincount
cuenta cuantas veces ocurre cada valor en un arreglo:
In [61]:
np.bincount(edades)
Out[61]:
Los métodos cumsum
y cumprod
calculan las sumas y productos acumulados:
In [62]:
edades.cumsum()
Out[62]:
In [63]:
edades.cumprod()
Out[63]:
La mayoría de las funciones y métodos anteriores toman un argumento llamado axis
que aplica la operación a lo largo de un eje particular:
In [64]:
a = np.random.randint(0, 10, (3,4))
a
Out[64]:
Con axis=0
, la operación toma lugar a lo largo de las filas:
In [65]:
a.sum(axis=0)
Out[65]:
Con axis=1
la operación toma lugar a lo largo de las columnas:
In [66]:
a.sum(axis=1)
Out[66]:
La función unique
es muy útil para trabajar con datos categóricos:
In [67]:
np.unique(generos)
Out[67]:
In [68]:
np.unique(generos, return_counts=True)
Out[68]:
La función where
permite aplicar lógica condicional a los arreglos. Este es un esquema de cómo funciona:
np.where(condicion, si_falsa, si_verdadera)
In [69]:
np.where(edades > 30, 0, 1)
Out[69]:
Los valores si_falsa
y si_verdadera
pueden ser arreglos:
In [70]:
np.where(edades < 30, 0, edades)
Out[70]:
NumPy tiene varias funciones para leer y escribir arreglos de y hacia el sistema operativo.
In [71]:
a = np.random.rand(10)
a
Out[71]:
Save the array to a binary file named array1.npy
:
In [72]:
np.savetxt('array.txt', a)
Load the array back into memory:
In [73]:
a_copy = np.loadtxt('array.txt')
In [74]:
a_copy
Out[74]:
NumPy tambien puede hacer operaciones de algebra lineal
In [84]:
a = np.random.rand(5,5)
b = np.random.rand(5,5)
Para hacer una multiplicacion de matrices sobre los arreglos a
y b
, se usa la funcion np.dot
.
In [86]:
np.dot(a, b)
Out[86]:
El paquete np.linalg
tiene muchas operaciones de algebra lineal.
Determinante:
In [89]:
np.linalg.det(a)
Out[89]:
Inversion de matrices:
In [90]:
np.linalg.inv(a)
Out[90]:
Eigenvalores:
In [91]:
np.linalg.eigvals(a)
Out[91]:
Nota Importante: Los contenidos de esta lección son una reediсión de Data Science for Everyone, por Brian Granger