0% encontró este documento útil (0 votos)
47 vistas205 páginas

UD3 Datos Librerías Numpy Pandas

Este documento describe los conceptos y herramientas fundamentales de procesamiento de datos y ciencia de datos en Python, incluyendo Numpy y Pandas. Introduce la gestión de archivos CSV, JSON y XML, explica los conceptos básicos de Numpy como arrays unidimensionales y multidimensionales, y concluye describiendo los dataframes de Pandas y cómo trabajar con ellos.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
47 vistas205 páginas

UD3 Datos Librerías Numpy Pandas

Este documento describe los conceptos y herramientas fundamentales de procesamiento de datos y ciencia de datos en Python, incluyendo Numpy y Pandas. Introduce la gestión de archivos CSV, JSON y XML, explica los conceptos básicos de Numpy como arrays unidimensionales y multidimensionales, y concluye describiendo los dataframes de Pandas y cómo trabajar con ellos.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 205

Procesamiento de datos y librerías para ciencia de

datos: Numpy y Pandas

I. Introducción y objetivos

II. Procesamiento de archivos

III. Numpy

IV. Pandas

V. Resumen

VI. Caso práctico con solución

VII. Glosario

VIII. Bibliografía
Lección 1 de 8

I. Introducción y objetivos

1.1. Introducción de la unidad

En este módulo se exponen dos de las librerías por excelencia dentro del mundo de la ciencia de datos:
Numpy y Pandas.
1

Previamente, se verá cómo tratar con archivos de tipo JSON, XML y CSV, algo imprescindible a la
hora de trabajar con Pandas.
2

Además, se darán a conocer utilidades de la librería para el manejo de arrays y otros cálculos
aritméticos y se enseñarán las principales funciones que podemos utilizar sobre arrays, tanto de
una dimensión (unidimensionales), como de más de una dimensión (multidimensionales), así
como el tipo de operaciones que es posible realizar sobre estos.
3

Finalmente, se explicará qué son los dataframes y cómo podemos trabajar con estos a través de
la librería Pandas.

C O NT I NU A R

1.2. Objetivos de la unidad


Una vez finalizada esta unidad, el alumno habrá adquirido las siguientes competencias sobre el stack
científico de Python:

1 Conocer los principales tipos de archivos con los que podemos trabajar en Python.

2 Saber realizar operaciones de lectura y escritura de archivos.

3 Aprender a utilizar arrays unidimensionales y multidimensionales.

4 Diferenciar las diferentes dimensiones de un array.

5 Comprender qué es un objeto series y cuál es su relación dentro de los dataframes.

6 Conocer las funcionalidades y transformaciones fundamentales que podemos realizar en


dataframes.
Lección 2 de 8

II. Procesamiento de archivos

Algunos de los archivos más utilizados por los científicos de datos son XML, CSV y JSON. En la siguiente
sección, se dedica un epígrafe a cada uno de ellos.
Se aconseja seguir el contenido de esta sesión a través de los siguientes notebooks:

GESTIÓN_DE_ARCHIVOS.zip
3.9 KB

GESTIÓN_DE_ARCHIVOS_html.zip
43.7 KB

C O NT I NU A R

2.1 Gestión de archivos CSV


Un archivo de extensión CSV1 (comma separated values) se trata de un archivo de texto plano que contiene
todos sus datos separados por comas. Estos archivos se encuentran estructurados por líneas (filas) y cada
campo separado por comas puede actuar como una columna. Por lo general, son visualizados en software
para hojas de cálculo, aunque, en esta ocasión, veremos cómo leer y escribir CSV desde Python.

Aquí, podemos ver la estructura de un archivo CSV.


1

FECHA,ARTICULO,CUANTIA,PRECIO UNIDAD,TOTAL
15/03/2020,Barra Pan,2,0.55,1.1
16/03/2020,Bolígrafo Bic,3,0.22,0.66
17/03/2020,Cuaderno,1,1.25,1.25
18/03/2020,Refresco,5,0.8,4
19/03/2020,Silla Gamer,1,153,153
20/03/2020,Paquete folios A4,3,2.48,7.44
21/03/2020,Pack x6 Vaso cristal,2,6,12
22/03/2020,Manzanas (Kg.),1,2.48,2.48
23/03/2020,Naranjas (Kg.),2,1.29,2.58
24/03/2020,Naranja Malla,1,1.5,1.5
2

Figura 1. Archivo CSV.


Fuente: elaboración propia.

1 Valores separados por comas [En línea] URL disponible en este enlace.

C O NT I NU A R

Para importar y poder leer un archivo CSV en Python, lo primero que tenemos que saber es cómo importar
una librería.
 NOTA: una librería consiste en un conjunto de funciones empaquetadas que, al
importarse en Python, nos permiten disponer de más funcionalidades para realizar
diferentes tareas, en este caso, para procesar archivos. En Python, para importar una
librería escribiremos lo siguiente: “import nombre_de_la_librería”.

En este caso, la librería en cuestión para procesar archivos CSV se llama “csv” 2.

Figura 2. "import csv".


Fuente: elaboración propia.

2 Documentación de librería CSV. [En línea] URL disponible en este enlace.

C O NT I NU A R
Lo siguiente que debemos tener en cuenta, es cómo abrir un archivo; para ello, siempre
utilizaremos la función open, la cual tiene los siguientes parámetros:
1

Nombre del archivo a leer o escribir.


2

Modo de lectura o escritura, que puede tomar los siguientes valores:

“r” (read): lectura, por defecto.

“w” (write): escritura, para crear un nuevo archivo.


3

Adicionalmente, al parámetro modo se le podrá añadir:

“t” (text): para archivo de texto.

“b” (binary): para archivos binarios o imágenes.

Figura 3. Apertura de archivo CSV.


Fuente: elaboración propia.

Es importante atender a la anterior imagen, ya que, cuando se utiliza la función open por sí sola, no se lee el
archivo como tal, sino que se crea un objeto de entrada y salida con base en el archivo.
comprascsv.zip
427 B

C O NT I NU A R
1

Figura 4. “csv.reader”.
Fuente: elaboración propia.

Para poder procesar el archivo y que tenga en Python la estética de una tabla, se hará uso de la
función de la librería CSV “csv.reader”. 
2

Figura 5. Archivo CSV en Python.


Fuente: elaboración propia.

Como se puede comprobar, todavía queda trabajo, ya que, de nuevo, se genera un objeto con
base en el archivo, en este caso “csv.reader”. Para darle forma, los archivos CSV deben utilizarse
como listas. Para ello, simplemente se utilizará la función list para transformar nuestro archivo
en un conjunto de listas. .
3

Finalmente, se obtiene el archivo CSV procesado en Python. Es importante recalcar que los CSV
toman todos los valores como cadenas de texto, por lo que, para realizar futuras acciones sobre
columnas como “cuantía”, “precio unidad” y “total”, habría que modificar (cast) las variables de
cadena (STR) a entero (INT). Una de las grandes ventajas que nos va a ofrecer Pandas es que
reconocerá automáticamente el tipo de las variables y nos ahorrará este trabajo.
4

Figura 6. CSV procesado.


Fuente: elaboración propia.

Una vez expuesto cómo leer un archivo CSV, se procederá a su escritura. El primer paso es añadir
más líneas (filas) al CSV actual, es decir: añadir más elementos a la lista que contiene el CSV
procesado.
5

Finalmente, con el CSV actualizado, se utilizarán las siguientes líneas de código para escribirlo y
guardarlo.

file = open('compras_actualizadas.csv', 'wt', newline='')


writer = csv.writer(file)
writer.writerows(clean_compras)
file.close()
6

Figura 7. Escribir CSV.


Fuente: elaboración propia.

En esta ocasión, a diferencia del proceso de lectura, en la función open se utiliza  el “mode ‘w’” en
lugar de la función “csv.reader”. Por el contrario, se utiliza “csv.writer” para obtener un objeto
writer y, lo más importante de todo, para poder exportar todas las líneas (filas) de la lista, se utiliza
la función writerows sobre un objeto “csv.writer” creado previamente.
7

Figura 8. Vista CSV guardado.


Fuente: elaboración propia

Para cerrar la edición del archivo, utilizaremos la función close.

C O NT I NU A R

2.2. Gestión de archivos JSON


Un archivo JSON[3](Java object notation) es un tipo de archivo con una estructura interna muy similar a un
diccionario de datos en Python, ya que todos sus valores se guardan en formato “{clave : valor }”. Se muestra
en el siguiente ejemplo un archivo JSON.
1

   "IBEX_35":[

     {"ACCIONA" : [95.9500, 14.70,    95.9500,  95.9500,  6.302]},

     {"B. SANTANDER": [2.2195,   9.99,     2.2195,   2.2195,     203.685]},

     {"IBERDROLA": [8.5880, 4.32,     8.5880,   8.5880,   98.298    ]}

    ],

    

   "IBEX_MEDIUM_CAP": [

     {"EUSKALTEL": [6.1500, 3.71,     6.1500,   6.0200,   947]},

     {"LIBERBANK": [0.1552, 7.48,     0.1648,   0.1551,   304.384]},

     {"SACYR": [1.1960, 4.09,     1.2260,   1.1960,   125.271]}

  ]

}
2

Figura 9. Estructura de archivo JSON.


Fuente: elaboración propia.

3JSON. [En línea] URL disponible en este enlace.

C O NT I NU A R

Para gestionar archivos JSON, se utiliza la librería JSON[4]. El primer paso es importar un archivo JSON. Al
igual que en los archivos CSV, se utiliza la función open. 

