PD-01-013-P · Primer — Aggregations & value_counts
The idea in one sentence
Aggregation squeezes a whole column of numbers into a single answer (sum, mean, count), while value_counts squeezes a column of labels into a tally of how often each one appears.
Why it exists
A column can have thousands of rows, and your eyes cannot read thousands of rows. What you actually want is the headline: how much did we make in total?, what's the average order?, how many rows do we even have?, which city shows up most? Aggregations answer the first three by collapsing many values into one; value_counts answers the last by grouping identical labels and counting each group. They exist so you can go from raw data to a decision-ready summary in a single method call, instead of writing loops.
How it works
Every pandas Series (a single column) carries built-in summary methods that walk the whole column for you. Call .sum() to add every value, .mean() to average them, and .count() to tally the non-missing values. These three each return one number — the column has been "reduced." For text or category columns, .value_counts() instead returns a new Series: each unique label becomes an index entry, and its value is how many times it occurred, sorted from most common to least. Notice how the shape shrinks: a 5-row column becomes 1 number (for sum/mean/count) or a compact per-label tally (for value_counts).
import pandas as pd
df = pd.DataFrame({
'city': ['Austin', 'Austin', 'Denver', 'Austin', 'Denver'],
'amount': [120, 80, 200, 50, 90],
})
print(df['amount'].sum()) # 540
print(round(df['amount'].mean(), 1)) # 108.0
print(df['amount'].count()) # 5
print(df['city'].value_counts())
# city
# Austin 3
# Denver 2
# Name: count, dtype: int64
The one gotcha
.count() counts only non-missing values, not rows. If a column has NaN in it, .count() returns fewer than len(df) — and .mean() quietly skips those NaNs too when averaging. Likewise, value_counts() drops missing labels by default; pass dropna=False if you want the blanks counted as their own category. So "count" here means "how many real values," not "how many rows" — reach for len(df) when you truly want the row total.
See it — one column collapses into a summary
flowchart LR A["amount column<br/>(5 numbers)"] --> B["sum() -> 540"] A --> C["mean() -> 108.0"] A --> D["count() -> 5"] E["city column<br/>(5 labels)"] --> F["value_counts()<br/>Austin 3, Denver 2"]
The one-line takeaway
sum/mean/count reduce a number column to one value; value_counts reduces a label column to a sorted tally — and both skip missing data unless you tell them not to.
Where you'll meet it
The moment you load any real dataset, your first three moves are almost always df['col'].sum() to size the whole, df['col'].mean() to feel the typical, and df['category'].value_counts() to see which groups dominate — sanity checks that catch bad data before it reaches a chart or a report.
Named concepts: sum, mean, count, value_counts
