{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Stat 593 : Robust Statistics\n", "## Introduction to robustness\n", "### *Joseph Salmon*\n", "\n", "This notebook reproduces the pictures for the course \"IntroRobustness\"\n", "\n", "- REM:\n", " - you need TeX install on your machine (otherwise errors could appends)\n", " - you need the file share_code somewhere available (for my architecture it was few level up)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# import packages\n", "import numpy as np\n", "from scipy import stats\n", "from statsmodels.nonparametric.kde import KDEUnivariate\n", "# dirty local imports:\n", "import sys\n", "sys.path.append(\"./../../../\")\n", "from share_code.utils import plt, sns, my_saving_display\n", "from joblib import Memory\n", "import scipy as sp\n", "\n", "# cachedir = './joblib_cache/'\n", "# memory = Memory(cachedir=cachedir, verbose=1)\n", "\n", "sns.set_palette(\"colorblind\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# to get images in the notebook\n", "%matplotlib inline " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Plot initialization" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "dirname = \"../prebuiltimages/\"\n", "imageformat = \".pdf\" # should be .pdf or .png \n", "# some colors I'll use\n", "brown = (0.64, 0.16, 0.16)\n", "purple = (148. / 255, 0, 211. / 255)\n", "plt.close(\"all\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Saving display function:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "saving = False # True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Popular statistics:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "mu, sigma, nb_samples = 1.5, 4, 15\n", "\n", "# Random setting\n", "np.random.seed(seed=2)\n", "rgamma = np.random.gamma\n", "X = rgamma(mu, sigma, nb_samples) # Generate sample from a Gamma distribution\n", "y = np.ones(nb_samples,)\n", "\n", "X[np.argmin(X)] = -3\n", "X[np.argmax(X)] = 30\n", "\n", "# Various statistics:\n", "meanX = np.mean(X) # mean\n", "minX = np.min(X) # min\n", "maxX = np.max(X) # max\n", "medX = np.median(X) # median\n", "MADX = np.median(np.abs(X - medX)) # mean absolute deviation\n", "s = np.std(X, ddof=1) # unbiased standard deviation\n", "\n", "alpha_trim = 0.25\n", "tmeanX = stats.trim_mean(X, alpha_trim) # trimmed mean (level: alpha_trim)\n", "\n", "xmin = minX - 20\n", "xmax = 35" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Empirical mean display:\n", "\n", "REM: meaning of shortcuts such as lw (linewidth), ls (linestyle) etc., are available at: https://matplotlib.org/api/lines_api.html" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig1, ax = plt.subplots(figsize=(10, 3))\n", "ax.set_ylim(0, 1.5)\n", "ax.set_xlim(xmin, xmax)\n", "ax.get_xaxis().tick_bottom()\n", "ax.axes.get_yaxis().set_visible(False)\n", "\n", "ax.spines['right'].set_color('none')\n", "ax.spines['top'].set_color('none')\n", "ax.spines['bottom'].set_position(('data', 0.5))\n", "ax.spines['left'].set_color('none')\n", "\n", "ax.scatter(X, y, c='black', s=300, marker='o', edgecolors=brown, lw='1')\n", "ax.plot([meanX, meanX], [0, 1.5], color=brown, lw=1.5, ls=\"--\")\n", "\n", "plt.xlabel(r'$x$', fontsize=18)\n", "plt.annotate(r'$\\overline{x}_n : \\mbox{empirical mean}$',\n", " xy=(meanX, 0.4), xycoords='data', xytext=(+10, +30),\n", " textcoords='offset points', fontsize=18, color=brown)\n", "\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "if saving:\n", " my_saving_display(fig1, dirname, \"GammaSampleMean\", imageformat)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Empirical median display:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig1, ax = plt.subplots(figsize=(10, 3))\n", "ax.set_ylim(0, 1.5)\n", "ax.set_xlim(xmin, xmax)\n", "ax.get_xaxis().tick_bottom()\n", "ax.axes.get_yaxis().set_visible(False)\n", "\n", "ax.spines['right'].set_color('none')\n", "ax.spines['top'].set_color('none')\n", "ax.spines['bottom'].set_position(('data', 0.5))\n", "ax.spines['left'].set_color('none')\n", "\n", "ax.scatter(X, y, c='black', s=300, marker='o', edgecolors=brown, lw='1')\n", "\n", "ax.plot([medX, medX], [0, 1.5], color=purple, lw=1.5, ls=\"--\")\n", "plt.xlabel(r'$x$', fontsize=18)\n", "plt.annotate(r'$\\rm{Med}_n(\\mathbb{x}): \\mbox{empirical median}$',\n", " xy=(medX, 0.4), xycoords='data', xytext=(-210, +30),\n", " textcoords='offset points', fontsize=18, color=purple)\n", "\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "if saving:\n", " my_saving_display(fig1, dirname, \"GammaSampleMediane\", imageformat)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Trimmed mean (level: alpha_trim) display:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig1, ax = plt.subplots(figsize=(10, 3))\n", "ax.set_ylim(0, 1.5)\n", "ax.set_xlim(xmin, xmax)\n", "ax.get_xaxis().tick_bottom()\n", "ax.axes.get_yaxis().set_visible(False)\n", "\n", "ax.spines['right'].set_color('none')\n", "ax.spines['top'].set_color('none')\n", "ax.spines['bottom'].set_position(('data', 0.5))\n", "ax.spines['left'].set_color('none')\n", "\n", "ax.scatter(X, y, c='black', s=300, marker='o', edgecolors=brown, lw='1')\n", "\n", "ax.plot([tmeanX, tmeanX], [0, 1.5], c='blue', lw=1.5, ls=\":\")\n", "plt.xlabel(r'$x$', fontsize=18)\n", "tt = \"$\\overline{x}_{n,%s} : \\mbox{trimmed mean}$\" % str(alpha_trim)\n", "plt.annotate(tt, xy=(tmeanX - 18, 0.4), xycoords='data', xytext=(+5, +30),\n", " textcoords='offset points', fontsize=18, color='blue')\n", "\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "if saving:\n", " my_saving_display(fig1, dirname, \"GammaSampleTrimmed\", imageformat)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Empirical mean / median / trimmed mean :" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig1, ax = plt.subplots(figsize=(10, 3))\n", "ax.set_ylim(0, 1.5)\n", "ax.set_xlim(xmin, xmax)\n", "ax.get_xaxis().tick_bottom()\n", "ax.axes.get_yaxis().set_visible(False)\n", "\n", "ax.spines['right'].set_color('none')\n", "ax.spines['top'].set_color('none')\n", "ax.spines['bottom'].set_position(('data', 0.5))\n", "ax.spines['left'].set_color('none')\n", "\n", "ax.scatter(X, y, c='black', s=300, marker='o', edgecolors=brown, lw='1')\n", "\n", "ax.plot([meanX, meanX], [0, 1.5], color=brown, lw=1.5, ls=\"--\")\n", "ax.plot([medX, medX], [0, 1.5], color=purple, lw=1.5, ls=\"--\")\n", "ax.plot([tmeanX, tmeanX], [0, 1.5], color='blue',\n", " lw=1.5, ls=\":\")\n", "\n", "plt.xlabel(r'$x$', fontsize=18)\n", "plt.annotate(r'$\\rm{Med}_n(\\mathbb{x}): \\mbox{empirical median}$',\n", " xy=(medX, 1), xycoords='data', xytext=(-210, +30),\n", " textcoords='offset points', fontsize=18, color=purple)\n", "plt.annotate(r'$\\bar{x}_n : \\mbox{empirical mean}$', xy=(meanX, 0.4),\n", " xycoords='data', xytext=(+10, +30), textcoords='offset points',\n", " fontsize=18, color=brown)\n", "plt.annotate(tt, xy=(tmeanX - 18, 0.4), xycoords='data', xytext=(+5, +30),\n", " textcoords='offset points', fontsize=18, color='blue')\n", "\n", "\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "if saving:\n", " my_saving_display(fig1, dirname, \"GammaSampleMedianeMean\", imageformat)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "X[np.argmax(X)] = 10\n", "\n", "fig1, ax = plt.subplots(figsize=(10, 3))\n", "ax.set_ylim(0, 1.5)\n", "ax.set_xlim(xmin, xmax)\n", "ax.get_xaxis().tick_bottom()\n", "ax.axes.get_yaxis().set_visible(False)\n", "\n", "ax.spines['right'].set_color('none')\n", "ax.spines['top'].set_color('none')\n", "ax.spines['bottom'].set_position(('data', 0.5))\n", "ax.spines['left'].set_color('none')\n", "\n", "ax.scatter(X, y, c='black', s=300, marker='o', edgecolors=brown, lw='1')\n", "\n", "ax.plot([np.mean(X), np.mean(X)], [0, 1.5], color=brown, lw=1.5, ls=\"--\")\n", "ax.plot([medX, medX], [0, 1.5], color=purple, lw=1.5, ls=\"--\")\n", "ax.plot([tmeanX, tmeanX], [0, 1.5], color='blue',\n", " lw=1.5, ls=\":\")\n", "\n", "plt.xlabel(r'$x$', fontsize=18)\n", "plt.annotate(r'$\\rm{Med}_n(\\mathbb{x}): \\mbox{empirical median}$',\n", " xy=(medX, 1), xycoords='data', xytext=(-210, +30),\n", " textcoords='offset points', fontsize=18, color=purple)\n", "plt.annotate(r'$\\bar{x}_n : \\mbox{empirical mean}$', xy=(meanX, 0.4),\n", " xycoords='data', xytext=(+10, +30), textcoords='offset points',\n", " fontsize=18, color=brown)\n", "plt.annotate(tt, xy=(tmeanX - 18, 0.4), xycoords='data', xytext=(+5, +30),\n", " textcoords='offset points', fontsize=18, color='blue')\n", "\n", "\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "if saving:\n", " my_saving_display(fig1, dirname, \"GammaSampleMedianeMeanBig10\", imageformat)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "X[np.argmax(X)] = 20\n", "\n", "fig1, ax = plt.subplots(figsize=(10, 3))\n", "ax.set_ylim(0, 1.5)\n", "ax.set_xlim(xmin, xmax)\n", "ax.get_xaxis().tick_bottom()\n", "ax.axes.get_yaxis().set_visible(False)\n", "\n", "ax.spines['right'].set_color('none')\n", "ax.spines['top'].set_color('none')\n", "ax.spines['bottom'].set_position(('data', 0.5))\n", "ax.spines['left'].set_color('none')\n", "\n", "ax.scatter(X, y, c='black', s=300, marker='o', edgecolors=brown, lw='1')\n", "\n", "ax.plot([np.mean(X), np.mean(X)], [0, 1.5], color=brown, lw=1.5, ls=\"--\")\n", "ax.plot([medX, medX], [0, 1.5], color=purple, lw=1.5, ls=\"--\")\n", "ax.plot([tmeanX, tmeanX], [0, 1.5], color='blue',\n", " lw=1.5, ls=\":\")\n", "\n", "plt.xlabel(r'$x$', fontsize=18)\n", "plt.annotate(r'$\\rm{Med}_n(\\mathbb{x}): \\mbox{empirical median}$',\n", " xy=(medX, 1), xycoords='data', xytext=(-210, +30),\n", " textcoords='offset points', fontsize=18, color=purple)\n", "plt.annotate(r'$\\bar{x}_n : \\mbox{empirical mean}$', xy=(meanX, 0.4),\n", " xycoords='data', xytext=(+10, +30), textcoords='offset points',\n", " fontsize=18, color=brown)\n", "plt.annotate(tt, xy=(tmeanX - 18, 0.4), xycoords='data', xytext=(+5, +30),\n", " textcoords='offset points', fontsize=18, color='blue')\n", "\n", "\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "if saving:\n", " my_saving_display(fig1, dirname, \"GammaSampleMedianeMeanBig20\", imageformat)\n", "\n", "X[np.argmax(X)] = 30" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Standard deviation:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig1, ax = plt.subplots(figsize=(10, 3))\n", "ax.set_ylim(0, 1.5)\n", "ax.set_xlim(xmin, xmax)\n", "ax.get_xaxis().tick_bottom()\n", "ax.axes.get_yaxis().set_visible(False)\n", "\n", "ax.spines['right'].set_color('none')\n", "ax.spines['top'].set_color('none')\n", "ax.spines['bottom'].set_position(('data', 0.5))\n", "ax.spines['left'].set_color('none')\n", "\n", "ax.scatter(X, y, c='black', s=300, marker='o', edgecolors=brown, lw='1')\n", "ax.plot([meanX, meanX], [0, 1.5], color=brown, lw=1.5, ls=\"--\")\n", "\n", "plt.arrow(meanX, 1.2, -s, 0, fc=brown, ec=brown,\n", " head_width=0.05, head_length=0.1, length_includes_head=True)\n", "plt.arrow(meanX - s, 1.2, s, 0, fc=brown, ec=brown,\n", " head_width=0.05, head_length=0.1, length_includes_head=True)\n", "plt.arrow(meanX, 1.2, s, 0, fc=brown, ec=brown,\n", " head_width=0.05, head_length=0.1, length_includes_head=True)\n", "plt.arrow(meanX + s, 1.2, -s, 0, fc=brown, ec=brown,\n", " head_width=0.05, head_length=0.1, length_includes_head=True)\n", "\n", "plt.xlabel(r'$x$', fontsize=18)\n", "\n", "plt.annotate(r'$\\bar{x}_n : \\mbox{empirical mean}$',\n", " xy=(meanX, 0.4), xycoords='data', xytext=(+10, +30),\n", " textcoords='offset points', fontsize=18, color=brown)\n", "plt.annotate(r'$s_n$', xy=(meanX + s * (0.4), 1), xycoords='data',\n", " xytext=(+10, +30), textcoords='offset points', fontsize=18,\n", " color=brown)\n", "plt.annotate(r'$s_n$', xy=(meanX - s * (0.6), 1), xycoords='data',\n", " xytext=(+10, +30), textcoords='offset points', fontsize=18,\n", " color=brown)\n", "\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "if saving:\n", " my_saving_display(fig1, dirname, \"GammaSD\", imageformat)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Mean Absolute Deviation (MAD):\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig1, ax = plt.subplots(figsize=(10, 3))\n", "ax.set_ylim(0, 1.5)\n", "ax.set_xlim(xmin, xmax)\n", "ax.get_xaxis().tick_bottom()\n", "ax.axes.get_yaxis().set_visible(False)\n", "\n", "ax.spines['right'].set_color('none')\n", "ax.spines['top'].set_color('none')\n", "ax.spines['bottom'].set_position(('data', 0.5))\n", "ax.spines['left'].set_color('none')\n", "\n", "ax.scatter(X, y, c='black', s=300, marker='o', edgecolors=brown, lw='1')\n", "ax.plot([medX, medX], [0, 1.5], color=purple, lw=1.5, ls=\"--\")\n", "\n", "plt.arrow(medX, 1.2, -MADX, 0, fc=purple, ec=purple, head_width=0.05,\n", " head_length=0.1, length_includes_head=True)\n", "plt.arrow(medX - MADX, 1.2, MADX, 0, fc=purple, ec=purple, head_width=0.05,\n", " head_length=0.1, length_includes_head=True)\n", "plt.arrow(medX, 1.2, MADX, 0, fc=purple, ec=purple, head_width=0.05,\n", " head_length=0.1, length_includes_head=True)\n", "plt.arrow(medX + MADX, 1.2, -MADX, 0, fc=purple, ec=purple, head_width=0.05,\n", " head_length=0.1, length_includes_head=True)\n", "\n", "plt.xlabel(r'$x$', fontsize=18)\n", "\n", "plt.annotate(r'$\\rm{Med}_n(\\mathbb{x}): \\mbox{empirical median}$',\n", " xy=(medX, 0.4), xycoords='data', xytext=(+10, +30),\n", " textcoords='offset points', fontsize=18, color=purple)\n", "plt.annotate(r'$\\rm{MAD}_n(\\mathbb{x})$', xy=(medX + MADX * (0.1), 1),\n", " xycoords='data', xytext=(+10, +30), textcoords='offset points',\n", " fontsize=14, color=purple)\n", "plt.annotate(r'$\\rm{MAD}_n(\\mathbb{x})$', xy=(medX - MADX * (1.2), 1),\n", " xycoords='data', xytext=(-55, +30), textcoords='offset points',\n", " fontsize=14, color=purple)\n", "\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "if saving:\n", " my_saving_display(fig1, dirname, \"GammaMAD\", imageformat)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Newcomb's measurements for evaluating the speed of light" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is extracted from Maronna et al. 2006 (see also Stigler 1977)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "X = np.array([28, 26, 33, 24, 34, 29, 22, 24, 21, 25, -44, 27, 16, 40, -2, 30, 23, 29, 31, 19]) * 0.001 + 24.8\n", "nb_samples = X.shape[0]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Various statistics:\n", "y = np.ones(nb_samples,)\n", "meanX = np.mean(X) # mean\n", "minX = np.min(X) # min\n", "maxX = np.max(X) # max\n", "medX = np.median(X) # median\n", "MADX = np.median(np.abs(X - medX)) # mean absolute deviation\n", "MADNX = MADX / sp.stats.norm.ppf(0.75) # 0.6745 correponds to sp.stats.norm.ppf(0.75)\n", "s = np.std(X, ddof=1) # unbiased standard deviation" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig1, ax = plt.subplots(figsize=(10, 3))\n", "ax.set_ylim(0, 1.5)\n", "ax.set_xlim(minX-0.01, maxX+0.01)\n", "ax.get_xaxis().tick_bottom()\n", "ax.axes.get_yaxis().set_visible(False)\n", "\n", "ax.spines['right'].set_color('none')\n", "ax.spines['top'].set_color('none')\n", "ax.spines['bottom'].set_position(('data', 0.5))\n", "ax.spines['left'].set_color('none')\n", "plt.xlabel(r'Raw observations', fontsize=18)\n", "\n", "ax.scatter(X, y, c='black', s=300, marker='o', edgecolors=brown, lw='1')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "if saving:\n", " my_saving_display(fig1, dirname, \"Newcombe_raw\", imageformat)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Investigation of outliers with t-statistics " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "t = (X - meanX) / s" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from matplotlib.ticker import MaxNLocator\n", "fig1, ax = plt.subplots(figsize=(10, 3))\n", "ax.set_ylim(-15, 15)\n", "ax.set_xlim(-1, t.shape[0])\n", "ax.xaxis.set_major_locator(MaxNLocator(integer=True))\n", "# ax.yaxis.set_major_locator(MaxNLocator(integer=True))\n", "\n", "plt.ylabel(r't-statistics', fontsize=18)\n", "plt.xlabel(r'index', fontsize=18)\n", "ax.axhline(y=3, color='k', lw=1.5, ls=\"--\")\n", "ax.axhline(y=-3, color='k', lw=1.5, ls=\"--\")\n", "\n", "ax.scatter(np.arange(t.shape[0]),t, c='black', s=100, marker='o', edgecolors=brown, lw='1')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "if saving:\n", " my_saving_display(fig1, dirname, \"Newcombe_t\", imageformat)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Conclusion**: with the classical rule that \"outliers\" correspond to values with $|t_i|>3$, only the values t[10] = -3.72, qualifies as an outlier" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Investigation of outliers with \"medianized\" t-statistics" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "t_2 = (X - medX) / MADNX" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from matplotlib.ticker import MaxNLocator\n", "fig1, ax = plt.subplots(figsize=(10, 3))\n", "ax.set_ylim(-15, 15)\n", "ax.set_xlim(-1, t.shape[0])\n", "ax.xaxis.set_major_locator(MaxNLocator(integer=True))\n", "\n", "plt.ylabel(r't-statistics', fontsize=18)\n", "plt.xlabel(r'index', fontsize=18)\n", "ax.axhline(y=3, color='k', lw=1.5, ls=\"--\")\n", "ax.axhline(y=-3, color='k', lw=1.5, ls=\"--\")\n", "\n", "ax.scatter(np.arange(t_2.shape[0]),t_2, c='black', s=100, marker='o', edgecolors=brown, lw='1')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "if saving:\n", " my_saving_display(fig1, dirname, \"Newcombe_t_2\", imageformat)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Conclusion**: with the robust variant rule the \"outliers\" correspond to values with $|t'_i|>3$, and now two values t[10] = -11.72 and t_2[14] = -4.64 qualify as outliers" ] } ], "metadata": { "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.0" } }, "nbformat": 4, "nbformat_minor": 2 }