Ejemplo
Un ejemplo de lectura de un JSON puede ser el siguiente:
import json
with open('mercados.json', 'rb') as f:
    mercados = json.load(f)

Exportar el archivo

Del ejemplo anterior, se debe prestar especial atención a la función json.load(objecto_open), ya que se
encarga de exportar el archivo de cadena de texto, que es lo que se obtiene al aplicar la función open a la
estructura JSON o de diccionario de datos para que podamos obtener sus claves y valores.

Figura 10. Estructura de archivo JSON.


Fuente: elaboración propia.

Resultado

El resultado obtenido no es más que un diccionario de datos que tiene como valores listas que en su
interior tienen más diccionarios de datos, por lo que, si se tienen conocimientos sobre claves, valores e
índices, se podrá acceder a cualquier valor fácilmente.

Figura 11. Obteniendo valores de un archivo JSON.


Fuente: elaboración propia.

4 Librería JSON [En línea] URL disponible en este enlace.

Una vez expuestos los diferentes elementos de un JSON, se describirá el proceso de escritura de un
diccionario de datos como un JSON. 
1

Figura 12. Nuevos valores de diccionario de datos.


Fuente: elaboración propia.

El primer paso será añadir nuevos campos.


2

Figura 13. Escribir diccionario de datos como JSON.


Fuente: elaboración propia

Una vez se obtienen nuevos campos, se utiliza el siguiente fragmento de código para escribir el
diccionario de datos en un archivo JSON.

with open('Mercados_update.json', 'w') as outfile:

    json.dump(mercados, outfile)
3

Figura 14. Vista JSON sin indent.


Fuente: elaboración propia.

En este caso, además de seleccionar el nombre y utilizar “modo ‘w’” en la función open, se tendrá
que utilizar la función “json.dump” para que tome un diccionario de datos y pueda guardarse
como un JSON. El archivo se guarda de la siguiente manera:
4

Figura 15. Guardar JSON con parámetro indent.


Fuente: elaboración propia.

Se puede observar que se ha guardado en una sola línea todo el JSON. Si se quiere guardar de
una forma más estética, propia de un JSON, se deberá utilizar el argumento indent para que se
generen tabulaciones y saltos de línea internamente.

with open('Mercados_update_ok.json', 'w') as outfile:

     json.dump(mercados, outfile, indent=4)


5

Figura 16. Vista JSON con indent.


Fuente: elaboración propia.

C O NT I NU A R

2.3. Gestión de archivos XML


Los archivos XML [5](extensible markup language) son archivos desarrollados en un lenguaje de marcas
similar a HTML (en algunos aspectos). Cualquier elemento de un archivo XML se escribe entre los
siguientes símbolos: “< >”. Para denotar cuando se cierra una etiqueta, se utiliza la simbología “</ >”. 

Para ilustrar esto, así como las diversas formas de leer y trabajar con la información e un fichero de este
tipo, se utilizará el siguiente XML:

<TuNombre>Juan Manuel</TuNombre>

Un ejemplo completo de archivo XML sería el siguiente:



<?xml version="1.0"?>
<Catalog>
    <Book id="bk101">
      <Author>Garghentini, Davide</Author>
       <Title>XML Developer's Guide</Title>
       <Genre>Computer</Genre>
       <Price>44.95</Price>
       <PublishDate>2000-10-01</PublishDate>
      <Description>An in-depth look at creating applications
       with XML.</Description>
    </Book>
    <Book id="bk102">
       <Author>Garcia, Debra</Author>
       <Title>Midnight Rain</Title>
       <Genre>Fantasy</Genre>
       <Price>5.95</Price>
       <PublishDate>2000-12-16</PublishDate>
       <Description>A former architect battles corporate zombies,
      an evil sorceress, and her own childhood to become queen
      of the world.</Description>
    </Book>
</Catalog>

Figura 17. Ejemplo de XML.


Fuente: elaboración propia.
5 Extensible markup language. [En línea] URL disponible en este enlace.

C O NT I NU A R

Tanto para CSV y JSON se ha hecho uso de la función open para poder procesar archivos y generar objetos
de lectura y escritura. En este caso, es distinto: se necesita una librería tanto como para abrir los XML, como
para procesar su información, existen varias librerías destinadas para tal efecto, en nuestro caso

utilizaremos la librería DOM[6].

import xml.dom.minidom

Figura 18. Librería DOM.
Fuente: elaboración propia.

1 2 3 4

Una vez importada la librería, para abrir un archivo XML hay que parsear el archivo; para ello, hacemos uso
de la función parse sobre el archivo “books.xml” que podrás descargar más abajo. 

Figura 19. Procesando archivo XML (I).


Fuente: elaboración propia.

1 2 3 4

Se obtiene un objeto de la librería DOM que contiene nuestro archivo para ser procesado. El primer paso es
procesar el elemento principal del archivo, que en nuestro caso es < Catalog> … </Catalog>. Para ello,
disponemos de la función “documentElement”, que sirve para ubicar el elemento principal del XML.
Figura 20. Procesando archivo XML (II).
Fuente: elaboración propia.

1 2 3 4

Si atendemos al resultado de la variable “libros_object”, vemos que el objeto DOM reconoce correctamente
el elemento general Catalog. Ahora, lo que tenemos que hacer es seguir procesando los diferentes
elementos. El más próximo en nuestro caso es <Book> … </Book>, es decir: la información de diferentes
libros que tiene almacenado el archivo. En lugar de utilizar “documentElement”, ahora identificaremos a los
diferentes elementos por el nombre de su etiqueta con la función “getElementByTagName”.

Es muy importante ver los resultados que ofrece el objeto elemento DOM, ya que podemos
encontrar dos listas que contienen los dos elementos libros, por lo que, llegados a este punto,
habrá que ir iterando sobre los diferentes subelementos del elemento Book para obtener la
información de forma legible.

Figura 21. Procesando archivo XML (III).


Fuente: elaboración propia.
1 2 3 4

Después, cada elemento Book contiene información que es accesible de la misma manera que se accede
al propio elemento Book, por lo tanto, seguiremos utilizando “getElementByTagName”. En este caso,
trataremos de obtener la información del elemento Author.

Figura 22. Procesando archivo XML (IV).


Fuente: elaboración propia.

1 2 3 4

Como ya no hay más elementos sobre los que iterar, sino que ya queremos acceder directamente al
contenido (por ejemplo, el primer autor: Garghentini, Davide), tenemos que acceder a los elementos de las
listas DOM Element. Cada lista es de longitud uno, pero lo comprobamos a continuación:

Figura 23. Procesando archivo XML (V).


Fuente: elaboración propia.
1 2 3 4

Es decir, las listas son indexables por [0]. Es importante recordar que, en caso de tener más elementos
sobre Author, habría que crear un nuevo bucle for para ir recorriendo estos subelementos. Por lo tanto,
sobre la lista del elemento Author, para acceder al contenido utilizamos la función “.childNodes”, que nos
devolverá una nueva lista.

Figura 24. Procesando archivo XML (VI).


Fuente: elaboración propia.

1 2 3 4
De nuevo, se obtienen dos listas que son de longitud 1, es decir, indexables por [0]. Finalmente, para acceder
al contenido de un nodo hijo, habrá que hacer uso de la función data.
Figura 25. Procesando archivo XML (VII).
Fuente: elaboración propia.

1 2 3 4

Una vez se obtiene la información final sobre los autores, la misma operación es aplicable para el resto de
nodos. En este punto, ya solo se tendría que almacenar la información en listas, diccionarios de datos, etc. y
procesarla.

Figura 26. Procesamiento completo de un archivo XML.


Fuente: elaboración propia.
1 2 3 4

Análogamente, si se realizan estas acciones de forma iterativa, se podría haber utilizado este fragmento de
código, que es equivalente:

Figura 27. Procesamiento completo de un archivo XML, equivalente.


Fuente: elaboración propia.
booksxml.zip
505 B

6 Librería DOM [En línea] URL disponible en este enlace.


Lección 3 de 8

III. Numpy

Los arrays de Numpy 7  son mucho más eficientes que las listas de Python,
especialmente en problemas numéricos. Por lo general, son siempre de un mismo
tipo de dato (salvo en casos especiales). Numpy proporciona operaciones que se
aplican sobre todo el array, al contrario que las listas de Python, que ya hemos
visto que hay que ir iterando sobre cada valor.

Del mismo modo que en las listas en Python, los arrays se indexan de la misma forma, es decir, empezando
de 0 a n.

El tipo de datos cambia. Por lo general, trabajaremos en lugar de int, en int64 (int32 en el caso de tener
instalada una versión de Python de 32 bits). Del mismo modo, trabajaremos en float64 (o float32) en lugar de
float.

 NOTA: Se recomienda seguir todo el contenido junto con el notebook NUMPY.

Descarga del notebook NUMPY.ipynb[MLJM1]


NUMPYipynb.zip
8 KB

Descarga del notebook en formato HTML NUMPY.html[MLJM2]

NUMPYhtlm.zip
52 KB

7[1] Numpy. [En línea] URL disponible en el siguiente enlace.

C O NT I NU A R
1

Figura 28. Ejemplo de Numpy array.


Fuente: elaboración propia.

Para comenzar nuestro aprendizaje con los arrays de Numpy, importaremos la librería Numpy y
crearemos nuestro primer array.

import numpy

arr = numpy.array([10, 20, 98, 34]) 


