Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Open In Colab Open In Kaggle

Exercise 1: A DataFrame and a column mean

Build a DataFrame with columns temp_celsius = [18.2, 17.5, 19.1, 16.8] and discharge_m3s = [48.0, 51.2, 47.5, 53.1]. Print the column dtypes and the mean temperature, rounded to two decimals.

Exercise 2: Write and read a CSV with dates

Build a DataFrame with a date column ("2024-06-01", "2024-06-02", "2024-06-03") and a temp_celsius column. Write it to _files/obs.csv without the index, then read it back with parse_dates=["date"] and print the dtypes.

Exercise 3: Label, position, and mask

Given

df = pd.DataFrame({"station": ["BAS", "LUG", "JFJ"], "temp_celsius": [18.0, 21.0, -1.0]},
                  index=["a", "b", "c"])

print the temperature at label "b", the whole first row by position, and all rows whose temperature is below 0 °C.

Exercise 4: Resample and rolling

Build a 40-day daily Series indexed by date (np.random.default_rng(0), mean 18, std 2). Print the monthly means and the first five values of the 3-day rolling mean, both rounded to two decimals.

Exercise 5: Group and aggregate

Given

df = pd.DataFrame({"station": ["BAS", "BAS", "LUG", "LUG"],
                   "temp_celsius": [18.0, 19.0, 21.0, 22.0]})

compute the mean temperature per station and print it as a dict.

Exercise 6: Handle a gap three ways

Given s = pd.Series([1.0, np.nan, np.nan, 4.0, 5.0]), print the forward-filled series, the linearly interpolated series, and the NaN-skipping mean. Note in a comment why the three differ.

Exercise 7: Join two tables

Given an observations table and a metadata table that share a station key, left-join the elevation onto the observations and print the result.

obs = pd.DataFrame({"station": ["BAS", "LUG"], "temp_celsius": [18.0, 21.0]})
meta = pd.DataFrame({"station": ["BAS", "LUG"], "elevation_m": [316, 273]})

Exercise 8: A log-scale axis, and counting past a threshold

River discharge is a classic right-skewed variable: most days sit near base flow, with a long tail of rare, much larger flood events.

rng = np.random.default_rng(1)
discharge_m3s = pd.Series(np.exp(rng.normal(3.4, 1.3, 300)))
  1. Plot a histogram of discharge_m3s with .plot(kind="hist"), on default (linear) axes, then again with logy=True. Which view makes the long tail easier to read?

  2. Build a boolean mask for discharge above 100 m3 s-1 (a “flood” threshold), filter discharge_m3s with it, and print how many of the 300 values exceed it.

Exercise 9: Filtered vs. unfiltered histogram

rng = np.random.default_rng(0)
temp_celsius = pd.Series(rng.normal(18.0, 2.0, 200))
temp_celsius[:5] = -999.0     # a stuck sensor: five obviously invalid readings
  1. Plot a histogram of the raw temp_celsius values with .plot(kind="hist"). What does the stuck sensor do to the plot?

  2. Build a boolean mask that keeps only values above −50 °C, filter the Series with it, and plot the histogram again. In one comment, say which of the two plots you would trust.

Exercise 10: Earthquake data analysis

A dirt track through a vineyard, broken along its length by a continuous ridge of pushed-up soil following the fault trace

Figure 1:Surface rupture from the magnitude 6.0 South Napa earthquake of 24 August 2014 — the kind of event a row in this catalog stands for. The continuous “mole track” running parallel to the strike of the fault indicates some east–west compression on top of the right-lateral faulting; taken near Buhman Road. Photo USGS, public domain.

This exercise reviews the pandas fundamentals of this subchapter on one real catalog, covering how to

  • open csv files

  • manipulate dataframe indexes

  • parse date columns

  • examine basic dataframe statistics

  • manipulate text columns and extract values

  • plot dataframe contents using

    • bar charts

    • histograms

    • scatter plots

The data is a snapshot of the USGS Earthquakes Database: every event recorded worldwide in 2014, 120 108 rows.

