Unique Values & Counting
Reviewed & published by Brayan K
Counting is the task of finding the distinct values in an array and tallying how often each one appears, which NumPy makes a one-liner with np.unique, np.bincount, and np.count_nonzero.
Part of the free NumPy course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
You'll extract sorted distinct values, get per-value counts with return_counts, histogram small integers with bincount, and count condition matches with count_nonzero.
What You'll Learn in This Lesson
- Get sorted distinct values with np.unique
- Tally each value using return_counts=True
- Find first positions with return_index=True
- Histogram small integers with np.bincount
- Count condition matches with np.count_nonzero
- Build a value-to-count table in one step
1 np.unique — Sorted Distinct Values
np.unique(arr) returns the distinct values with duplicates removed, and the result is always sorted — even if the input was scrambled. It works on numbers and strings alike.
import numpy as np
arr = np.array([3, 1, 2, 1, 3, 3])
np.unique(arr) # [1 2 3] -> sorted, no duplicates
colors = np.array(["red", "blue", "red", "green"])
np.unique(colors) # ['blue' 'green' 'red']import numpy as np
arr = np.array([3, 1, 2, 1, 3, 3])
# Sorted distinct values
print(np.unique(arr)) # [1 2 3]
# return_index -> position of the FIRST occurrence of each value
values, first_idx = np.unique(arr, return_index=True)
print(values) # [1 2 3]
print(first_idx) # [1 2 0]
# ✅ Expected output:
# [1 2 3]
# [1 2 3]
# [1 2 0]2 Counting Categories with return_counts
Add return_counts=True and np.unique hands back a second array: how many times each value occurred. Zip the two arrays together and you have an instant frequency table — the go-to way to count categories.
votes = np.array(["yes", "no", "yes", "yes", "no"])
values, counts = np.unique(votes, return_counts=True)
# values -> ['no' 'yes']
# counts -> [2 3]
dict(zip(values, counts)) # {'no': 2, 'yes': 3}import numpy as np
votes = np.array(["yes", "no", "yes", "yes", "no"])
values, counts = np.unique(votes, return_counts=True)
print(values) # ['no' 'yes']
print(counts) # [2 3]
# Build a tidy table
for v, c in zip(values, counts):
print(v, "->", c)
# no -> 2
# yes -> 3
# ✅ Expected output:
# ['no' 'yes']
# [2 3]
# no -> 2
# yes -> 33 np.bincount & np.count_nonzero
For non-negative integers, np.bincount is a fast specialist: it returns counts indexed by value, so result[k] is how many times k appeared. Separately, np.count_nonzero counts entries that are not zero — perfect for counting how many elements pass a condition.
labels = np.array([0, 1, 1, 2, 1, 0])
np.bincount(labels) # [2 3 1] -> two 0s, three 1s, one 2
scores = np.array([55, 80, 42, 91, 67])
np.count_nonzero(scores >= 60) # 3 -> how many passedimport numpy as np
labels = np.array([0, 1, 1, 2, 1, 0])
# bincount: index k holds the count of value k
counts = np.bincount(labels)
print(counts) # [2 3 1]
print("zeros:", counts[0]) # zeros: 2
print("ones:", counts[1]) # ones: 3
# count_nonzero counts how many pass a test
scores = np.array([55, 80, 42, 91, 67])
print(np.count_nonzero(scores >= 60)) # 3
# ✅ Expected output:
# [2 3 1]
# zeros: 2
# ones: 3
# 3🎯 YOUR TURN: Fill in the Blank
Replace ___ with the keyword argument that makes np.unique also return per-value counts.
import numpy as np
fruits = np.array(["apple", "pear", "apple", "apple", "pear"])
# 🎯 YOUR TURN:
# Get each fruit AND how many times it appears.
# Hint: ask unique to also return the counts.
values, counts = np.unique(fruits, ___=True)
print(values) # ['apple' 'pear']
print(counts)
# Expected output:
# [3 2]Answer: return_counts — it returns a counts array matching the sorted values.
! Common Errors (And How to Fix Them)
❌ bincount on negative or float values
np.bincount([0, -1, 2]) # ❌ ValueError: negative not allowed✅ Fix: bincount needs non-negative integers; use np.unique(arr, return_counts=True) for other data.
❌ Forgetting to unpack two return values
vals = np.unique(arr, return_counts=True) # vals is a TUPLE✅ Fix: unpack both, e.g. values, counts = np.unique(arr, return_counts=True).
❌ Expecting unique to keep original order
np.unique always sorts the output.
✅ Fix: use return_index=True and sort by that index if you need first-appearance order.
🎯 Mini Challenge: Find the Most Common Value
Given a list of survey ratings, find which rating was most common and how many times it appeared, using unique with counts and argmax.
import numpy as np
ratings = np.array([5, 4, 5, 3, 5, 4, 2, 5, 4])
values, counts = np.unique(ratings, return_counts=True)
print(values) # [2 3 4 5]
print(counts) # [1 1 3 4]
# argmax finds the index of the largest count
top = counts.argmax()
print("most common:", values[top]) # most common: 5
print("appeared:", counts[top]) # appeared: 4
# ✅ Expected output:
# [2 3 4 5]
# [1 1 3 4]
# most common: 5
# appeared: 4❓ Frequently Asked Questions
Lesson complete — you can count anything!
You can extract sorted distinct values with np.unique, tally categories with return_counts, histogram integers with np.bincount, and count matches with np.count_nonzero.
Practice quiz
What does np.unique([3, 1, 2, 1, 3, 3]) return?
- [3 1 2]
- [3 3 3 1 1 2]
- [1 2 3]
- [3 2 1]
Answer: [1 2 3]. unique returns sorted distinct values with duplicates removed.
Is the output of np.unique always sorted?
- No, it keeps input order
- Yes, it is always sorted ascending
- Only for strings
- Only for integers
Answer: Yes, it is always sorted ascending. np.unique always returns its result sorted, even if the input was not.
How do you get per-value counts from np.unique?
- Pass return_counts=True
- Pass sort=True
- Use np.tally
- Pass count=True
Answer: Pass return_counts=True. return_counts=True returns the values plus a matching counts array.
What does np.bincount([0, 1, 1, 2, 1, 0]) return?
- [0 1 2]
- [6]
- [1 2 3]
- [2 3 1]
Answer: [2 3 1]. Index k holds the count of value k: two 0s, three 1s, one 2.
What does np.count_nonzero([55,80,42,91,67] >= 60) return?
- 5
- 2
- 3
- 0
Answer: 3. Three values (80, 91, 67) pass the >= 60 test.
When counts line up with np.unique's values, what order are they in?
- Input order
- Sorted value order
- Reverse order
- Random order
Answer: Sorted value order. Counts match the sorted values, so pair counts[i] with values[i].
Which is the fast specialist for counting non-negative integers?
- np.bincount
- np.sort
- np.where
- np.repeat
Answer: np.bincount. np.bincount counts each integer from 0 up to the maximum.
What does return_index=True give you from np.unique?
- The counts of each value
- The sorted values reversed
- Nothing extra
- The position of each value's first occurrence
Answer: The position of each value's first occurrence. return_index returns the index of the first occurrence of each value.
Why does np.bincount([0, -1, 2]) fail?
- The list is too short
- bincount needs non-negative integers
- It must be sorted first
- Floats are required
Answer: bincount needs non-negative integers. bincount only works on non-negative integers; negatives raise a ValueError.
On a boolean mask, how does count_nonzero compare to sum?
- sum is always larger
- count_nonzero rounds the result
- They give the same number (True counts as 1)
- count_nonzero only works on floats
Answer: They give the same number (True counts as 1). Both count the True entries, since True is 1.
Continue this course
- Previous: Handling NaN & Infinity
- Next: Set Operations on Arrays — Compare arrays with intersect1d, union1d, setdiff1d, and isin
- Quick reference: NumPy cheat sheet
Frequently asked questions
What does np.unique return?
By default np.unique returns the sorted array of distinct values, with every duplicate removed. So np.unique([3, 1, 2, 1, 3]) gives [1 2 3]. Importantly the result is always sorted, even if the input was not, which makes it predictable for building categories or lookups.
How do I count how many times each value appears?
Pass return_counts=True to np.unique. It then returns two arrays: the unique values and a matching array of how many times each one occurred. Zipping them together gives you a clean value-to-count table, which is the fastest way to tally categories in NumPy.
When should I use np.bincount instead of np.unique?
np.bincount is a fast specialist for non-negative integers. It counts how many times each integer from 0 up to the maximum appears, returning a count array indexed by value. It is ideal for things like histogramming small integer labels, but it only works on non-negative ints, whereas np.unique works on any dtype.
What is the difference between count_nonzero and sum on a boolean mask?
On a boolean array both give the same number, because True counts as 1. np.count_nonzero(mask) is the more explicit, slightly faster way to count how many elements satisfy a condition, and it also works on numeric arrays to count entries that are not zero. Many people prefer it for readability when counting matches.