{ "cells": [ { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "# Programming Tips\n", "\n", "Steve Matsumoto " ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "This notebook will cover various tips for programming that you might find useful as you work through projects." ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "## Pandas\n", "\n", "In ModSim, you will primarily work with two types of Pandas data: series and data frames. (The TimeSeries and SweepSeries types in ModSim work very similarly to series in Pandas.) You can find the documentation for [series](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.html) and for [data frames](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html), which provide some example code and illustrate all the things you can do with these data types. It's important to note that you do **not** need to know what all of these do, but if you want to see if there is an easy way to do X with a data frame or series, the documentation is a good place to start. Below, I will highlight a couple things that you may consider doing in your project.\n", "\n", "Here is some sample data to serve as examples:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 4\n", "1 36\n", "2 45\n", "3 50\n", "4 75\n", "dtype: int64" ] }, "execution_count": 1, "metadata": { }, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "\n", "series = pd.Series([4, 36, 45, 50, 75])\n", "series" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
abc
0123
1456
2789
\n", "
" ], "text/plain": [ " a b c\n", "0 1 2 3\n", "1 4 5 6\n", "2 7 8 9" ] }, "execution_count": 2, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame = pd.DataFrame({'a': [1, 4, 7], 'b': [2, 5, 8], 'c': [3, 6, 9]})\n", "frame" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "### How to get a specific row or column out of a data frame\n", "\n", "Getting a specific value out of a series is similar to how you set the value of a series. Remember that the index starts at 0, so using an index like `[1]` will actually give you the second item in the series." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "36" ] }, "execution_count": 3, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series[1]" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "This works with getting columns out of a data frame:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 1\n", "1 4\n", "2 7\n", "Name: a, dtype: int64" ] }, "execution_count": 4, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame['a']" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "But this doesn't work for getting a row out of a data frame:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "ename": "KeyError", "evalue": "1", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/srv/conda/envs/notebook/lib/python3.7/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 2896\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2897\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2898\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", "\u001b[0;31mKeyError\u001b[0m: 1", "\nDuring handling of the above exception, another exception occurred:\n", "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# This will give result in KeyError: 1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mframe\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m/srv/conda/envs/notebook/lib/python3.7/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 2978\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnlevels\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2979\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_multilevel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2980\u001b[0;31m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2981\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mis_integer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2982\u001b[0m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/srv/conda/envs/notebook/lib/python3.7/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 2897\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2898\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2899\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_maybe_cast_indexer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2900\u001b[0m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_indexer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtolerance\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtolerance\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2901\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mindexer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mndim\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mindexer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msize\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", "\u001b[0;31mKeyError\u001b[0m: 1" ] } ], "source": [ "# This will give result in KeyError: 1\n", "frame[1]" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "With data frames, you have to use `loc`, like so:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "a 4\n", "b 5\n", "c 6\n", "Name: 1, dtype: int64" ] }, "execution_count": 6, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame.loc[1]" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "If you want to get a *specific cell* of a data frame, you can use `at`:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 7, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame.at[1, 'b']" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "### Information about series or data frames\n", "\n", "You can find the rows and columns of a data frame by just printing it:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
abc
0123
1456
2789
\n", "
" ], "text/plain": [ " a b c\n", "0 1 2 3\n", "1 4 5 6\n", "2 7 8 9" ] }, "execution_count": 8, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "But if the data frame is large, this will take a up a lot of screen space. You can instead use `index` (for the rows), which works for both series and data frames, and `columns` (for the...columns), which only works for data frames:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "RangeIndex(start=0, stop=5, step=1)" ] }, "execution_count": 9, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series.index" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "RangeIndex(start=0, stop=3, step=1)" ] }, "execution_count": 10, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame.index" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "Index(['a', 'b', 'c'], dtype='object')" ] }, "execution_count": 11, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame.columns" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "`RangeIndex` might look familiar: it provides you a start, stop, and a number of steps and gives you an even spacing of that number of steps between the two values.\n", "\n", "You can also get the total number of values in a data frame or series:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 12, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series.size" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 13, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame.size" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "The \"shape\" will tell you how many rows or columns are in a series or data frame:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(5,)" ] }, "execution_count": 14, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series.shape" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(3, 3)" ] }, "execution_count": 15, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame.shape" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "To get just the number of rows or just the number of columns, you can use `[0]` after for the number of rows or `[1]` for the number of columns:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 16, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series.shape[0]" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 17, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame.shape[0]" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 18, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame.shape[1]" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "It's not always clear if you are working with a series or data frame. You can use `type` to see what a piece of data is." ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "pandas.core.series.Series" ] }, "execution_count": 19, "metadata": { }, "output_type": "execute_result" } ], "source": [ "type(series)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "pandas.core.frame.DataFrame" ] }, "execution_count": 20, "metadata": { }, "output_type": "execute_result" } ], "source": [ "type(frame)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "For example, getting a row or column out of a data frame will give you a series:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "pandas.core.series.Series" ] }, "execution_count": 21, "metadata": { }, "output_type": "execute_result" } ], "source": [ "type(frame['b'])" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "pandas.core.series.Series" ] }, "execution_count": 22, "metadata": { }, "output_type": "execute_result" } ], "source": [ "type(frame.loc[1])" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "### How to find the mean, median, etc. of a data frame or series\n", "\n", "Typically you will get the mean or median of a specific row of a data frame, which as we saw above is a series. We do that like this:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "42.0" ] }, "execution_count": 23, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series.mean()" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "4.0" ] }, "execution_count": 24, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame['a'].median()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "The `.0` at the end means that the value is being treated as a *float*, which is Python's way of representing decimal numbers. If you need to use an integer for whatever reason, you can use `int`:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "45" ] }, "execution_count": 25, "metadata": { }, "output_type": "execute_result" } ], "source": [ "int(series.median())" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "You can get the maximum and minimum values with `max` and `min`." ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "75" ] }, "execution_count": 26, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series.max()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "For a data frame, this will compute the maximum and minimum for *each column* by default:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "a 1\n", "b 2\n", "c 3\n", "dtype: int64" ] }, "execution_count": 27, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame.min()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "Another useful thing you can do is to sum the values in a series." ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "210" ] }, "execution_count": 28, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series.sum()" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "### Making changes to series or data frames\n", "\n", "If you assign a series to another variable, it *does not copy the series*. Any change you make to that variable will affect the original series." ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 4\n", "1 36\n", "2 45\n", "3 50\n", "4 75\n", "dtype: int64" ] }, "execution_count": 29, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 4\n", "1 42\n", "2 45\n", "3 50\n", "4 75\n", "dtype: int64" ] }, "execution_count": 30, "metadata": { }, "output_type": "execute_result" } ], "source": [ "copy = series\n", "copy[1] = 42\n", "series" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "Let's set that back to its original value:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 4\n", "1 36\n", "2 45\n", "3 50\n", "4 75\n", "dtype: int64" ] }, "execution_count": 31, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series[1] = 36\n", "series" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "If you need to keep the original values, use `copy`:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 4\n", "1 42\n", "2 45\n", "3 50\n", "4 75\n", "dtype: int64" ] }, "execution_count": 32, "metadata": { }, "output_type": "execute_result" } ], "source": [ "copy = series.copy()\n", "copy[1] = 42\n", "copy" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "Now `copy` and `series` are different:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 4\n", "1 36\n", "2 45\n", "3 50\n", "4 75\n", "dtype: int64" ] }, "execution_count": 33, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "### How to only get cells that match a certain condition\n", "\n", "You can actually compare series or data frames to values to get a frame of `True` and `False` values that reflect that comparison:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
abc
0FalseFalseFalse
1FalseFalseTrue
2TrueTrueTrue
\n", "
" ], "text/plain": [ " a b c\n", "0 False False False\n", "1 False False True\n", "2 True True True" ] }, "execution_count": 34, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame > 5" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "You can use these to get only the cells that match that condition:" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2 45\n", "3 50\n", "4 75\n", "dtype: int64" ] }, "execution_count": 35, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series[series > 40]" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "### How to check equality\n", "\n", "If you want to check that two series are equal, using `==` won't work as you expect:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 True\n", "1 False\n", "2 True\n", "3 True\n", "4 True\n", "dtype: bool" ] }, "execution_count": 36, "metadata": { }, "output_type": "execute_result" } ], "source": [ "other_series = pd.Series([4, 42, 45, 50, 75])\n", "series == other_series" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "To just get a yes or no answer as to whether two series match completely, use `equals`:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 37, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series.equals(other_series)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "### How to read CSV files\n", "\n", "A CSV (*comma-separated values*) file contains data that typically looks like this:\n", "\n", "```\n", "a,b,c\n", "1,2,3\n", "4,5,6\n", "7,8,9\n", "```\n", "\n", "You can read these values using `read_csv`:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
abc
0345
151213
281517
372425
\n", "
" ], "text/plain": [ " a b c\n", "0 3 4 5\n", "1 5 12 13\n", "2 8 15 17\n", "3 7 24 25" ] }, "execution_count": 38, "metadata": { }, "output_type": "execute_result" } ], "source": [ "frame_from_file = pd.read_csv('data.csv')\n", "frame_from_file" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "The function automatically detects column headers." ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "## Debugging\n", "\n", "If something does not go as you expect, you should start by thinking about (and maybe writing down) what you expect to have happened versus what did happen.\n", "\n", "Let's go back to an earlier example error:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "collapsed": false }, "outputs": [ { "ename": "KeyError", "evalue": "1", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/srv/conda/envs/notebook/lib/python3.7/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 2896\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2897\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2898\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", "\u001b[0;31mKeyError\u001b[0m: 1", "\nDuring handling of the above exception, another exception occurred:\n", "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# This will result in an error\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mframe\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m/srv/conda/envs/notebook/lib/python3.7/site-packages/pandas/core/frame.py\u001b[0m in \u001b[0;36m__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 2978\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnlevels\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2979\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_getitem_multilevel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2980\u001b[0;31m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcolumns\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2981\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mis_integer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2982\u001b[0m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mindexer\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/srv/conda/envs/notebook/lib/python3.7/site-packages/pandas/core/indexes/base.py\u001b[0m in \u001b[0;36mget_loc\u001b[0;34m(self, key, method, tolerance)\u001b[0m\n\u001b[1;32m 2897\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2898\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2899\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_loc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_maybe_cast_indexer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2900\u001b[0m \u001b[0mindexer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_indexer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mkey\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtolerance\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtolerance\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2901\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mindexer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mndim\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mindexer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msize\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/index.pyx\u001b[0m in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", "\u001b[0;32mpandas/_libs/hashtable_class_helper.pxi\u001b[0m in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n", "\u001b[0;31mKeyError\u001b[0m: 1" ] } ], "source": [ "# This will result in an error\n", "frame[1]" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "The very last line tells us what the specific error was: `KeyError: 1`. If you are new to Python, this is probably not very helpful. But if we figure out *where* the error happened, we might be able to get a better sense of *what* the error actually was. Error messages in Python usually include a *traceback* (mentioned near the top), which roughly describe all the functions that are executing when this error occurs.\n", "\n", "Above the last line, there are lines that look like `some/folder/file.ext in some.python.function()`. We can see that the files look like `pandas/_libs/...` which means that the traceback is looking through code that is part of the Pandas library. The error is probably not here, since we can be reasonably sure that the Pandas authors did a good job. Very occasionally there is a mistake in the library itself, but you should assume that this is almost certainly not the case.\n", "\n", "If we continue up from the bottom, we see the traceback go through `/srv/conda/envs/notebook/lib/python3.7/site-packages/pandas/core/indexes/base.py` with lines of code beneath. The filename indicates that we are in the Anaconda environment, which is also probably not the cause of the error.\n", "\n", "Finally, we see this:\n", "```\n", " in \n", " 1 # This will result in an error\n", "----> 2 frame[1]\n", "```\n", "\n", "The `` means that this is happening in a Jupyter cell. In fact, the lines that follow are what I typed into the cell. The error message is pointing at the statement `frame[1]`, which indicates that this line is responsible for the error. Generally, you should take the line that is closest to the bottom and not part of library code to be the source of the error.\n", "\n", "In case you are curious, when you type something like `frame[1]`, the `1` is called the *key*. So `KeyError: 1` means that in `frame`, the use of `1` as a key failed. Intuitively, this means that `frame` does not have a column named `1` and therefore Python doesn't know how to satisfy your request for `frame[1]`." ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "## Implementation\n", "\n", "**Always know what your code should be doing before you implement a function.** If you cannot articulate what your function is supposed to do, then you should stop writing that function until you can sketch out what the function does.\n", "\n", "It is often helpful to start by documenting your function before you write any code in the body of the function. You can use the `pass` keyword to avoid errors about not having written any code in the function." ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "collapsed": false }, "outputs": [ ], "source": [ "def relative_to_mean(series):\n", " \"\"\"\n", " Compute the proportion of each of a series's cell values relative to the mean.\n", " \n", " Args:\n", " series: the Pandas series containing the input data values.\n", " \n", " Returns:\n", " A Pandas series where each cell's value is the original cell's value relative to the series's mean.\n", " \"\"\"\n", " pass" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "It can also be helpful to write a test function that will tell you if your function is doing what you expect." ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "collapsed": false }, "outputs": [ ], "source": [ "def test_relative_to_mean(relative_to_mean):\n", " series = pd.Series([4, 36, 45, 50, 75])\n", " expected_results = pd.Series([4 / 42, 36 / 42, 45 / 42, 50 / 42, 75 / 42])\n", " return expected_results.equals(relative_to_mean(series))" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "Obviously, this will not work now:" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 42, "metadata": { }, "output_type": "execute_result" } ], "source": [ "test_relative_to_mean(relative_to_mean)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "We can start implementing by writing a series of comments that break the function into its major steps." ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "collapsed": false }, "outputs": [ ], "source": [ "def relative_to_mean(series):\n", " \"\"\"\n", " Compute the proportion of each of a series's cell values relative to the mean.\n", " \n", " Args:\n", " series: the Pandas series containing the input data values.\n", " \n", " Returns:\n", " A Pandas series where each cell's value is the original cell's value relative to the series's mean.\n", " \"\"\"\n", " # Calculate the mean of the series.\n", " # Divide each cell value by the mean.\n", " # Return the results.\n", " pass" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "We know how to do the first step, so we can write the first line of code. We can also take out `pass` once we write the first line:" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "collapsed": false }, "outputs": [ ], "source": [ "def relative_to_mean(series):\n", " \"\"\"\n", " Compute the proportion of each of a series's cell values relative to the mean.\n", " \n", " Args:\n", " series: the Pandas series containing the input data values.\n", " \n", " Returns:\n", " A Pandas series where each cell's value is the original cell's value relative to the series's mean.\n", " \"\"\"\n", " # Calculate the mean of the series.\n", " avg = series.mean()\n", " # Divide each cell value by the mean.\n", " # Return the results." ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "How do we divide each cell value by the mean? To do this, I actually looked at the documentation for Pandas series and did a Ctrl-F search for \"divide\". I found a function called `div`, which has its own [documentation](https://pandas.pydata.org/pandas-docs/version/0.25/reference/api/pandas.Series.div.html#pandas.Series.div). It says that `other` can be a scalar value, so let's try putting a single integer." ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "0 2.0\n", "1 18.0\n", "2 22.5\n", "3 25.0\n", "4 37.5\n", "dtype: float64" ] }, "execution_count": 45, "metadata": { }, "output_type": "execute_result" } ], "source": [ "series.div(2)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "Nice! So now we can add the second line of code to the function:" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "collapsed": false }, "outputs": [ ], "source": [ "def relative_to_mean(series):\n", " \"\"\"\n", " Compute the proportion of each of a series's cell values relative to the mean.\n", " \n", " Args:\n", " series: the Pandas series containing the input data values.\n", " \n", " Returns:\n", " A Pandas series where each cell's value is the original cell's value relative to the series's mean.\n", " \"\"\"\n", " # Calculate the mean of the series.\n", " avg = series.mean()\n", " # Divide each cell value by the mean.\n", " divided_series = series.div(avg)\n", " # Return the results." ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "Finally, we just need to return the variable we just made." ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "collapsed": false }, "outputs": [ ], "source": [ "def relative_to_mean(series):\n", " \"\"\"\n", " Compute the proportion of each of a series's cell values relative to the mean.\n", " \n", " Args:\n", " series: the Pandas series containing the input data values.\n", " \n", " Returns:\n", " A Pandas series where each cell's value is the original cell's value relative to the series's mean.\n", " \"\"\"\n", " # Calculate the mean of the series.\n", " avg = series.mean()\n", " # Divide each cell value by the mean.\n", " divided_series = series.div(avg)\n", " # Return the results.\n", " return divided_series" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "We can take out the comments for a short function like this. If it takes many lines of code to do each major step, we might want to leave in those comments. One way I personally use to decide whether to keep the comments in is to ask myself how obvious the code would be to someone who knows more Python than me. If I don't think it would be obvious (particularly *why* I wrote that code), I leave the comment in.\n", "\n", "In this case, we can just take it out, so our final function looks like this:" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "collapsed": false }, "outputs": [ ], "source": [ "def relative_to_mean(series):\n", " \"\"\"\n", " Compute the proportion of each of a series's cell values relative to the mean.\n", " \n", " Args:\n", " series: the Pandas series containing the input data values.\n", " \n", " Returns:\n", " A Pandas series where each cell's value is the original cell's value relative to the series's mean.\n", " \"\"\"\n", " avg = series.mean()\n", " divided_series = series.div(avg)\n", " return divided_series" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "### Jupyter Pitfalls\n", "\n", "When you work in Jupyter notebooks, errors can sometimes be a bit unintuitive.\n", "\n", "### Out-of-Order Execution\n", "\n", "If you see this:\n", "\n", "```\n", "In [42]: x = 42\n", "\n", "In [41]: x = 3.14\n", "```\n", "\n", "What will the value of `x` be?\n", "\n", "```\n", "In [43]: x\n", "Out [43]: 42\n", "```\n", "\n", "This is because the `In[42]` indicates that it ran more recently than `In[41]`, so even though it appears before, the current value of `x` is 42.\n", "\n", "If you suspect this has happened and is causing an error, you can select a cell, and then use `Cell -> Run All Above` in the top menu to run all the cells above that one in order. Sometimes, this can get the state of the notebook closer to what you expect it to be, which will in turn make finding the bug easier.\n", "\n", "### Repeated Variable Names\n", "\n", "**Avoid repeating variable names within a notebook if possible.**\n", "\n", "This can cause your errors to appear as if they are something completely different. For example, if you make a state object with sample values, like `state = make_state(1, 2, 3)`, and then write something like `make_state(42, 2, 100)` (note that it is not assigned to the variable), when you run your simulation like `run_simulation(state, system)`, you are going to get completely wrong results. It will look like the error is in the code that runs your simulation, even though the real error is that you forgot to assign your new state to a variable.\n", "\n", "This also illustrates another pitfall of repeating variable names: it can cause your code to appear to succeed, even if your code is wrong." ] } ], "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.7.3" } }, "nbformat": 4, "nbformat_minor": 0 }