November 7, 2022

How to Use Python Counters in 2023 (w/ 23 Code Examples)

We, as Python developers, may need to develop a piece of code that counts several repeated objects at once. There are different ways to perform this task. However, Python's Counter class from the collections module provides the most efficient and straightforward solution to count individual items in an iterable object.

In this tutorial, we will learn about the Counter class and the basics of using it in Python.
After you finish this tutorial, you'll have a good understanding of

  • What the Counter class is.
  • How to create a Counter object.
  • How to update an existing Counter object.
  • How to determine the most frequent item in an iterable object.
  • How to combine or subtract Counter objects.
  • How to perform union and intersection on two Counter objects.

We assume you know the fundamentals of Python, including basic data structures and functions. If you're unfamiliar with these or eager to brush up your Python skill, you might like to try our Python Basics for Data Analysis – Dataquest.

What is the Python's Counter Class

Python's Counter is a subclass of the dictionary data type for counting hashable objects by creating a dictionary where the iterable's elements are stored as keys, and their counts are stored as values.
In other words, the Counter's constructor function takes an iterable object, and returns a dictionary containing the frequency of each item in the iterable object as long as the objects are hashable.
The good news is that some of the arithmetic operations are applicable to Counter objects.

In the following section, we will discuss using the Counter to determine the frequency of hashable objects in lists, strings, and other iterable objects.

Working with the Counter Object

As mentioned earlier, the Counter object provides an effortless way to count items in iterable objects quickly.
To demonstrate how the Counter object works and show its result, let's start with importing the Counter class from the collections module and then apply it on a string, as follows:

from collections import Counter
a_str = 'barbara'
counter_obj = Counter(a_str)
print(counter_obj)
    Counter({'a': 3, 'b': 2, 'r': 2})

As shown, the code above counts the letters in the word.
Let's make the output more appealing by adding the following lines to the previous code.

for item in counter_obj.items():
    print("Item: ", item[0]," Frequency: ", item[1])
    Item:  b  Frequency:  2
    Item:  a  Frequency:  3
    Item:  r  Frequency:  2

The Counter class implements useful methods such as update() and most_common([n]). The update() method takes an iterable object and adds it to the existing counter object.
Let's try it:

counter_obj.update("wallace")
print(counter_obj)
    Counter({'a': 5, 'b': 2, 'r': 2, 'l': 2, 'w': 1, 'c': 1, 'e': 1})

The most_common([n]) method returns an ordered list of tuples with the n most common
items and their counts.

print(counter_obj.most_common(1))
    [('a', 5)]

The code above returns the most frequent item in the a_str object.

To understand the usage of the Counter object better, let's determine the most frequent item occurring in the following sentence:

"Fear leads to anger; anger leads to hatred; hatred leads to conflict; conflict leads to suffering."
Here's how we would do it:

quote_1 = "Fear leads to anger; anger leads to hatred; hatred leads to conflict; conflict leads to suffering."
words_1 = quote_1.replace(';','').replace('.','').split()
word_counts = Counter(words_1)
the_most_frequent = word_counts.most_common(1)
print(the_most_frequent)
    [('leads', 4)]

In the code above, the Counter object generates a dictionary that maps the hashable items in the input sequence to the number of occurrences, as follows:

{
 'Fear': 1,
 'leads': 4,
 'to': 4,
 'anger': 2,
 'hatred': 2,
 'conflict': 2,
 'suffering': 1
}

As mentioned in the first section of this tutorial, one of the valuable features of Counter objects is that they can be combined using mathematical operations. For example:

from pprint import pprint
quote_2 = "Fear, anger, and hatred essentially come from a lack of perspective as to what life is all about."
words_2 = quote_2.replace(',','').replace('.','').split()

dict_1 = Counter(words_1)
dict_2 = Counter(words_2)
pprint(dict_1)
print()
pprint(dict_2)
    Counter({'leads': 4,
             'to': 4,
             'anger': 2,
             'hatred': 2,
             'conflict': 2,
             'Fear': 1,
             'suffering': 1})

    Counter({'Fear': 1,
             'anger': 1,
             'and': 1,
             'hatred': 1,
             'essentially': 1,
             'come': 1,
             'from': 1,
             'a': 1,
             'lack': 1,
             'of': 1,
             'perspective': 1,
             'as': 1,
             'to': 1,
             'what': 1,
             'life': 1,
             'is': 1,
             'all': 1,
             'about': 1})

