A Summary Table
What You Will Learn in This Lesson
By the end of this lesson, you will be able to:
- Build a table with one row per thing and one column per fact.
- Order it by the thing being compared.
- Include the group size.
- Say what the table does that the chart cannot.
Why This Matters
A chart shows the shape; the table pins the values. Together they answer both "what is the pattern" and "what exactly was the number", and the group size in the table is what stops a reader over-reading a bar built from two rows.
Step 1: One row per thing, one column per fact
The table under a chart is small on purpose: the few numbers the picture cannot state exactly, and the counts behind them.
Count and mean together
One group-by gives both. The count is not optional — it is what makes the mean interpretable.
import pandas as pd
df = pd.DataFrame({"team": ["a", "a", "b"], "score": [90.0, 80.0, 95.0]})
print(df.groupby("team")["score"].agg(["count", "mean"]).round(1))
Name the columns for a reader
"count" and "mean" are how it was computed. "students" and "mean score" are what it means.
import pandas as pd
df = pd.DataFrame({"team": ["a", "a", "b"], "score": [90.0, 80.0, 95.0]})
out = df.groupby("team").agg(
students=("score", "count"),
mean_score=("score", "mean"),
).round(1)
print(out)
Mini Practice #1: Count and mean, named
Try It YourselfProduce a summary with the columns named students and mean_score.
Step 2: Order it by the thing being compared
The first row should be the one the reader is looking for. Alphabetical order almost never is.
Sort by the value
Best first, so the ranking is visible without reading every row.
import pandas as pd
df = pd.DataFrame({"team": ["a", "a", "b"], "score": [90.0, 80.0, 95.0]})
out = df.groupby("team")["score"].agg(["count", "mean"]).round(1)
print(out.sort_values("mean", ascending=False))
And match the chart
If the bars are ordered by value, the table should be too. A reader moving between the two should not have to re-find each row.
import pandas as pd
df = pd.DataFrame({"team": ["zeta", "alpha", "mu"], "score": [70.0, 90.0, 80.0]})
order = df.groupby("team")["score"].mean().sort_values(ascending=False).index
print(list(order))
Mini Practice #2: Best first
Try It YourselfSort the same summary so the highest mean is the first row.
Step 3: When to Use It
Under a chart
The exact values the picture only shows approximately, with the group sizes.
df.groupby("team").agg(students=("score", "count"), mean_score=("score", "mean"))
When readers need to look things up
A short, sorted table answers “what exactly was it for my group”.
When Not to Use It
Do not paste the whole grouped output. A summary table that needs scrolling is data, not a summary — keep the few columns the question needs.
End-of-Lesson Exercises
Exercise 1: The table under the chart
Write summary_table(df) returning a list of (team, count, mean) tuples, highest mean first, with the mean to one decimal place.
Group once and ask for count and mean together, sort by the mean descending, then build plain tuples so the result is easy to compare.
Exercise 2: Groups too small to compare
Write thin_groups(df, least) returning the names of the teams with fewer than least rows, best mean first. These are the bars a reader should be warned about.
Group for count and mean, keep the rows whose count is below the threshold, sort what is left by mean descending, and return the index as a list.