Goal
Use Olympics medals/athletes data to:
- Rank countries by medals
- See trends over years
- Identify top sports
Analysis pipeline
flowchart LR A["Raw results"] --> B["Count
(medals per country)"] B --> C["Rank
(sort_values, top 10)"] C --> D["Visualize
(bar chart)"] D --> E["Trend
(medals by year)"]
Step 1: Load
import pandas as pd
df = pd.read_csv("data/olympics.csv")
print(df.head())Step 2: Basic counts
medals = df.groupby("country").size().sort_values(ascending=False).head(10)
print(medals)Step 3: Plot top countries
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 4))
plt.bar(medals.index, medals.values)
plt.title("Top 10 countries by medals")
plt.xticks(rotation=25)
plt.tight_layout()
plt.show()Visualize it
Deliverable
- Top 10 countries
- Change over years
- Sports that contribute most
What one row means
Before you count anything, find out what a row represents. In a medals file, one row might be one athlete's medal, one team's medal, or one country's total for a year. The answer changes the numbers. In a team event such as relay, each team member may have their own row, so counting rows would give a country four medals for one race. Look at df.head() and df.columns, then decide what "one medal" means and remove duplicates if needed (for example with drop_duplicates on event, year and country).
Ranking countries
The one-line ranking from the lesson works in three steps: groupby("country") splits rows by country, .size() counts the rows in each group, and sort_values(ascending=False).head(10) orders them and keeps the top ten. Here is the same idea on a tiny table you can run:
import pandas as pd
df = pd.DataFrame({
"country": ["USA", "USA", "CHN", "CHN", "CHN", "GBR", "USA", "GBR"],
"year": [2016, 2020, 2016, 2020, 2020, 2016, 2020, 2020],
"medal": ["Gold", "Silver", "Gold", "Gold", "Bronze", "Silver", "Gold", "Gold"],
})
top = df.groupby("country").size().sort_values(ascending=False)
print(top)
# USA 3
# CHN 3
# GBR 2Two countries can tie, and the order between tied countries is not guaranteed unless you add a second sort key. For a fair ranking, sort by gold medals first and total second.
Trends over the years
To see change over time, group by two columns and reshape with unstack, so each country becomes a line:
by_year = df.groupby(["year", "country"]).size().unstack(fill_value=0)
print(by_year)
# country CHN GBR USA
# year
# 2016 1 1 1
# 2020 2 1 2fill_value=0 matters: a country with no medals in a year would otherwise show NaN. Plotting by_year.plot() then draws one line per country.
Common mistakes
- Counting rows when rows are athletes. Team medals get counted many times.
- Comparing raw totals across eras. Games have added events over time, so also look at the share of all medals.
- Mixing country names and codes, such as "United States" and "USA", which splits one country into two groups.
- Missing values in the medal column. Rows for athletes who did not medal may be included; filter them out with
dropna(subset=["medal"]). - Plotting too many bars. Show the top 10 so labels stay readable.
Turning it into findings
State each result as a plain sentence: which countries lead, how their share changed, and which sports drive it. Then check the finding by looking at one country and one sport by hand, to make sure the pipeline agrees with common sense.
Check your understanding
What does df.groupby("country").size().sort_values(ascending=False).head(10) return?
It splits by country, counts rows per group, sorts descending and keeps the top ten.
Show answer
A โ The ten countries with the most rows (medals) โ It splits by country, counts rows per group, sorts descending and keeps the top ten.
In the small example, USA and CHN both have 3 medals. What should you do for a fair ranking?
The order of ties is not guaranteed unless you add a tiebreaker.
Show answer
A โ Add a second sort key such as gold medals โ The order of ties is not guaranteed unless you add a tiebreaker.
Why use unstack(fill_value=0) on the year by country counts?
unstack makes one column per country, and fill_value=0 turns the gaps into zeros.
Show answer
A โ A country with no medals in a year would otherwise show NaN โ unstack makes one column per country, and fill_value=0 turns the gaps into zeros.
What is the risk of counting rows when each row is an athlete?
First find out what one row means, since a team medal may appear once per athlete.
Show answer
A โ Team medals are counted many times โ First find out what one row means, since a team medal may appear once per athlete.
๐งช Try It Yourself
Exercise 1 โ Medal counts per country
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Exercise 2 โ Top N ranking
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Exercise 3 โ Medals by year (trend)
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.