Now, we're able to combine or subtract these two Counter instances. Let's try them:

pprint(dict_1 + dict_2)
    Counter({'to': 5,
             'leads': 4,
             'anger': 3,
             'hatred': 3,
             'Fear': 2,
             'conflict': 2,
             'suffering': 1,
             'and': 1,
             'essentially': 1,
             'come': 1,
             'from': 1,
             'a': 1,
             'lack': 1,
             'of': 1,
             'perspective': 1,
             'as': 1,
             'what': 1,
             'life': 1,
             'is': 1,
             'all': 1,
             'about': 1})
pprint(dict_1 - dict_2)
    Counter({'leads': 4,
             'to': 3,
             'conflict': 2,
             'anger': 1,
             'hatred': 1,
             'suffering': 1})

So far, we have tried the Counter object with string values. In the same way, we're able to give list, tuple, or dictionary objects to Counter and count the frequency of their items. Let's explore them in the following sections.

Python'sCounter with List, Tuple, and Dictionary Objects

To explore how list, tuple, and dictionary objects given to Python's Counter will be converted to hashable objects in the form of key-value pairs, let's consider a boutique that sells T-shirts in three colors, green, white, and red.

The following iterable objects show the T-shirt sales on two consecutive days, as follows:

sales_day_1 = ['red','green','white','red','red','green', 'white','green','red','red','red', 'white', 'white']
sales_day_2 = ('red','red','green','white','green','white','red','red','green', 'white','green','red','green','red','red')
price = {'red':74.99, 'green':83.99, 'white':51.99}

sales_day_1_counter = Counter(sales_day_1)
sales_day_2_counter = Counter(sales_day_2)
price_counter = Counter(price)

total_sales = sales_day_1_counter + sales_day_2_counter
sales_increment = sales_day_2_counter - sales_day_1_counter
minimum_sales = sales_day_1_counter & sales_day_2_counter
maximum_sales = sales_day_1_counter | sales_day_2_counter

print("Total Sales:", total_sales)
print("Sales Increment over Two Days:", sales_increment)
print("Minimun Sales:", minimum_sales)
print("Maximum Sales:", maximum_sales)
    Total Sales: Counter({'red': 13, 'green': 8, 'white': 7})
    Sales Increment over Two Days: Counter({'green': 2, 'red': 1})
    Minimun Sales: Counter({'red': 6, 'green': 3, 'white': 3})
    Maximum Sales: Counter({'red': 7, 'green': 5, 'white': 4})

In the example above, the sales_increment Counter doesn't contain white shirts since the Counter object doesn't show negative values. That's why the Counter contains only green and red shirts. The number of white shirts is decreased to -1 and ignored.

We have used the & and | operators in the code above to return minimum and maximum sales of each T-shirt's color. Let's discuss these two operators here. The intersection operator (&) returns the objects with minimum counts from both counters, while the union operator (|) returns the maximum counts from both counters.
To calculate the total sales of each color, we can use the following snippet:

for color,quantity in total_sales.items():
    print(f"Total sales of '{color}' T-shirts: ${quantity*price_counter[color]:.2f}")
    Total sales of 'red' T-shirts: $974.87
    Total sales of 'green' T-shirts: $671.92
    Total sales of 'white' T-shirts: $363.93

To retrieve the original data used to create a Counter, we can use the elements() method, as follows:

for item in sales_day_1_counter.elements():
    print(item)
    red
    red
    red
    red
    red
    red
    green
    green
    green
    white
    white
    white
    white

The output above reveals that the Counter's elements have been returned in the same order as in the sales_day_1_counter object.

Conclusions

This tutorial discussed Python's Counter, which provides an efficient approach to counting the number of items in an iterable object without dealing with loops and different data structures. We also learned about the Counter's methods and operators that help us to take the most insights out of the data stored into collections.

I hope that you have learned something new today. Feel free to connect with me on LinkedIn or Twitter.

Mehdi Lotfinejad

About the author

Mehdi Lotfinejad

Mehdi is a Senior Data Engineer and Team Lead at ADA. He is a professional trainer who loves writing data analytics tutorials.