2

Figura 29. Clase “numpy.ndarray”.


Fuente: elaboración propia.

Algo que se mencionó en pasadas unidades es que, cuando se importa una librería, se están
importando nuevas funcionalidades y también nuevos tipos y clases. En el caso de los arrays,
toman la clase “numpy.ndarray”. 
3

Figura 30. “numpy as np”.


Fuente: elaboración propia.

Un hábito muy extendido dentro de la comunidad de desarrolladores de Python es utilizar alias


para denotar a una librería; de esta forma, se mejora la legibilidad del código. Para Numpy, el alias
que siempre se utiliza es “np”.

import numpy as np

# Creamos de nuevo un array

arr = np.array([23, 42, 58])


4

Figura 31. Tupla como array.


Fuente: elaboración propia.

Se puede verificar que los resultados no cambian en nada, sino que simplemente se ha utilizado
otro nombre para trabajar con la librería Numpy. Respecto al array que hemos creado
anteriormente, hemos utilizado una lista, no obstante, podemos utilizar más tipos de estructuras
de datos. Veamos ahora un array formado por una tupla.

mi_tupla = (1, 58, 63, 45)

arr_tuple = np.array(mi_tupla)
5

Figura 32. Diccionario de datos como array.


Fuente: elaboración propia.

También, aunque con algún cambio previo, se puede transformar un diccionario de datos a un
array. 

my_dict = {'one': 'uno',

           'two': 'dos',

           'three': 'tres'}

dict_list = list(my_dict.items())

arr_dict = np.array(dict_list)

La importancia, en este caso, recae en pasar previamente el diccionario de datos como una lista. 
C O NT I NU A R

3.1. Dimensiones de un array

Una de las características principales de un array es que puede tener n dimensiones. Para conocer el
número de dimensiones de un array, disponemos de la función “ndim”.

Figura 33. Dimensiones de un array.


Fuente: abrir el enlace.
 
1

Primero, se definen algunos arrays.


a = np.array(42)

b = np.array([1, 2, 3, 4, 5])

c = np.array([

    [1, 2, 3], [4, 5, 6]

])

d = np.array([

  [

         [1, 2, 3], [4, 5, 6]

    ], 

  [

         [1, 2, 3], [4, 5, 6]

  ]

])

e = np.array([

  [

         [[1, 2, 3], [4, 5, 6]], 

        [[1, 2, 3], [4, 5, 6]],

         [[1, 2, 3], [4, 5, 6]], 

         [[1, 2, 3], [4, 5, 6]]


  ]

])
2

Figura 34. Diferentes arrays y dimensiones (I).


Fuente: elaboración propia.
3

Posteriormente, se pinta el número de dimensiones.


print(a.ndim)

print(b.ndim)

print(c.ndim)

print(d.ndim)

print(e.ndim)
4

Figura 35. Diferentes arrays y dimensiones (II).


Fuente: elaboración propia.

C O NT I NU A R

3.2. Seleccionar elementos de un array

En esta sección, se muestra cómo seleccionar diferentes elementos de un array. Es necesario recordar que,
a fin de cuentas, cada dimensión de un array es una lista, por lo que podemos emplear los métodos para
indexar listas.
b[0]

c[0]

c[0][2]

d[1]

d[1][0]

d[1][0][2]
Figura 36. Listas y sublistas de un array
Fuente: elaboración propia.

C O NT I NU A R

3.3. Estructura de un array


Además de dimensiones, un array tiene su propia estructura. Esta estructura viene marcada por la longitud
de cada dimensión del array. Para poder conocer la estructura de un Numpy array, utilizamos la función
shape.

print(a.shape) # No tiene dimensiones, solamente es el número 42

 print(b.shape) # Longitud 5 dimensión 1

 print(c.shape) # Longitud 2, cada lista tiene 3 elemento

 print(d.shape) # Longitud 2, cada sub-lista tiene 2 listas, de 3 elementos

 print(e.shape) # Longitud 1, 

                # dentro de esta lista hay 4 sub-listas, 

                # cada sub-lista tiene 2 listas, 

                # de 3 elementos
Figura 37. Estructura de un array.
Fuente: elaboración propia.

C O NT I NU A R

3.4. Índices de un array y slices de un array


Teniendo en cuenta que cada elemento de un array es una lista, resulta lógico que los arrays y las listas
comparten la misma forma de indexar. Cuando se indexan arrays para separar solo una parte de este, se
realiza una operación que se conoce como slice de un array. 

Para esta sección creamos un array a través de la función arange, que nos permite generar un array

en función del rango de valores que le pasemos como parámetro. Si no especificamos un rango, generará
una secuencia.
my_array = np.arange(11)

my_array

Figura 38. Generación de arrays con arange.


Fuente: elaboración propia.
A continuación, mostraremos varios ejemplos de indexación y slicing.
1

Mostrar de posición n a m.

Figura 39. Array de n a m.
Fuente: elaboración propia.

my_array[0:3] # De posición 0 a 3

my_array[2:7] # De posición 2 a 7
2

Mostrar de inicio a posición n.

Figura 40. Array de inicio a m.


Fuente: elaboración propia.

my_array[:6] # De inicio a 6
3

Mostrar de posición n a final del array.

Figura 41. Array de n a fin.


Fuente: elaboración propia.

my_array[6:] # De 6 a final
4

Mostrar de posición n en función de m secuencias.

Figura 42. De n a m en secuencias de x elementos.


Fuente: elaboración propia.

Mostrar desde la posición n a la posición m del array, en función del número de elementos. Por
ejemplo, como se ve en la figura 42, se toma un slice de un array desde un inicio hasta el final en
secuencias de tres en tres elementos.

my_array[:9:3] # De inicio a 9 de tres en tres elementos

my_array[6::2] # De 6 a fin de dos en dos elementos


5

Indexación negativa.

Figura 43. Indexación negativa.


Fuente: elaboración propia.

my_array[-2] # Posición 2 empezando por el final

my_array[:-3] # De inicio hasta el elemento -3 del array


6

Mostrar array de forma inversa.

Figura 44. Array reverso.


Fuente: elaboración propia.

my_array[::-1] # Array reverso

my_array[::-2] # De fin (reverso) a inicio tomados de 2 en 2

C O NT I NU A R

3.5. Manipulando dimensiones de un array


Los arrays no son de estructura fija, ya que, tanto en el momento de creación del array como sobre un array
ya existente, se puede definir la estructura del mismo. Esto se consigue con la función reshape. 

 Es importante tener en cuenta que el elemento más interior de la estructura del array
debe ser divisible por su nueva estructura.
1

Figura 45. Reestructuración de un array.


Fuente: elaboración propia.

new_array = np.arange(36).reshape(2,3,6)

new_array
2

Figura 46. Reestructuración de un array existente.


Fuente: elaboración propia.

new_dims = e.reshape(2,2,6)

new_dims
3

Figura 47. Crear arrays planos.


Fuente: elaboración propia.

Lo contrario de reestructurar un array es disolver todas sus dimensiones dejando un array plano;
para ello, existen las funciones ravel y flatten.

new_dims.ravel()

new_dims.flatten()

Principal diferencia

La principal diferencia entre los dos es que flaten devuelve una copia y ravel devuelve una vista, es decir: si
hacemos un cambio en el array original, se verá reflejado en la variable asignada a ravel.
Importante

Es importante recordar que los arrays son mutables, es decir, si no se realiza una copia correctamente, los
dos arrays compartirán las mismas posiciones de memoria.

C O NT I NU A R

3.6. Apilar (stacking) arrays


Al igual que con otras estructuras de datos, también es posible concatenar o apilar arrays. Esta operación
puede ser realizada con base en los ejes de los arrays. Tomaremos como referencia los siguientes arrays: 

pares = np.array([

    [0, 2, 4],

    [6, 8, 10],

    [12, 14, 16]

])

impares = np.array([

    [1, 3, 5],

    [7, 9, 11],
    [13, 15, 17]

])

Figura 48. Definición de arrays para stacking.


Fuente: elaboración propia.

Las formas en que se puede concatener un array son:

HO R I Z O N TA L VER TI C A L C O N C AT E N AT E PR O F UN DI DA D

np.hstack((pares, impares)) # Apila los arrays en referencia a la la longitud 3

Figura 49. Stacking horizontal.


Fuente: elaboración propia.
HO R I Z O N TA L VER TI C A L C O N C AT E N AT E PR O F UN DI DA D

np.vstack((pares, impares)) # Apila los arrays en referencia al número de elementos.

Figura 50. Stacking vertical.


Fuente: elaboración propia.

HO R I Z O N TA L VER TI C A L C O N C AT E N AT E PR O F UN DI DA D
Existe una función equivalente tanto a “vstack” como a “hstack”, que es concatenate. El funcionamiento de
este comando está marcado por el sentido de los ejes (axis), donde 0 será de forma vertical y 1 de forma
horizontal.

Figura 51. Función concatenate.


Fuente: elaboración propia.

HO R I Z O N TA L VER TI C A L C O N C AT E N AT E PR O F UN DI DA D

En profundidad (este tipo de unión se realiza elemento a elemento de los arrays).


 
np.dstack((pares, impares))

Figura 52. Función “dstack”.


Fuente: elaboración propia.
C O NT I NU A R

3.7. Dividir (spliting) arrays


Los arrays pueden concatenarse y también dividirse (spliting) de una forma muy similar al stacking, es decir,
de forma horizontal, vertical y en profundidad. 

 A diferencia de las funciones para hacer stacking, el spliting necesita también que se
