{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\"AeroPython\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Introducción a NumPy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_Hasta ahora hemos visto los tipos de datos más básicos que nos ofrece Python: integer, real, complex, boolean, list, tuple... Pero ¿no echas algo de menos? Efectivamente, los __arrays__. _\n", "\n", "_En este notebook nos adentraremos en el paquete NumPy: aprenderemos a crear distintos arrays y a operar con ellos_." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ¿Qué es un array? " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Un array es un __bloque de memoria que contiene elementos del mismo tipo__. Básicamente:\n", "\n", "* nos _recuerdan_ a los vectores, matrices, tensores...\n", "* podemos almacenar el array con un nombre y acceder a sus __elementos__ mediante sus __índices__.\n", "* ayudan a gestionar de manera eficiente la memoria y a acelerar los cálculos.\n", "\n", "\n", "---\n", "\n", "| Índice | 0 | 1 | 2 | 3 | ... | n-1 | n |\n", "| ---------- | :---: | :---: | :---: | :---: | :---: | :---: | :---: |\n", "| Valor | 2.1 | 3.6 | 7.8 | 1.5 | ... | 5.4 | 6.3 |\n", "\n", "---\n", "\n", "__¿Qué solemos guardar en arrays?__\n", "\n", "* Vectores y matrices.\n", "* Datos de experimentos:\n", " - En distintos instantes discretos.\n", " - En distintos puntos del espacio.\n", "* Resultado de evaluar funciones con los datos anteriores.\n", "* Discretizaciones para usar algoritmos de: integración, derivación, interpolación...\n", "* ... " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ¿Qué es NumPy?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "NumPy es un paquete fundamental para la programación científica que __proporciona un objeto tipo array__ para almacenar datos de forma eficiente y una serie de __funciones__ para operar y manipular esos datos.\n", "Para usar NumPy lo primero que debemos hacer es importarlo:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'1.14.0'" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", "#para ver la versión que tenemos instalada:\n", "np.__version__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Nuestro primer array" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "¿No decíamos que Python era fácil? Pues __creemos nuestros primeros arrays__:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1, 2, 3, 4])" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Array de una dimensión\n", "mi_primer_array = np.array([1, 2, 3, 4]) \n", "mi_primer_array" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1 2 3 4]\n" ] } ], "source": [ "# Podemos usar print\n", "print(mi_primer_array)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "numpy.ndarray" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Comprobar el tipo de mi_primer_array\n", "type(mi_primer_array)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dtype('int64')" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Comprobar el tipo de datos que contiene\n", "mi_primer_array.dtype" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Los arrays de una dimensión se crean pasándole una lista como argumento a la función `np.array`. Para crear un array de dos dimensiones le pasaremos una _lista de listas_:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "# Array de dos dimensiones\n", "mi_segundo_array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Podemos continuar en la siguiente línea usando `\\`, pero no es necesario escribirlo dentro de paréntesis o corchetes
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Esto sería una buena manera de definirlo, de acuerdo con el [PEP 8 (indentation)](http://legacy.python.org/dev/peps/pep-0008/#indentation):" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "mi_segundo_array = np.array([\n", " [1, 2, 3],\n", " [4, 5, 6],\n", " [7, 8, 9]\n", " ]) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Funciones y constantes de NumPy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Hemos dicho que NumPy también incorporá __funciones__. Un ejemplo sencillo:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Suma\n", "np.sum(mi_primer_array)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Máximo\n", "np.max(mi_primer_array)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0.84147098, 0.90929743, 0.14112001],\n", " [-0.7568025 , -0.95892427, -0.2794155 ],\n", " [ 0.6569866 , 0.98935825, 0.41211849]])" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Seno\n", "np.sin(mi_segundo_array)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Y algunas __constantes__ que podemos neccesitar:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(3.141592653589793, 2.718281828459045)" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.pi, np.e" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Funciones para crear arrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "¿Demasiada teoría? vayamos a la práctica. Ya hemos visto que la función `np.array()` nos permite crear arrays con los valores que nosotros introduzcamos manualmente a través de listas. Más adelante, aprenderemos a leer ficheros y almacenarlos en arrays. Mientras tanto, ¿qué puede hacernos falta?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### array de ceros" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# En una dimensión\n", "np.zeros(100)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", " [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", " [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", " [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", " [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", " [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", " [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", " [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", " [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", " [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# En dos dimensiones\n", "np.zeros([10,10])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Nota: \n", "En el caso 1D es válido tanto `np.zeros([5])` como `np.zeros(5)` (sin los corchetes), pero no lo será para el caso nD\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### array \"vacío\"" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([6.94753636e-310, 4.65239212e-310, 4.65239227e-310, 0.00000000e+000,\n", " 0.00000000e+000, 0.00000000e+000, 4.65239215e-310, 0.00000000e+000,\n", " 0.00000000e+000, 0.00000000e+000])" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.empty(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Importante: \n", "El array vacío se crea en un tiempo algo inferior al array de ceros. Sin embargo, el valor de sus elementos será arbitrario y dependerá del estado de la memoria. Si lo utilizas asegúrate de que luego llenas bien todos sus elementos porque podrías introducir resultados erróneos.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### array de unos" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1., 1.],\n", " [1., 1.],\n", " [1., 1.]])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.ones([3, 2])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Nota: \n", "Otras funciones muy útiles son `np.zeros_like` y `np.ones_like`. Usa la ayuda para ver lo que hacen si lo necesitas.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### array identidad" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1., 0., 0., 0.],\n", " [0., 1., 0., 0.],\n", " [0., 0., 1., 0.],\n", " [0., 0., 0., 1.]])" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.identity(4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Nota: \n", "También puedes probar `np.eye()` y `np.diag()`.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Rangos" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### np.arange" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "NumPy, dame __un array que vaya de 0 a 5__:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3, 4])" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.arange(0, 5)\n", "a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__Mira con atención el resultado anterior__, ¿hay algo que deberías grabar en tu cabeza para simpre?\n", "__El último elemento no es 5 sino 4__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "NumPy, dame __un array que vaya de 0 a 10, de 3 en 3__:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0, 3, 6, 9])" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.arange(0, 11, 3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### np.linspace" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Si has tenido que usar MATLAB alguna vez, seguro que esto te suena:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. ,\n", " 5.5, 6. , 6.5, 7. , 7.5, 8. , 8.5, 9. , 9.5, 10. ])" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.linspace(0, 10, 21)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "En este caso sí que se incluye el último elemento." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Nota: \n", "También puedes probar `np.logspace()`\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### reshape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Con `np.arange()` es posible crear \"vectores\" cuyos elementos tomen valores consecutivos o equiespaciados, como hemos visto anteriormente. ¿Podemos hacer lo mismo con \"matrices\"? Pues sí, pero no usando una sola función. Imagina que quieres crear algo como esto:\n", "\n", "\\begin{pmatrix}\n", " 1 & 2 & 3\\\\ \n", " 4 & 5 & 6\\\\\n", " 7 & 8 & 9\\\\\n", " \\end{pmatrix}\n", " \n", "* Comenzaremos por crear un array 1d con los valores $(1,2,3,4,5,6,7,8,9)$ usando `np.arange()`.\n", "* Luego le daremos forma de array 2d. con `np.reshape(array, (dim0, dim1))`." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 3],\n", " [4, 5, 6],\n", " [7, 8, 9]])" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.arange(1, 10)\n", "M = np.reshape(a, [3, 3])\n", "M" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 3],\n", " [4, 5, 6],\n", " [7, 8, 9]])" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# También funciona como método\n", "N = a.reshape([3,3])\n", "N" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Nota: \n", "No vamos a entrar demasiado en qué son los métodos, pero debes saber que están asociados a la programación orientada a objetos y que en Python todo es un objeto. Lo que debes pensar es que son unas funciones especiales en las que el argumento más importante (sobre el que se realiza la acción) se escribe delante seguido de un punto. Por ejemplo: `.método(argumentos)`\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Operaciones" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Operaciones elemento a elemento" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ahora que pocas cosas se nos escapan de los arrays, probemos a hacer algunas operaciones. El funcionamiento es el habitual en FORTRAN y MATLAB y poco hay que añadir:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65])" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#crear un arra y y sumarle un número\n", "arr = np.arange(11)\n", "arr + 55" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20])" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#multiplicarlo por un número\n", "arr * 2" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100])" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#elevarlo al cuadrado\n", "arr ** 2" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0. , 0.76159416, 0.96402758, 0.99505475, 0.9993293 ,\n", " 0.9999092 , 0.99998771, 0.99999834, 0.99999977, 0.99999997,\n", " 1. ])" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#calcular una función\n", "np.tanh(arr)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Entrenamiento: \n", "Puedes tratar de comparar la diferencia de tiempo entre realizar la operación en bloque, como ahora, y realizarla elemento a elemento, recorriendo el array con un bucle.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__Si las operaciones involucran dos arrays también se realizan elemento a elemento__" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "#creamos dos arrays\n", "arr1 = np.arange(0, 11)\n", "arr2 = np.arange(20, 31)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40])" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#los sumamos\n", "arr1 + arr2" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 21, 44, 69, 96, 125, 156, 189, 224, 261, 300])" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#multiplicamos\n", "arr1 * arr2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Comparaciones" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([False, False, False, False, False, False, False, False, False,\n", " False, False])" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# >,<\n", "arr1 > arr2" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([False, False, False, False, False, False, False, False, False,\n", " False, False])" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ==\n", "arr1 == arr2 # ¡ojo! los arrays son de integers, no de floats" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Nota: \n", "Por cierto, ¿qúe ocurrirá si los arrays con los que se quiere operar no tiene la misma forma? ¿apuestas? Quizá más adelante te interese buscar algo de información sobre __broadcasting__.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "___Hemos aprendido:___\n", "\n", "* A usar las principales funciones para crear arrays.\n", "* A operar con arrays.\n", "\n", "_En definitiva:_\n", "* __Ingenieros y científicos $\\heartsuit$ arrays.__\n", "* __Ingenieros y científicos necesitan NumPy.__\n", "\n", "__¡Quiero más!__Algunos enlaces:\n", "\n", "Algunos enlaces en Pybonacci:\n", "\n", "* [Cómo crear matrices en Python con NumPy](http://pybonacci.wordpress.com/2012/06/11/como-crear-matrices-en-python-con-numpy/).\n", "* [Números aleatorios en Python con NumPy y SciPy](http://pybonacci.wordpress.com/2013/01/11/numeros-aleatorios-en-python-con-numpy-y-scipy/).\n", "\n", "\n", "Algunos enlaces en otros sitios:\n", "\n", "* [100 numpy exercises](http://www.labri.fr/perso/nrougier/teaching/numpy.100/index.html). Es posible que de momento sólo sepas hacer los primeros, pero tranquilo, pronto sabrás más...\n", "* [NumPy and IPython SciPy 2013 Tutorial](http://conference.scipy.org/scipy2013/tutorial_detail.php?id=100).\n", "* [NumPy and SciPy documentation](http://docs.scipy.org/doc/)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "
\n", "####

¡Síguenos en Twitter!\n", "
\n", "###### Follow @AeroPython \n", "
\n", "###### Este notebook ha sido realizado por: Juan Luis Cano y Álex Sáez \n", "
\n", "##### \"Licencia
Curso AeroPython por Juan Luis Cano Rodriguez y Alejandro Sáez Mollejo se distribuye bajo una Licencia Creative Commons Atribución 4.0 Internacional." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "_Las siguientes celdas contienen configuración del Notebook_\n", "\n", "_Para visualizar y utlizar los enlaces a Twitter el notebook debe ejecutarse como [seguro](http://ipython.org/ipython-doc/dev/notebook/security.html)_\n", "\n", " File > Trusted Notebook" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/html": [ "/* This template is inspired in the one used by Lorena Barba\n", "in the numerical-mooc repository: https://github.com/numerical-mooc/numerical-mooc\n", "We thank her work and hope you also enjoy the look of the notobooks with this style */\n", "\n", "\n", "\n", "El estilo se ha aplicado =)\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Esta celda da el estilo al notebook\n", "from IPython.core.display import HTML\n", "css_file = '../styles/aeropython.css'\n", "HTML(open(css_file, \"r\").read())" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.4" } }, "nbformat": 4, "nbformat_minor": 1 }