{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "tags": [ "remove-cell" ] }, "outputs": [], "source": [ "import babypandas as bpd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Accessing and Sorting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Cedar Fire left an indelible mark on San Diego county. When it happened in 2003, it was the largest wildfire in California history. Just how big was the fire? And what caused it? The data set we saw in the previous section has these answers, but we still need to learn how to retrieve this information." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{figure} ../images/cedar.jpg\n", "---\n", "height: 300px\n", "---\n", "Cars scramble to leave the 15 as the Cedar Fire crosses the highway and approaches Miramar.\n", "\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Accessing with `.loc`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's begin by reading our dataset from a CSV and setting the `'name'` column to be the index:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "calfire = bpd.read_csv('data/calfire.csv').set_index('name')\n", "calfire" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "How big was the Cedar Fire? We know that we can retrieve the `'acres'` column using the `.get` method:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "calfire.get('acres')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The result is a series. We don't see the Cedar Fire listed; it *is* there, just hidden within the `...`. \n", "\n", "We can retrieve an element from a Series using its row label and the special `.loc` attribute. Since it looks like all the fires have their names capitalized, the row label for the Cedar Fire will be `CEDAR`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "calfire.get('acres').loc['CEDAR']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice the square brackets in `.loc['CEDAR']`. This is by analogy with using square brackets to retrieve elements from an array.\n", "\n", "To repeat, we can retrieve a particular element in a table, such as the size of the Cedar Fire, by first `.get`ting the column containing the fire sizes, then using `.loc` to retrieve the size corresponding to the Cedar Fire. This is a pattern that we'll be using over and over:\n", "\n", "1. `.get()` with the column label; then\n", "2. `.loc[]` with the row label\n", "\n", "Let's try it again: what was the cause of the Cedar Fire?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "calfire.get('cause').loc['CEDAR']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Originally, the Cedar Fire was to believed to be caused by a lost hunter shooting their rifle to get the attention of rescuers -- thus the cause is listed as \"Equipment Use\". However, the hunter later admitted that they had started a signal fire to alert rescuers, and that it quickly spread out of control." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Question**:\n", " What code would you write to determine the county in which the Frying Pan Fire occurred?\n", "\n", "
Answer:`calfire.get('county').loc['FRYING PAN']`
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Cedar Fire was truly huge, stretching from the Cuyamaca Mountains in eastern San Diego County, almost to the Pacific Ocean. But most of us don't have a good sense of what an \"acre\" is. Instead, let's frame the size of the fire in terms of other things we might be more familiar with. For instance, a soccer field is 1.32 acres. Therefore, the Cedar Fire burned:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(calfire.get('acres').loc['CEDAR'] / 1.32, 'soccer fields.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other comparisons are perhaps more surprising. The Cedar Fire burned:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(calfire.get('acres').loc['CEDAR'] / 1_976, 'times the size of UCSD\\'s campus.')\n", "print(calfire.get('acres').loc['CEDAR'] / 14_600, 'times the size of Manhattan.')\n", "print(calfire.get('acres').loc['CEDAR'] / 382_000, 'times the size of the island of Oahu.')\n", "print(calfire.get('acres').loc['CEDAR'] / 2.9e6 * 100, 'percent of San Diego county.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sorting\n", "\n", "While the Cedar Fire was the largest fire in California history when it occurred in 2003, it has since been surpassed. If it wasn't the largest fire, what was?\n", "\n", "One way to answer this question is to sort the table by the size of the fires. We can do this with the `.sort_values` DataFrame method. The method requires one keyword argument, `by=`, which should be given a string with the name of the column to sort by:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "calfire.sort_values(by='acres')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that the table has been sorted in *ascending* order (from smallest to largest) using the values in the `'acres'` column. Therefore, we see that the largest fire in California history was the Ranch Fire. At 410,202 acres, the Ranch fire was *double* the size of the Cedar Fire. It was part of the Mendocino Complex Fire, which burned in 2019. Although the cause of the fire is listed here as undetermined, it was later discovered that it began when a person tried to plug the entrance of wasp's nest with a hammer and a metal stake. When they hammered the stake, sparks flew and caught the ground on fire. The fire resulted in $250 million in damages." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What if we want to come to the same conclusion *programatically*, without having to look at the table? After sorting, the last row of the table corresponds to the largest fire, and we want the fire's name. This is stored in the {dterm}`table index`. Remember that the index is essentially an array, and so we can get the last element of the array using square bracket notation:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "calfire.sort_values(by='acres').index[-1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, we are using {dterm}`method chaining` to save typing." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{margin}\n", "\n", "Actually, we do not need to include the `by=` in this case: calling `.sort_values('acres')` will work just fine. But writing `by=` makes the code more *readable*.\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sorting in *descending* order" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We could have also made the same discovery by sorting the table in *descending* order. This is done by passing a second keyword argument: `ascending=False`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "calfire.sort_values(by='acres', ascending=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If this keyword argument isn't given, it defaults to `ascending=True`.\n", "\n", "When sorting in descending order, we could get the fire's name from the index by asking for the first row label:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "calfire.sort_values(by='acres', ascending=False).index[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also sort by columns containing strings. In this case, the rows are sorted *lexicographically* -- that is, in dictionary order:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "calfire.sort_values(by='county')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sorting by multiple columns" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you look at the help message for `.sort_values`, you'll see that it can also accept a *list* of column names to sort by, like this:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "calfire.sort_values(by=['year', 'acres'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this case, the resulting table will be sorted by the `'year'` column, but within each year the fires will be grouped by their size in the `'acres'` column. Take a look: the fires occurring in 2018 are organized from smallest to largest. Sorting like this is mostly used for presentation purposes." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Accessing with `.iloc`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "How large was the oldest fire in the data set? There are two approaches to answering this question. The first approach uses tools that we already know, but it requires a little extra work. The second approach uses something new: `.iloc`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Approach #1: with `.loc`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the first approach, we'll first find the name of the oldest fire in the data set. We'll then use this name to ask for the size of the fire using our `.get().loc[]` pattern.\n", "\n", "To get the name of the oldest fire, we'll sort by year and look at the first element of the index:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "oldest_fire_name = calfire.sort_values(by='year').index[0]\n", "oldest_fire_name" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we'll use this as the row label in looking up the acreage:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "calfire.get('acres').loc[oldest_fire_name]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This approach works, but there is a faster way." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Approach #2: with `.iloc`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "After we sort the table by year, we know that the row we're interested in is the first row in the table. But to access the entries of this row with `.loc`, we need to first find out that row's label. Instead of performing this intermediate step, we can get the first row's information directly with `.iloc`.\n", "\n", "Whereas `.loc` looks up a row by its label, `.iloc` looks up a row by its *integer position* (thus the *i* in `iloc`). For instance, suppose we have sorted the table by year and retrieved the acreage column:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sizes = calfire.sort_values(by='year').get('acres')\n", "sizes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To get the size of the first fire, we can use `.iloc` directly, without knowing the fire's name." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sizes.iloc[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is equivalent to using `.loc` with the column name:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sizes.loc['GLASS MOUNTAIN']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To summarize, `.loc` retrieves information using the row label. `.iloc` retrieves information using integer position. It is typically more convenient to use `.loc` with the row label, but sometimes `.iloc` is preferable." ] } ], "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": 4 }