especifique el número de subarrays que quieren obtenerse. Este parámetro debe ser
divisible entre la longitud de los elementos del array. Tampoco puede ser mayor que
la longitud de elementos en el array.
S PLI T E N
S PLI T HO R I Z O N TA L S PLI T V E R T I C A L N UM PY. S PLI T
PR O F UN DI DA D

np.hsplit(pares, 3)

Figura 53. Función “hsplit”.


Fuente: elaboración propia.

S PLI T E N
S PLI T HO R I Z O N TA L S PLI T V E R T I C A L N UM PY. S PLI T
PR O F UN DI DA D

np.vsplit(pares, 3)

Figura 54. Función “vsplit”.


Fuente: elaboración propia.
S PLI T E N
S PLI T HO R I Z O N TA L S PLI T V E R T I C A L N UM PY. S PLI T
PR O F UN DI DA D

De forma equivalente a “hsplit” y “vsplit”, podemos utilizar la función “numpy.split”, que necesita tanto el
número de subarrays como el eje sobre el que dividir.

Figura 55. Función split.


Fuente: elaboración propia.

S PLI T E N
S PLI T HO R I Z O N TA L S PLI T V E R T I C A L N UM PY. S PLI T
PR O F UN DI DA D

Este tipo de split requiere que la dimensión del array sea de tres como mínimo.
 
big = np.arange(27).reshape(3, 3, 3)
np.dsplit(big, 3)
Figura 56. Función split.
Fuente: elaboración propia.

C O NT I NU A R

3.8. Atributos de un array

Número de dimensiones de un array “ndim”



big.ndim 
Figura 57. Función “ndim”.
Fuente: elaboración propia.

Número de elementos de un array “size”



big.size

Figura 58. Función “size”.


Fuente: elaboración propia.

Espacio que ocupa en bytes cada elemento de un array “itemsize”



big.itemsize

Figura 59. Función “itemsize”.


Fuente: elaboración propia.

Tamaño total en bytes del array “nbytes”



big.nbytes

Figura 60. Función “nbytes”.


Fuente: elaboración propia.

Transpuesta del array “T”



big.T

Figura 61. Función transpuesta.


Fuente: elaboración propia.
C O NT I NU A R

3.9 Convertir arrays


Es posible extraer slices del array o, simplemente, todo el array para obtener listas o modificar el tipo del
array. En este caso, utilizaremos dos funciones para realizar conversiones sobre el array. 
1

“Tolist”

Figura 62. Función tolist.


Fuente: Elaboración propia

Convierte a lista el array o un slice.


2

“Astype”

Figura 63. Función “astype”.


Fuente: elaboración propia

Convierte el tipo completo del array

C O NT I NU A R
3.10. Copia y vista de un array
Es importante mencionar que, al igual que las listas, los arrays comparten posiciones en la memoria física,
por lo tanto, si no utilizamos los comandos necesarios para realizar una copia de un array correctamente, los
cambios que hagamos en el “array_a” se verán reflejados en el “array_b”.

Ejemplo básico

Se expone el ejemplo más básico: hacer una copia de un array y asignarlo a una nueva variable.

# Definimos un array con elementos del 2 hasta 20


arr = np.arange(2, 20)
# Asignamos las dos últimas posiciones a la variable b
b = arr[-2:]
b
# Asignamos todas las posiciones del array b a cero.
b[::] = 0
b
# Los cambios se reflejan en nuestra variable arr
Arr

Figura 64. Copia de un array (I).


Fuente: elaboración propia.
Otro ejemplo

Otro ejemplo similar: obtener las primeras cinco posiciones del array. Serán asignadas a otra variable, se
les dará valor 100 y se verá que estos cambios aparecen reflejados en nuestro array original

array_dos = np.arange(0, 31)


c = array_dos[0:5]
c[::] = 100
array_dos

 
Figura 65. Copia de un array (II).
Fuente: elaboración propia.
Ejemplo con función view (I)

En los dos ejemplos anteriores, se ve que los arrays hay sufrido cambios producidos en los arrays copia.
Algo similar sucede si se utiliza la función view. Su uso se aconseja para mostrar arrays, pero no para
realizar cambios sobre los mismos.

array_1 = np.array([[10,10], [2,3], [4,5]]) 


array_dos = array_1.view()
array_dos[0] = [10000, 3]
array_dos
array_1
 
Figura 66. Comando view (I).
Fuente: elaboración propia.
Ejemplo con función view (II)

Figura 67. Comando view (II).
Fuente: elaboración propia.
Ejemplo con función view (III)

Figura 68. Comando view (III).
Fuente: elaboración propia.

Ejemplo con el comando copy



Para evitar que esto ocurra, si realmente se quiere obtener una copia de un array para su posterior
procesamiento o modificación, lo mejor es copiar el array con el comando copy:
array_copiado = array_1.copy()
array_1[1] = [2200, 34]
array_1
array_copiado

Figura 69. Comando copy.


Fuente: elaboración propia.

C O NT I NU A R

3.11. Operaciones sobre arrays


Existen varias operaciones que se pueden realizar sobre arrays. Es importante enfatizar en la importancia de
saber sobre qué eje de los arrays queremos realizar la suma:
Suma de todo el array o por sus ejes sum (I)

e = np.array([[[1, 0], [0, 0]],
               [[1, 1], [1, 0]],
               [[1, 0], [0, 1]]]
             )
e.sum(axis = 0)
e.sum(axis=1)

Figura 70. Comando Numpy “sum” (I).


Fuente: elaboración propia.

Suma de todo el array o por sus ejes sum (II)



Figura 71. Comando Numpy sum (II).
Fuente: elaboración propia.
Generar un array con valores arbitrarios empty

nothing = np.empty(10)
nothing

Figura 72. Comando empty.


Fuente: elaboración propia

Generar un array de unos o ceros (ones, zeros)



ones = np.ones(5)
ones
zeros = np.zeros(5)
zeros

Figura 73. Comando ones y zeros.


Fuente: elaboración propia.
Generar números aleatorios función random (I)

Existe una gran cantidad de números aleatorios que pueden realizarse con base en distribuciones
estadísticas. Todas ellas pueden consultarse en el siguiente enlace: https://docs.scipy.org/doc/numpy-
1.15.0/reference/routines.random.html

rand = np.random.rand(10)
randn = np.random.rand(10)
randint = np.random.randint(20, 100, 10)
random = np.random.random(10)
beta = np.random.beta(0.2, 0.5, 10)
binomial = np.random.binomial(10, 0.5, 10)
gamma = np.random.gamma(0.25, 0.3, 10)

Figura 74. Distribuciones aleatorias (I).


Fuente: elaboración propia.
Generar números aleatorios función random (II)

Figura 75. Distribuciones aleatorias (II).
Fuente: elaboración propia.

Redondear todos los elementos de un array round



gamma.round(2)

Figura 76. Función round.


Fuente: elaboración propia.

Rellenar n elementos de un array fill.



zero_array = np.zeros(20)
zero_array[5:15].fill(5)
zero_array

Figura 77. Función fill.


Fuente: elaboración propia.

Media del array o por sus ejes mean



e.mean(axis = 0)
e.mean(axis = 1)
e.mean()

Figura 78. Función mean.


Fuente: Elaboración propia.
Producto de arrays dot

e.dot(d)

Figura 79. Función dot.


Fuente: elaboración propia.
Valor mínimo de un array min

aux = np.array([
    [1, 100, 5],
    [2, 4, 0]
])
aux.min()
aux.min(axis=0)
aux.min(axis=1)

Figura 80. Función min.


Fuente: elaboración propia.
Valor máximo de un array max

print(aux.max())
print(aux.max(axis=0))
print(aux.max(axis=1))

Figura 81.  Función max.


Fuente: elaboración propia.

Posición de índice con el valor mínimo de un array “argmin”



aux.argmin() # Devuelve 5

Figura 82.  Función “argmin”.


Fuente: elaboración propia.

Posición de índice con el valor máximo de un array “argmax”



aux.argmax() # Devuelve 1

Figura 83.  Función “argmax”.


Fuente: elaboración propia.

Ordenar valores de un array sort



aux.sort()
aux

Figura 84.  Función sort.


Fuente: elaboración propia.
Lección 4 de 8

IV. Pandas

Actualmente, una de las librerías más utilizada por los científicos de datos es Pandas[8], cuyo nombre
proviene de panel data, de manera que simula las estructuras de múltiples dimensiones que se utilizan en
econometría. Es una librería que nos permite realizar prácticamente cualquier tipo de transformación sobre
nuestros datos.

Las principales estructuras de datos con las que se puede trabajar en esta librería son series y dataframes.

Lo primero de todo, tanto para obtener un objeto series o dataframe,


habrá que importar los datos y cargarlos como una serie o
dataframe. No obstante, también se puede generar un dataframe
desde cero. 

En primer lugar, se importará la librería Pandas utilizando el alias extendido.

 “pd”.import pandas as pd

 Se recomienda seguir todo el contenido junto con el notebook PANDAS.


Descarga del notebook PANDAS.ipynb[MLJM1] 

PANDASipynb.zip
813.4 KB

Descarga del notebook en formato HTML PANDAS.html[MLJM1] 

PANDAShtml.zip
851.1 KB

8 Pandas [En línea] Url disponible en este enlace. 

C O NT I NU A R

