Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a histogram from a list of strings in Python?

I have a list of strings:

a = ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e', 'e', 'e', 'e']

I want to make a histogram for displaying the frequency distribution of the letters. I can make a list that contains the count of each letter using following codes:

from itertools import groupby
b = [len(list(group)) for key, group in groupby(a)]

How do I make the histogram? I may have a million such elements in list a.

like image 815
Gray Avatar asked Feb 09 '15 20:02

Gray


4 Answers

Very easy with Pandas.

import pandas
from collections import Counter
a = ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e', 'e', 'e', 'e']
letter_counts = Counter(a)
df = pandas.DataFrame.from_dict(letter_counts, orient='index')
df.plot(kind='bar')

Notice that Counter is making a frequency count, so our plot type is 'bar' not 'hist'.

histogram of letter counts

like image 190
notconfusing Avatar answered Sep 25 '22 18:09

notconfusing


here's a concise all-pandas approach:

a = ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e', 'e', 'e', 'e']
pd.Series(a).value_counts(sort=False).plot(kind='bar')

barplot of counts

like image 23
drammock Avatar answered Sep 23 '22 18:09

drammock


As @notconfusing pointed above this can be solved with Pandas and Counter. If for any reason you need to not use Pandas you can get by with only matplotlib using the function in the following code:

from collections import Counter
import numpy as np
import matplotlib.pyplot as plt

a = ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e', 'e', 'e', 'e']
letter_counts = Counter(a)

def plot_bar_from_counter(counter, ax=None):
    """"
    This function creates a bar plot from a counter.

    :param counter: This is a counter object, a dictionary with the item as the key
     and the frequency as the value
    :param ax: an axis of matplotlib
    :return: the axis wit the object in it
    """

    if ax is None:
        fig = plt.figure()
        ax = fig.add_subplot(111)

    frequencies = counter.values()
    names = counter.keys()

    x_coordinates = np.arange(len(counter))
    ax.bar(x_coordinates, frequencies, align='center')

    ax.xaxis.set_major_locator(plt.FixedLocator(x_coordinates))
    ax.xaxis.set_major_formatter(plt.FixedFormatter(names))

    return ax

plot_bar_from_counter(letter_counts)
plt.show()

Which will produce enter image description here

like image 12
Heberto Mayorquin Avatar answered Sep 24 '22 18:09

Heberto Mayorquin


Rather than use groupby() (which requires your input to be sorted), use collections.Counter(); this doesn't have to create intermediary lists just to count inputs:

from collections import Counter

counts = Counter(a)

You haven't really specified what you consider to be a 'histogram'. Lets assume you wanted to do this on the terminal:

width = 120  # Adjust to desired width
longest_key = max(len(key) for key in counts)
graph_width = width - longest_key - 2
widest = counts.most_common(1)[0][1]
scale = graph_width / float(widest)

for key, size in sorted(counts.items()):
    print('{}: {}'.format(key, int(size * scale) * '*'))

Demo:

>>> from collections import Counter
>>> a = ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'd', 'e', 'e', 'e', 'e', 'e']
>>> counts = Counter(a)
>>> width = 120  # Adjust to desired width
>>> longest_key = max(len(key) for key in counts)
>>> graph_width = width - longest_key - 2
>>> widest = counts.most_common(1)[0][1]
>>> scale = graph_width / float(widest)
>>> for key, size in sorted(counts.items()):
...     print('{}: {}'.format(key, int(size * scale) * '*'))
... 
a: *********************************************************************************************
b: **********************************************
c: **********************************************************************
d: ***********************
e: *********************************************************************************************************************

More sophisticated tools are found in the numpy.histogram() and matplotlib.pyplot.hist() functions. These do the tallying for you, with matplotlib.pyplot.hist() also providing you with graph output.

like image 10
Martijn Pieters Avatar answered Sep 24 '22 18:09

Martijn Pieters