You do not need to download the file yourself. The pre-supplied cell below fetches and caches it with the help of pooch — there is no need to read pooch’s documentation unless you want to — and stores the path to the file in the variable datafile.

Q1) First, import numpy, pandas and matplotlib, and — optionally — set the display options.

Hint: display options are documented at this link.

Q2) Use pandas’ read_csv function directly on datafile to open it as a DataFrame.

Display the first few rows with .head(), and the column names, dtypes and non-null counts with .info(). Check these tutorials if you have doubts about what the two functions do: .head() and .info().

.info() will show you that the two date columns, time and updated, came in as plain strings rather than as dates. They were not parsed automatically. What can you do about that?

Q3) Re-read the data in such a way that both date columns are identified as dates and the earthquake ID is used as the index.

Check with .head() and .info() that it worked: time and updated should now be datetime64 columns, and id should be the index rather than a column.

Hint: the documentation for read_csv is here.

Q4) Use describe to get the basic statistics of all the columns.

Hint: the documentation of describe is at this link.

Q5) Use nlargest to get the top 20 earthquakes by magnitude.

Hint: the documentation of nlargest is at this link.

Q6) Extract the state or country using pandas’ text data functions, and add it as a new column to the DataFrame.

Examine the column titled place: it holds strings like "26km S of Redoubt Volcano, Alaska", so it carries both the local description and the state or country. Pull the second part out and store it in a new column called country.

Hint 1: the documentation for pandas’ text data functions is here.

Hint 2: you will use .split() to extract the country names. The documentation of this function can be found here.

Q7) Display each unique value from the new country column.

Hint: you may use the unique function documented at this link.

You should see an array of a couple of hundred country and state names. A plain split leaves the space that followed the comma, so they come out as array([' Alaska', ' Nevada', ...]) — worth removing before you use them as labels.

Q8) Create a filtered dataset that only has earthquakes larger than magnitude 4.

Hint: print the table to see the name of the column containing the earthquake magnitude.

Check out this link to find examples of filtering by column values.

Q9) Using the filtered dataset (magnitude > 4), count the number of earthquakes whose magnitudes are above 4 [Num 1], and count the number of earthquakes in each country or state [Num 2]. Make a bar chart of Num 2 for the top 5 locations with the most earthquakes.

Hint 1: to get Num 1, pandas has a count function documented at this link.

Hint 2: check out the value_counts function to get Num 2.

Then convert the first five rows of Num 2 into a DataFrame with two columns, country (text) and earthquake_num (number), and recreate the bar chart below.

A bar chart of the number of magnitude-above-4 earthquakes in the five countries with the most of them

Figure 2:The five locations with the most magnitude-above-4 events in 2014.

Q10) Make a histogram for the distribution of the earthquakes’ magnitudes.

Hint: pandas has a histogram function documented at this link and matplotlib has one documented at this link.

A histogram of earthquake magnitude with a dashed grid

Figure 3:The distribution of magnitude across the whole catalog.

Then redraw it with a logarithmic scale on the y-axis, which brings the rare large events into view alongside the many small ones. Hint: here you can find a tutorial for how to change an axis scale.

The same histogram of earthquake magnitude with a logarithmic y-axis

Figure 4:The same histogram with a logarithmic count axis.

Finally, make one histogram for the filtered dataset and one for the unfiltered dataset, side by side.

Two histograms of earthquake magnitude side by side, one for events above magnitude 4 and one for the whole catalog

Figure 5:The filtered and unfiltered magnitude distributions, drawn on their own count axes.

Q11) Visualize the locations of earthquakes by making a scatterplot of their latitude and longitude.

Make a figure with two panels: one for the filtered dataset and one for the unfiltered one, with the points coloured by magnitude on a shared colour range.

Hint: consider reading the documentation for plt.scatter to make the scatter plot and that of plt.colorbar to colour the points by magnitude.

Two scatter plots of earthquake longitude against latitude coloured by magnitude, one filtered to magnitude above 4 and one unfiltered

Figure 6:Every event in the catalog placed by longitude and latitude, filtered and unfiltered.

Do you notice a difference between the filtered and unfiltered datasets?