4.1. Series
Se trata de una colección indexada que funciona de un modo similar a un diccionario de datos. Es la unidad
mínima con la que podemos trabajar en Pandas, de hecho, un dataframe no es más que una sucesión de
series.

Debemos tener en cuenta que:


1

Las series funcionan de forma similar a un diccionario de datos donde tenemos los archivos
formados por {clave_1: 'valor uno', clave_2. 'valor dos', ....., clave_n: 'valor m'}. 
2

Las series pueden formarse a través de un array de Numpy o una lista y unos valores que
actuarán como índices (si no se introducen, se tomarán por defecto de 0 a la longitud del
conjunto de elementos). 

Figura 85.  Definición de una serie.


Fuente: elaboración propia.

criptos = pd.Series(
 [5973.55, 13.85, 0.1575, 0.96, 215.29],
index= ['Bitcoin', 'Ethereum', 'XRP', 'Tether', 'BTC Cash']
)

criptos

Las series también tienen su propio tipo: (pandas.core.series.Series)

Figura 86.  Clase series.


Fuente: elaboración propia.

type(criptos) # Clase Series

C O NT I NU E

4.2. Dataframes
 Los dataframes son el resultado de unir una o más series. Funcionan de forma
similar a una matriz (salvo por el tipo de dato), una base de datos relacional o una
hoja de cálculo, es decir: son indexables por filas y columnas.

Función principal

Su función principal es que nos permiten pasar prácticamente cualquier tipo de variable como arrays, listas,
diccionarios, etc. Es: pandas.DataFrame.

Obtener un dataframe con objeto series



Podemos utilizar nuestro objeto series creado anteriormente para obtener un dataframe.

# Creamos un Dataframe a través del objeto Series


df_criptos = pd.DataFrame(criptos)
 
# Vemos que por defecto, se genera una columna con nombre 0, 
# ya que no se lo hemos especificado.
df_criptos

Figura 87.  De serie a dataframe.


Fuente: elaboración propia.
Obtener un dataframe desde un array

De la misma forma, podemos obtener un dataframe desde un array.
 
# Ejemplo 2 a través numpy array
import numpy as np
# Creamos un array de 5 número aleatorios
array_uno = np.random.rand(5)
pd.DataFrame(array_uno)

Figura 88.  De array a dataframe.


Fuente: elaboración propia.
Obtener un dataframe a través de listas

Hay que destacar en el ejemplo anterior que, al no utilizar ningún parámetro como índice, automáticamente
ha tomado valores de 0 a n. Vemos en el siguiente ejemplo cómo obtener un dataframe a través de listas:

# Ejemplo 3 listas
# Creamos una lista
lista = ['hola mundo', 1, 3.14, 'adios']
# Pasamos la lista a un DataFrame
df_list = pd.DataFrame(lista)
df_list

Como podemos ver, un dataframe acepta todo tipo de variables. 


Figura 89.  De lista a dataframe.
Fuente: elaboración propia
Obtener un dataframe desde un diccionario de datos

Finalmente, podemos obtener un dataframe desde un diccionario de datos:
 
# Ejemplo 4 Diccionario de datos
# Creamos un Diccionario de datos
dict_cli = {'ID001': 'Cliente uno',
            'ID002': 'Cliente dos',
             'ID003': 'Cliente tres',
             'ID004': 'Cliente cuatro',
             'ID005': 'Cliente cinco'}
dict_cli
# Pasamos el dict a un DataFrame
df_dict = pd.DataFrame.from_dict(dict_cli, orient='index')
df_dict
 
Nótese que, cuando se trata de un diccionario de datos, hay que utilizar el parámetro orient para que
reconozca correctamente el campo clave como índice.

Figura 90.  De diccionario de datos a dataframe.


Fuente: elaboración propia.
Tal y como hemos visto con las series, un dataframe también tiene su propio de clase:

(pandas.core.frame.DataFrame)

Figura 91. Clase de un dataframe.


Fuente: elaboración propia.

C O NT I NU A R
4.3. Cargando archivos a través de un CSV
Una de las grandes ventajas que supone trabajar con dataframes es que podemos cargar archivos muy
fácilmente y procesar sus filas y columnas. Hay varios tipos de datos que podemos cargar a Pandas: CSV,
JSON, HTML, EXCEL, HDF5, TXT, ORC, STATA, etc.

Todos los tipos de datos que podemos cargar se encuentran en este link.

A lo largo de esta sección, se mostrarán las principales funcionalidades de Pandas a través de un archivo
CSV cargado como dataframe. Para cargar un CSV como un dataframe, se dispone de la función “read_csv”.
Se requiere previa descarga del siguiente dataset, que contiene información sobre datos inmobiliarios de
California[9]:

Figura 92.  Vista de un Pandas dataframe.


Fuente: elaboración propia.

Con solamente una línea de código, se puede disponer de un dataframe totalmente operativo para realizar
cualquier tipo de transformación sobre el mismo. Si observamos la propia estructura del dataframe, vemos
que nos muestra el nombre de todas las columnas. 
1

A la izquierda del mismo, podemos ver el índice del dataframe. En este caso va de 0 a 20639 filas
(sin contar la cabecera).
2

Abajo podremos ver el número de filas totales (contando la cabecera) y el número de columnas.

1 Es dataset es externo a la librería Pandas. Toda la información se encuentra disponible en

este enlace.

C O NT I NU A R

4.4. Obtención de series y columnas de un dataframe


Tal y como hemos visto antes, un dataframe es una sucesión o colección de series, es decir: cada columna
actúa como una serie, ya que todas las columnas comparten el mismo índice. 
1

Figura 93. Vista de una columna de un dataframe.


Fuente: elaboración propia.

Para acceder a una columna, se debe escribir entre corchetes el nombre de la misma.

houses['housing_median_age']
2

Figura 94. Clase de una columna de un dataframe.


Fuente: elaboración propia.

Si atendemos al tipo de clase que tiene una columna, veremos que es Series

type(houses['housing_median_age'])
3

Figura 95. Vista dos, columna de un dataframe.


Fuente: elaboración propia.

Otra forma de acceder a las columnas de un dataframe es nombre_data_frame.nombre_columna,


es decir sin corchetes y sin la estructura de un string.

houses.housing_median_age

C O NT I NU A R
4.5. Selección de múltiples columnas de un dataframe
Una vez determinado que un dataframe se compone de series, se procederá a explicar cómo
seleccionar varias columnas. 
1

Para ello, simplemente se deben encerrar entre corchetes los nombres de las columnas que se
quieran seleccionar, como:

nombre_df[['columna_uno', 'columna_dos', 'columna_tres']]

Análogamente, se podrá pasar una lista con nombres de las columnas.


2

Para hacer lo mismo mediante indexación, es decir, obtener un subconjunto de columnas del
dataframe por la posición que ocupan las columnas, podemos hacer:

nombre_dataframe[nombre_dataframe.columns[[col_n, col_m]]]
3

También a través de la función “iloc”, que permite seleccionar tanto filas como columnas, donde
las filas serán el primer elemento entre corchetes y las filas el segundo [filas, columnas]:

nombre_dataframe.iloc[:, [col_n, col_m]]


4

Mediante columnas (I)

Figura 96. Indexación por columnas.


Fuente: elaboración propia.

houses[['housing_median_age', 'total_bedrooms']]
5

Mediante columnas (II)

Figura 97. Indexación por columnas (II).


Fuente: elaboración propia.

target = ['housing_median_age', 'total_bedrooms', 'population']

houses[target]

 
6

Mediante índices

Figura 98. Selección de columnas por índices.


Fuente: elaboración propia.

Es necesario utilizar el atributo de los “dataframes .column”:

houses.columns[1]

houses.columns[0: 4]

houses[houses.columns[2:6]]
 Anteriormente, se ha visto el uso de la función “.iloc”. Es importante saber cómo se
distribuye un dataframe de manera estructural en cuanto a sus filas y columnas,
pues, como se mostrará a continuación, un dataframe se puede indexar tanto por
sus filas como por sus columnas.

E S T R UC T UR A E JE M PLO

En cuanto a la estructura de un dataframe, será la siguiente: 

dataframe[filas, columnas]: tanto las filas como las columnas son indexables.

E S T R UC T UR A E JE M PLO

En el siguiente ejemplo, se seleccionarán todas las filas (para seleccionar todas las filas o todas las
columnas se utiliza el operador “:”) y las columnas uno y tres:
 
houses.iloc[:,[1,3]]

Figura 99.  Selección de columnas mediante “.iloc”.


Fuente: elaboración propia.
 
C O NT I NU A R

4.6. Selección de múltiples filas de un dataframe


Para seleccionar múltiples filas, se procederá de forma similar a las listas, no así para seleccionar
una única fila, que tendrá un proceso diferente: 
1

Para seleccionar desde la primera fila hasta un límite se realiza dataframe[0:n]; análogamente, se
puede omitir el cero y realizar simplemente dataframe[ : n], 
2

Para seleccionar desde una fila hasta el final, se realiza: dataframe[n: ]


3

Para seleccionar un rango definido de las filas, se realiza: dataframe[n : m]

# Seleccionamos de la fila 0 a la 2 houses[0:2]



Figura 100.  Selección de fila n a m.
Fuente: elaboración propia.

# Vemos que es lo mismo si quitamos el cero. houses[:2]



Figura 101.  Selección de fila de inicio a m.
Fuente: elaboración propia.

# Seleccionamos de fila n al final houses[20635:]



Figura 102.  Selección de fila m a fin.
Fuente: elaboración propia.

