Unit 8 • Lesson 6

Putting a Join to Work

Overview

Two files, one question, and the checks that keep the answer honest.

Intermediate 20–25 min

What You Will Learn in This Lesson

By the end of this lesson, you will be able to:

  • Take two files through to one summarised answer.
  • Put the checks in the right places.
  • Summarise last, after the joining and the cleaning.
  • Report the size of what you summarised.

Why This Matters

This is the unit assembled: read, check the keys, join, check the row count, then summarise. The order matters, because every check is cheap before the join and expensive afterwards — once a duplicate key has multiplied your rows, the total is wrong and nothing in the output says so.

Step 1: The shape of a real answer

Read both. Check the keys. Join with the how the question implies. Check the row count. Only then summarise.

1

Read, and look

Two files, four checks each — the habit from unit 5. The key columns get one extra look, because they are what the join depends on.

import pandas as pd
from io import StringIO

people = pd.read_csv(StringIO("id,team\n1,red\n2,red\n3,blue\n"))
scores = pd.read_csv(StringIO("id,score\n1,90\n2,80\n3,70\n"))

print(people.shape, scores.shape)
print(people["id"].dtype, scores["id"].dtype)
print("dupes:", int(people["id"].duplicated().sum()), int(scores["id"].duplicated().sum()))
2

Join, and check the count

You predicted one row per person. If the join gives more, a key was duplicated; if fewer, some did not match. Either way you want to know now.

import pandas as pd
from io import StringIO

people = pd.read_csv(StringIO("id,team\n1,red\n2,red\n3,blue\n"))
scores = pd.read_csv(StringIO("id,score\n1,90\n2,80\n3,70\n"))

out = pd.merge(people, scores, on="id", how="left")
print(len(out), "rows for", len(people), "people")

Mini Practice #1: Check before joining

Try It Yourself

Print the dtypes and the duplicate counts for both key columns before you join anything.

Press Run to see output

Step 2: Summarise last

Group only once the table is the one you meant. A mean over multiplied rows is wrong in a way that looks entirely reasonable.

1

The answer, with its size

The team means, and the number of people behind each — because a team of one is not a comparison.

import pandas as pd
from io import StringIO

people = pd.read_csv(StringIO("id,team\n1,red\n2,red\n3,blue\n"))
scores = pd.read_csv(StringIO("id,score\n1,90\n2,80\n3,70\n"))

out = pd.merge(people, scores, on="id", how="left")
print(out.groupby("team")["score"].agg(["mean", "size"]))
2

What a duplicate would have done

The same code with one duplicated score row. The red mean has not changed much, the size has doubled, and nothing raised.

import pandas as pd
from io import StringIO

people = pd.read_csv(StringIO("id,team\n1,red\n2,red\n3,blue\n"))
bad = pd.read_csv(StringIO("id,score\n1,90\n1,90\n2,80\n3,70\n"))

out = pd.merge(people, bad, on="id", how="left")
print(len(out), "rows for 3 people")
print(out.groupby("team")["score"].agg(["mean", "size"]))

Mini Practice #2: The answer and its size

Try It Yourself

Join these and produce the mean and the count per team in one result.

Press Run to see output

Step 3: When to Use It

Answers that need two files

Scores in one file, teams in another: read, clean, join, then summarise.

out = pd.merge(people, scores, on="id")

Reports you will rerun

A function over the file paths runs the same checks on next month’s files.

When Not to Use It

Do not join before cleaning the keys. An id kept as "007" in one file and turned into "7" in the other matches nothing, and the result is empty rather than an error.

End-of-Lesson Exercises

Exercise 1: Mean score per team, from two files

Two files are supplied: people.csv with id and team, and scores.csv with id and score. Write team_means(people_path, scores_path) returning a dictionary of team to mean score, rounded to one decimal place.

Read both, merge on id, group by team, take the mean of score, round it, then to_dict(). The second file set is different, so a typed-in answer fails.

Press Run to try it, then Check my work to mark it.

Exercise 2: Report the join, not just its result

Write join_report(people_path, scores_path) returning a three-element list of [people read, rows after a left join, people with no score]. The middle number differing from the first is how a duplicated key announces itself.

Read both, left join, and report len(people), len(joined) and the count of NaN in the score column. A left join cannot lose rows, so more rows than people means a key was duplicated.

Press Run to try it, then Check my work to mark it.