Counting & Uniques: value_counts, unique, nunique

value_counts() tallies how often each distinct value appears in a column, giving you an instant frequency table — the workhorse of exploratory data analysis.

Learn Counting & Uniques: value_counts, unique, nunique in our free Pandas course — a beginner-friendly interactive lesson with worked examples, a practice…

Part of the free Pandas course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Learn to count categories, turn counts into percentages with normalize=, include missing values with dropna=False, and list distinct values with unique() and nunique().

Call value_counts() on a Series and pandas counts how many times each distinct value appears, then hands back the tallies sorted from most common to least. It is the first thing analysts run on a new categorical column: one line tells you the mode, the spread, and whether any category dominates.

Two arguments make value_counts far more useful. normalize=True converts the raw counts into proportions that add up to 1 — multiply by 100 and you have percentages, perfect for "what share of customers are on each plan?" And dropna=False stops pandas from hiding the gaps: missing values appear as their own NaN row so you can see how incomplete a column really is.

When you do not need the counts, just the distinct values, reach for unique() and nunique() . unique() returns an array of the actual distinct values — useful for spotting typos and stray categories. nunique() returns a single number: how many distinct values exist. That count, called cardinality, tells you whether a column is a good candidate for the category dtype or a grouping key.

❌ Calling value_counts on a whole DataFrame by mistake

You wanted to count one column but passed the frame:

Your counts do not add up to the row total because NaN was dropped:

Quickly profile a column of responses for an EDA report.

Lesson complete — you can profile any column!

You can build frequency tables with value_counts() , switch to shares with normalize=True , expose gaps with dropna=False , and measure distinctness with unique() and nunique() .

🚀 Up next: Filtering with query() — write readable filters as plain-English strings.

Practice quiz

What does s.value_counts() return?

  • The number of rows
  • A frequency table of how often each value appears
  • The unique values only
  • The column mean

Answer: A frequency table of how often each value appears. value_counts() tallies each distinct value's frequency.

How is value_counts() ordered by default?

  • Alphabetically
  • By the index labels
  • From most frequent to least frequent
  • Randomly

Answer: From most frequent to least frequent. It sorts descending by count, so the top row is the mode.

What does normalize=True do?

  • Sorts the result
  • Removes missing values
  • Capitalises labels
  • Converts counts to proportions that sum to 1

Answer: Converts counts to proportions that sum to 1. normalize=True returns each value's share as a fraction.

Which argument makes NaN appear as its own row?

  • dropna=False
  • include_na=True
  • keepna=True
  • na='show'

Answer: dropna=False. dropna=False stops pandas hiding the missing values.

Does value_counts() include NaN by default?

  • Always
  • No, it drops NaN unless told otherwise
  • Only for numeric columns
  • Only the first NaN

Answer: No, it drops NaN unless told otherwise. By default NaN is excluded; pass dropna=False to include it.

What does unique() return?

  • A single count
  • The most common value
  • An array of the distinct values
  • A sorted Series

Answer: An array of the distinct values. unique() lists the actual distinct values in the column.

What does nunique() return?

  • The distinct values
  • A frequency table
  • The first value
  • The count of distinct values (a single number)

Answer: The count of distinct values (a single number). nunique() reports how many distinct values exist (cardinality).

If value_counts(normalize=True) is computed with dropna=True, what is the denominator?

  • Only the non-missing rows
  • All rows including NaN
  • Always 100
  • The number of columns

Answer: Only the non-missing rows. Proportions are over non-null values unless you keep NaN in.

What is the result type of value_counts()?

  • A list
  • A dict
  • A Series (values as index, counts as values)
  • A DataFrame

Answer: A Series (values as index, counts as values). It returns a Series, so you can chain .head() or .plot.bar().

A low nunique() relative to row count suggests what?

  • The data is corrupted
  • Every value is unique
  • There are no repeats
  • Lots of repeats — a good 'category' dtype candidate

Answer: Lots of repeats — a good 'category' dtype candidate. Few distinct values among many rows means heavy repetition.