# Rango personalizado, escogemos de fila 150 a 200 houses[150:200]



Figura 103.  Selección de fila n a m rango personalizado.
Fuente: elaboración propia.

Para seleccionar una sola fila, no se puede hacer la misma operación que en las listas, indexar una única
posición lista[n], ya que esto no nos devuelve nada; para ello, tenemos que seleccionar como un rango
personalizado la fila que queremos mostrar más una posición dataframe[n:n+1]
Figura 104.  Selección de una fila.
Fuente: elaboración propia.

houses[1000:1000]houses[1000:1001]

C O NT I NU A R

4.7. Función “.iloc”


Del mismo modo que acabamos de ver cómo seleccionar varias filas y columnas, es importante también
mostrar cómo realizar todas estas operaciones a través de la función “.iloc”. 

Operaciones de selección e indexación de filas y columnas



De forma resumida, podemos realizar las siguientes operaciones de selección e indexación de filas y
columnas:
Dataframe.iloc[0] – Primera fila de un dataframe.

Dataframe.iloc[1] – Segunda fila de un dataframe.

Dataframe.iloc[-1] – Última fila de un dataframe.

Dataframe.iloc[[n]] – Fila n de un dataframe.

Dataframe.iloc[n:m] – Rango personalizado de filas n a m.

Dataframe.iloc[: , 0] – Primera columna de un dataframe.

Dataframe.iloc[:, 1] – Segunda columna de un dataframe.

Dataframe.iloc[: , -1] – Última columna de un dataframe.

Dataframe.iloc[: , [n,m]] – Filas n y m de un dataframe.

Dataframe.iloc[: , n:m] – Rango personalizado de las columnas n a m de un dataframe.


Mostramos algunos ejemplos: 
1

Figura 105. Selección múltiple de filas y columnas con listas.


Fuente: elaboración propia.

houses.iloc[[20,5680,19875], [3, 5]] # Selección de filas 20, 5680, 19875 y columnas 3 y 5 


2

Figura 106. Selección múltiple de filas y columnas con rangos.


Fuente: elaboración propia.

houses.iloc[0:10, 0:3] 

C O NT I NU A R
4.8. Índices de un dataframe
Un índice es un identificador de cada fila; todos los elementos de una fila comparten el mismo índice. Los
índices por defecto, son de 0 a la longitud total del dataframe. 
Creamos un nuevo dataframe:
1

# Creamos un dataframe

ventas = {

'region': ["EUROPA", "EUROPA", "EUROPA",

"USA", "USA", "USA", "LATAM", "LATAM"],

'ventas':[153752, 168742, 162587, 256198, 285743, 290371, 145638, 151678],

'anio':[2018, 2019, 2020, 2018, 2019, 2020, 2018, 2019]

df = pd.DataFrame(ventas)
2

Figura 107. Definición de un dataframe.


Fuente: elaboración propia.

Para observar el índice de un dataframe, podemos hacer uso de su atributo index.

df.index 

 
Figura 108.  Índice de un dataframe.
Fuente: elaboración propia.

Dependiendo de cómo estén formados los datos, se podrán crear multiíndices basados en columnas
propias del dataframe. Las columnas region y year tienen elementos repetidos. Esto permitirá hacer
multiíndices donde se tenga un continente por año de ventas. 

Función “set_index” (I)



Con la función “set_index” se podrá establecer un nuevo índice. 

Figura 109. Definición de un multiíndice.


Fuente: elaboración propia.
Función “set_index” (II)

En vista del nuevo dataframe, podemos ver que ahora las columnas region y year actúan como índice. Si
consultamos la primera fila: 

region_year.iloc[0]

Figura 110.  Búsqueda de valores en dataframe multiíndice.


Fuente: elaboración propia.

Función “set_index” (III)



Obtenemos el dato que pertenece al volumen de ventas. Region (Europe) y year (2018) son sus índices.
Del mismo modo, podemos pasar una lista como índice a un dataframe. Obviamente, esta lista debe ser de
la misma longitud que el dataframe.

indice = ['REGISTRO_1', 'REGISTRO_2', 'REGISTRO_3', 'REGISTRO_4',


'REGISTRO_5', 'REGISTRO_6', 'REGISTRO_7', 'REGISTRO_8']
df.index = indice
df

Figura 111.  Nuevo índice de un dataframe.


Fuente: elaboración propia.

Función loc

Con la función loc podemos buscar elementos en el índice.

df.loc['REGISTRO_6']

Figura 112. Función loc.


Fuente: elaboración propia.
C O NT I NU A R

4.9. Funciones básicas de un dataframe


A continuación, se presenta un listado de algunas de las principales funciones que podemos
aplicar en un dataframe para operar en sus columnas: 
1

Obtener las primeras filas de un dataframe con “.head”. 


2

Obtener las últimas filas de un dataframe con “.tail”. 


3

Obtener los elementos únicos de una columna de un dataframe con “.unique”.


4

Obtener un resumen estadístico del dataset con “.describe”.


5

Obtener la media de una columna con “.mean”.


6

Obtener una copia de un dataframe con “.copy”.


7

Ver los nombres de las columnas de un dataframe con “.columns”.


8

Obtener la correlación entre todas las variables numéricas con “.corr”.


9

Borrar duplicados de un dataframe con “.drop_duplicates”.


10

Especialmente para big data sets, se puede ver el consumo en memoria RAM de nuestro dataset
con “.memory_usage”.
11

Ver un resumen gráfico (basado en densidad, scatter plots y gráficas de correlaciones) de todas
las variables del dataframe con “.scatter_matrix”.
12

Obtener un histograma de cada variable numérica del dataset con “.hist”.

Primeras filas de un dataframe (I)


# Primeras filas del dataframe


houses.head()

Figura 113.  Función head (I).


Fuente: elaboración propia.
Primeras filas de un dataframe (II)

Si en “.head()” no especificamos nada, por defecto se muestran cinco. Podemos especificar el número de
filas a mostrar. 

Figura 114.  Función head (II).


Fuente: elaboración propia.
Últimas filas de un dataframe

houses.tail()

Lo mismo pasa con el comando tail: si no le pasamos como parámetro el número de filas a visualizar,
tomará las últimas cinco.  

Figura 115.  Función tail.


Fuente: elaboración propia.
Valores únicos por columna

# Observamos los valores únicos de la columna
houses['ocean_proximity'].unique()
houses['latitude'].unique()

Como podemos comprobar, unique es una función que tiene un mayor impacto en variables categóricas.
Por lo general, las variables numéricas tienen demasiados valores diferentes y no es interesante su estudio
desde el punto de vista de valores únicos.

Figura 116.  Función unique.


Fuente: elaboración propia.
Resumen estadístico

# Resumen estadístico.
houses.describe()

Vemos que la función describe nos muestra un resumen estadístico solo de las variables numéricas.
Muestra información sobre el número de filas, media, desviación estándar, valor mínimo, máximo e
información referente a sus cuartiles.

Figura 117. Función describe.


Fuente: elaboración propia.
Media de una columna

Si aplicamos la función mean a una columna, nos mostrará su media.
houses['total_rooms'].mean()

Figura 118.  Función mean.


Fuente: elaboración propia.

Copia de un dataframe

Al igual que en listas y arrays, los dataframes comparten memoria. Es fácil equivocarnos y asignar a una
nueva variable un dataframe completo. Posteriormente, en esta nueva variable se realizan modificaciones
teniendo en cuenta que solamente se están realizando en la copia del dataframe.
No obstante, esto no es verdad, dado que se están realizando modificaciones en ambos dataframes ya que,
al estar almacenados en memoria, comparten las mismas posiciones.

A continuación, se muestra un ejemplo de cómo no copiar un dataframe:

bad_copy = houses
# Modificamos la primera fila por ceros
bad_copy.iloc[[0]] = np.zeros(len(houses.columns))
bad_copy.head(3)
Observamos que los cambios se reflejan en el dataframe original.
houses.head(2)

Figura 119.  Copia de un dataframe erróneo.


Fuente: elaboración propia.
Copia de un dataframe (II)

Por lo tanto, se han modificado ambos dataframes. Para únicamente realizar modificaciones sobre la
copia, hemos de hacer uso del comando copy.

houses = pd.read_csv('housing_California.csv')
# Copiamos correctamente el dataframe
df_copia = houses.copy()
df_copia.iloc[[0]] = np.zeros(len(houses.columns))
df_copia.head(2)
houses.head(2)

Figura 120. Copia de un dataframe.


Fuente: elaboración propia.
Correlaciones de variables numéricas

houses.corr()

Simplemente, se ha de utilizar la función “corr”. Automáticamente, mostrará una matriz de correlación


sobre las variables numéricas y dejará otras variables categóricas o carácter fuera de la matriz.

 
Figura 121 Matriz de correlación de un dataframe.
Fuente: elaboración propia.
Nombres de las columnas de un dataframe

Con la función columns podemos acceder a los nombres de las columnas. Devuelve el resultado en forma
de lista. Esto permitirá poder utilizar cualquier función ya conocida sobre el manejo de listas para trabajar
con los nombres de las columnas de un dataframe.

Figura 122. Nombres de las columnas de un dataframe.


Fuente: elaboración propia.

Borrar duplicados de un dataframe (I)



Una de las tareas más realizadas en ciencia de datos es la de gestionar la duplicidad de datos; para ello, en
Pandas disponemos de la función “drop_duplicates”.
Primero, haremos una copia de las primeras 10 filas del dataframe para poder ver los cambios
correctamente y duplicaremos la fila nueve.

# Para verlo más claro, vamos a realizar una copia de las diez primeras posiciones del dataframe
ten_rows = houses.head(10).copy()
# Duplicamos la fila 9
ten_rows = ten_rows.append(ten_rows.iloc[[9]])
ten_rows = ten_rows.append(ten_rows.iloc[[9]])

Figura 123. Filas duplicadas.


Fuente: elaboración propia.
Borrar duplicados de un dataframe (II)

Observamos que se ha duplicado la fila nueve. Con la función “drop_duplicates” podemos borrar los
duplicados de un dataframe (borra toda la fila). Es importante atender al parámetro keep, que nos dará la
opción de mantener la primera ocurrencia (first) o la última (last).

ten_rows = ten_rows.drop_duplicates(inplace = False, keep = 'first')


ten_rows
 
Figura 124. Dataframe sin duplicados.
Fuente: elaboración propia.
Uso de RAM de un dataframe

Mediante la función “memory_usage” se puede observar la cantidad de memoria RAM (en bytes) que
necesita cada columna del dataframe.

# Consumo RAM del dataframe en BYTES


houses.memory_usage()

Figura 125. Uso de memoria RAM por columna.


Fuente: elaboración propia.
Análisis gráfico – Scatter Matrix

Pandas también dispone de algunas funciones de visualización de datos sobre un dataframe. Una de ellas
es “scatter_matrix”. Para poder aplicar esta función, habrá que importar una funcionalidad de Pandas para
visualización, que es plotting.

# Configuración para mostrar gráficas en notebook


%pylab
%matplotlib inline
%config InlineBackend.figure_format = 'retina'
# Importamos scatter_matrix
from pandas.plotting import scatter_matrix
# Es necesario que configuremos el tamaño de las gráficas que será el mismo que el número de
columnas
scatter_matrix(houses, figsize = (len(houses.columns),
                                  len(houses.columns)),
               diagonal = 'kde');

Gracias a este tipo de visualizaciones podemos estudiar algunas correlaciones, la distribución que siguen
las variables y sus diagramas de densidad. 

Figura 126. Matriz de visualización de un dataframe.


Fuente: elaboración propia.
Histogramas de variables

Se puede obtener un histograma de cada variable sin necesidad del paquete plotting. Tan solo es necesaria
la función hist.

# Histogramas de cada variable continua del dataframe.


houses.hist(figsize = (len(houses.columns), len(houses.columns)))

Figura 127. Histogramas de un dataframe.


Fuente: elaboración propia.
C O NT I NU A R

4.10. Agrupación de dataframes


Una opción muy útil es poder realizar la librería Pandas es poder realizar agrupaciones de columnas de un
dataframe con base en campos clave, de un modo similar a SQL. Para obtener estas agrupaciones, al igual
que en SQL, se utiliza la función “groupby”.

 Es importante estudiar la documentación de esta función, disponible en este enlace.

E JE M PLO 1 E JE M PLO 2 E JE M PLO 3


J O J O J O 3

En este ejemplo, se muestra una agrupación de columnas por la media (AVG en SQL).
# Agrupamos por la media de los valores numéricos para la columna ocean_proximity
houses.groupby(['ocean_proximity']).mean()

Figura 128. “Groupby” por media.


Fuente: elaboración propia.

E JE M PLO 1 E JE M PLO 2 E JE M PLO 3

En el siguiente ejemplo, se muestra una agrupación de columnas por su frecuencia.


# Observamos cuántos tipos el total de dormitorios en función de
# su frecuencia.
houses.groupby(['total_bedrooms']).count()

Figura 129. Groupby por frecuencia.


Fuente: Elaboración propia.
E JE M PLO 1 E JE M PLO 2 E JE M PLO 3

También podemos mostrar solamente una columna:


houses.groupby(['total_bedrooms']).count()['ocean_proximity']

Figura 130. “Groupby” por frecuencia, solo una columna.


Fuente: elaboración propia.
Otra función similar a “groupby” es mostrar de forma porcentual la cantidad de un valor en todo el dataframe.
Esto es interesante cuando estamos estudiando la cantidad de etiquetas de una variable categórica.
También, observar cómo de balanceado está un dataset con base en una variable objetivo. Para ello,
utilizamos la función “crosstab”. 

Figura 131. “Crosstab”.
Fuente: elaboración propia.

# Obtener el porcentaje de valores para una variable categórica


print((pd.crosstab(index=houses["ocean_proximity"], columns="count"))/len(houses) * 100)

C O NT I NU A R

4.11. Unión de dataframes


Otra de las grandes funcionalidades de Pandas es la facilidad con la que se puede unir (merge)
dataframes (tanto si comparten un campo clave como si no). Para ello, existen dos funciones que son las
que se estudian a continuación.

Primero, se crean dos copias del dataframe original para explicar las funciones:

Figura 132. Dataframes para realizar merge.


Fuente: elaboración propia.
# Creamos datasets reducidos
first_positions = houses[['housing_median_age',

                             'total_rooms',                       'total_bedrooms']].head(5).copy()

last_positions = houses[['housing_median_age',

                             'total_rooms',

                     'total_bedrooms']].tail(4).copy()

“A PPE N D” “ C O N C AT ” ( I ) “ C O N C AT ” ( I I ) “ C O N C AT ” ( I I I )

De un modo similar a las listas, con “append” uniremos los dataframes de forma consecutiva.
# Unimos ambos datasets con append
first_positions = first_positions.append(last_positions)
first_positions

Se han apilado los dos dataframes respetando sus índices. En la columna households se puede ver que el
dataframe original no tenía datos sobre esta columna y, al unir los dataframes, los toma todos como nulos.
Figura 133. Dataframes “append”.
Fuente: elaboración propia.
“A PPE N D” “ C O N C AT ” ( I ) “ C O N C AT ” ( I I ) “ C O N C AT ” ( I I I )

Es muy importante saber los tipos de unión (join) que podemos realizar al concatenar datasets:

inner: se realiza la unión por los elementos comunes de ambos datasets.

outer: la unión se realiza por todos los elementos entre los datasets

Se recomienda echar un vistazo a la documentación para ver los diferentes tipos de unión o join que
podemos realizar. [En línea] URL disponible en este enlace.

 En el apartado anterior, se han alterado los dataframes. Se vuelven a crear y se juntan por dos criterios de
unión descritos anteriormente.
“A PPE N D” “ C O N C AT ” ( I ) “ C O N C AT ” ( I I ) “ C O N C AT ” ( I I I )

first_positions = houses[['housing_median_age',
'total_rooms',
'total_bedrooms',
'ocean_proximity']].head(5).copy()
last_positions = houses[['housing_median_age',
'total_rooms',
'total_bedrooms',
'households',
'ocean_proximity']].tail(4).copy()
union_outer = pd.concat([first_positions, last_positions],
ignore_index=True, join='outer')
union_outer

Figura 134. Outer join.
Fuente: elaboración propia.
“A PPE N D” “ C O N C AT ” ( I ) “ C O N C AT ” ( I I ) “ C O N C AT ” ( I I I )

Es el mismo resultado que con “append” (salvo por el índice que se resetea).

union_inner = pd.concat([first_positions, last_positions],


                        ignore_index=True, join='inner')
union_inner
 
Como se puede ver en el merge por tipo inner, la columna households del nuevo dataset no aparece, ya que
no es un elemento común entre ambos datasets. No obstante, se debe tener en cuenta que, si un
dataset no tiene filas pertenecientes a una columna de otro dataset, como es el caso de la columna
households, que únicamente aparece en el nuevo dataset, sus valores pasarán a ser nulos. 

Figura 135. Inner join.


Fuente: elaboración propia.

C O NT I NU A R
4.12. Nuevas columnas
En muchas ocasiones, habrá que añadir nuevas columnas a un dataframe o realizar modificaciones entre las
columnas de un dataframe para obtener una nueva. 

 Es importante saber que las operaciones se realizan de forma columnar, es decir: si


dos columnas tienen una misma longitud, se puede realizar una operación entre
ambas sin necesidad de iterar sobre sus filas.
1

Figura 136. Creación de nuevas columnas (I).


Fuente: elaboración propia.

Para agregar una nueva columna, simplemente se puede crear una nueva variable con el nombre
del dataframe y el nombre de la columna que se va a crear. Primero, se creará un array para
utilizarlo como datos de la nueva columna.

np.random.randint(65, 120, 10)

Creamos la nueva columna ‘area’

union_inner['area'] = np.random.randint(65, 120, len(union_inner))

print(union_inner.columns)

union_inner.head()
2

Figura 137. Creación de nuevas columnas (II).


Fuente: elaboración propia.

Hay que señalar que cualquier operación que se realice entre columnas en un dataframe se aplica
a todos y cada uno de los elementos de la columna. Para ejemplificar esto, se crea una nueva
columna que sea la división de dos columnas del dataframe. Es importante ver que, para ello, no
se utiliza ningún bucle.

# Podemos crear una nueva columna que sea la media de camas por habitaciones totales

union_inner['mean_bedrooms'] = round(union_inner['total_rooms'] /
union_inner['total_bedrooms'],2)

C O NT I NU A R
4.13. Borrar filas y columnas
En algunas ocasiones, cuando se realiza una limpieza de datos o, simplemente, porque no sean objeto de
análisis, será necesario borrar filas o columnas de un dataframe. Para ambos casos, la función es la misma:
drop. Si se quiere borrar filas, se usará en el parámetro axis el valor 0 y, para las columnas, el valor 1. 
A continuación, se muestran algunos ejemplos: 
1

Figura 138. Borrado de columnas.


Fuente: elaboración propia.

union_inner = union_inner.drop(['housing_median_age', 'mean_bedrooms'], axis = 1)

union_inner
2

Figura 139. Borrado de filas.


Fuente: elaboración propia.

# Borrado por filas

print('TODAS LAS FILAS')

print(union_inner, "\n")

union_inner = union_inner.drop(3, axis=0)

print('BORRADO DE FILA 3')

print(union_inner.head(5))
C O NT I NU A R

4.14. Gestión de nulos


Finalmente, como es habitual, al trabajar con dataframes pueden aparecer los missing values o
simplemente, valores nulos. En Python aparecen representados por el string “NaN”. Mediante la función
isnull podremos saber si un elemento de un dataframe es nulo o no. Una práctica muy habitual es obtener el
número de valores nulos por columna en un dataframe y su porcentaje.

Figura 140. Nulos de un dataframe.


Fuente: elaboración propia.
print("*CANTIDAD de datos nulos por columna en el dataframe")

print(union_outer.isnull().sum())

print("----------------------------------")

print("*PORCENTAJE de datos nulos por columna en el dataframe")

print(union_outer.isnull().sum()/len(union_outer)*100)

Función “fillna” (I)



Si se quiere reemplazar los valores nulos y no borrarlos, existe la función “fillna”, que recibe como
parámetro el valor de reemplazo.
 
union_outer['households'] = union_outer['households'].fillna(5)

Figura 141. Reemplazo de nulos.


Fuente: elaboración propia.
Función “fillna” (I)

print("*CANTIDAD de datos nulos por columna en el data frame")
print(union_outer.isnull().sum())

Figura 142. Verificación de reemplazo de nulos.


Fuente: elaboración propia.

Función “dropna”

Por el contrario, si lo que queremos es borrar los valores nulos de un dataframe, podemos hacer uso de la
función “dropna” 

union_outer = pd.concat([first_positions, last_positions],


                        ignore_index=True, join='outer', sort=False)
union_outer = union_outer.dropna()
print("*CANTIDAD de datos nulos por columna en el data frame")
print(union_outer.isnull().sum())
print(union_outer.shape)

Figura 143. Borrado de nulos.


Fuente: elaboración propia.
C O NT I NU A R

4.15. Escribir dataframe a CSV

Al igual que se puede cargar datos de diferentes fuentes y procesarlos como un dataframe, posteriormente
se puede escribir un dataframe en una de las múltiples fuentes un uno de los diversos formatos de archivo
que acepta Pandas para exportar archivos.

En esta ocasión, se volcará la información de un dataframe como un CSV. Para ello, se dispone de la


función “to_csv”. Como parámetros se utilizarán el nombre del archivo, el argumento “sep” para utilizar un
tipo de separador u otro y, si no se desea que se muestre el índice del dataframe, se utilizará el argumento
index con valor none.
union_outer.to_csv('RESULTADOS.csv', sep=',', index=None)

Figura 144. Dataframe a CSV.


Fuente: elaboración propia.
Lección 5 de 8

V. Resumen

Repasa los conocimientos adquiridos en la unidad

A lo largo de la presente unidad, se ha trabajado con los archivos más comunes que podemos
encontrarnos a la hora de obtener y procesar un dataset con formatos de archivos muy comunes que se
encuentran a la hora de leer datos con los que trabajar. Se ha visto cómo trabajarlos sin utilizarlos como
dataframes y las diferentes formas de gestionar archivos.
Se ha visto a los arrays de la mano de la librería Numpy y se ha expuesto como diferenciarlos tanto por
su número de dimensiones, como por su estructura y las diferentes operaciones que podemos realizar
sobre los mismos. Es necesario conocer los arrays porque son la materia prima principal de algoritmos
de aprendizaje automático.

Por último, no podía faltar entre las herramientas del científico de datos la librería Pandas. Se ha visto
cómo crear un dataframe de cero o cargarlo desde un archivo, hasta realizar algunas de sus
operaciones más complejas, como agrupación, gestión de datos faltantes o selección de filas y
columnas, hasta su volcado final en archivos que soporta la librería.
Lección 6 de 8

VI. Caso práctico con solución

Aplica los conocimientos adquiridos en esta unidad

ENUNCIADO

Resuelve los siguientes ejercicios.


EJERCICIO 1

Crea los siguientes arrays:

Un array con 10 ceros.

Un array con 10 unos.

Un array con 10 sietes.

EJERCICIO 2

Crea un array con la secuencia de números del 20 a 40 (ambos inclusive).

Crea un array con la secuencia de números del 20 a 40 (ambos inclusive), tomados de cinco en
cinco elementos.

Muestra el array anterior en orden inverso.

Si es posible, intenta reconvertir el array reverso en un nuevo array multidimensional de 2x3. Si no


es posible, agrega elementos al array hasta que la longitud del array sea divisible entre tres.

Finalmente, elimina todas las dimensiones del array y devuelve un array plano.
EJERCICIO 3

Crea un objeto Pandas series a través de un array de 30 elementos aleatorios que sigan una
distribución beta con parámetros 0,1 y 0,8.

Sobre este objeto series crea un dataframe.

Muestra sus primeros y últimos cuatro elementos.

Renombra la columna del dataframe a “BETA_DIST”.

Crea una nueva columna con nombre “SQUARE_BETA”, que sea cada elemento de la distribución
beta al cuadrado.

Obtén los histogramas del dataframe.

EJERCICIO 4

A partir de las siguientes notas de un examen:


edad = np.random.randint(15, 18, 10)
puntuacion = [3.25, 8.5, 7.75, np.nan, 9.80, 4, 6.5, np.nan, 8.70, 5.5]

Crea un dataframe en donde el array “edad” tenga como nombre de columna “Edad” y, para la lista
“puntuación”, nombre “Puntuacion”.

Sustituye los valores nulos por 0.

Crea una nueva columna llamada “Situacion” que tenga como valores “PROMOCIONA” o “REPITE”
en función de si los valores de la columna “Puntuacion” son mayores a cinco o no.

Agrupa el nuevo dataframe por la media de edad.

Obtén el porcentaje de aprobados y repetidores.


Realiza una matriz de análisis gráfico.

Obtén una matriz de correlación sobre los datos numéricos.

V E R S O L U C I O NE S

EJERCICIO_1_SOLUCION_ipynb.zip
898 B

EJERCICIO_2_SOLUCION_ipynb.zip
1.6 KB

EJERCICIO_3_SOLUCION_ipynb.zip
10.4 KB
EJERCICIO_4_SOLUCION_ipynb.zip
22.9 KB
Lección 7 de 8

VII. Glosario

El glosario contiene términos destacados para la


comprensión de la unidad

Dataframe

Estructura de datos similar a una matriz, compuesta e indexable por filas y columnas, que puede aceptar
diferentes tipos de datos, no solo numéricos. Todas sus filas comparten el mismo índice.
Array

Tipo de dato estructurado que almacena los datos de forma similar a una lista. Podemos distinguir entre
arrays de una dimensión (vector) a arrays multidimensionales.

Pandas

Librería de procesamiento de datos que nos permite generar series y dataframes de forma muy sencilla, ya
sea creando nuestros propios dataframes como importándolos a través de archivo.

Numpy

Librería dedicada a la creación y procesamiento de arrays, así como de operaciones matriciales y de
álgebra lineal.

Archivo CSV

Archivo de texto en el que cada dato está separado por comas.

Archivo XML

Archivo estructurado bajo lenguaje de marcas, en el que podemos encontrar elementos que contienen los
datos y atributos de forma jerárquica.
Archivo JSON

Archivo similar a un diccionario de datos en donde los datos se distribuyen entre pares de clave : valor.

Series

Es la estructura de datos más básica de Pandas. A cada índice le corresponde un dato que se representan
en una columna junto con su índice; cuando existen más de una columna, se habla de un dataframe, ya que
todos sus datos comparten el mismo índice. Al seleccionar una única columna de un dataframe, se obtiene
un objeto series de esta.

Alias

Nombre con el que se asigna a una librería para simplificar y mejorar la legibilidad del código. En Python, un
alias se representa como as nombre_de_la_librería.

Slice

Porción de un conjunto de datos, ya sea de una lista, array, dataframe u otros.

Stacking

Resultado de unir o apilar uno o más arrays en un único array.
Spliting

Resultado de dividir un array en n nuevos arrays.

Indexación negativa

Propiedad de listas y cadenas de texto, principalmente. Se interpreta como la eliminación de los n últimos
elementos de una lista.
Lección 8 de 8

VIII. Bibliografía

Cheatsheet Numpy. [En línea] URL disponible en el siguiente enlace. 

Cheatsheet Pandas. [En línea] URL disponible en el siguiente enlace. 

Documentación Pandas. [En línea] URL disponible en siguiente enlace. 

Documentaicón Numpy. [En línea] URL disponible en el siguiente enlace.

Chin, L. Numpy essentials. Packt Publishing; 2016. [En línea] URL disponible en el siguiente
enlace.

Miller, C. Hands on data analysis with Numpy and Pandas implement Python packages from
data manipulation to processing. Packt Publishing; 2018. [En línea] URL disponible en el
siguiente enlace.  

Idris, I. Python data analysis cookbook. Packt Publishing; 2016. URL disponible en el siguiente
enlace. 

También podría gustarte