A histogram is used to plot the distribution of a numeric variable. It’s the quantitative version of the bar chart. However, rather than plot one bar for each unique numeric value, values are grouped into continuous bins, and one bar for each bin is plotted depicting the number. For instance, using the default settings for matplotlib’s hist
function:
plt.hist(data = df, x = 'num_var')
You can see that there are eight data points that fall in the range between about 0 and 2.5 in the leftmost bin, and nine points in the range from about 2.5 to 5 in the adjacent bin. Overall, a generally bimodal distribution is observed (one with two peaks or humps). The direct adjacency of the bars in the histogram, in contrast to the separated bars in a bar chart, emphasize the fact that the data takes on a continuous range of values. When a data value is on a bin edge, it is counted in the bin to its right. The exception is the rightmost bin edge, which places data values equal to the uppermost limit into the right-most bin (to the upper limit’s left).
By default, the hist
function divides the data into 10 bins, based on the range of values taken. In almost every case, we will want to change these settings. Usually, having only ten bins is too few to really understand the distribution of the data. And the default tick marks are often not on nice, ’round’ values that make the ranges taken by each bin easy to interpret. Wouldn’t it be better if I said “between 0 and 2.5” instead of “between about 0 and 2.5″, and “from 2.5 to 5” instead of “from about 2.5 to 5″ above?
You can use descriptive statistics (e.g. via df['num_var'].describe()
) to gauge what minimum and maximum bin limits might be appropriate for the plot. These bin edges can be set using numpy’s arange
function:
bin_edges = np.arange(0, df['num_var'].max()+1, 1)
plt.hist(data = df, x = 'num_var', bins = bin_edges)
The first argument to arange
is the leftmost bin edge, the second argument the upper limit, and the third argument the bin width. Note that even though I’ve specified the “max” value in the second argument, I’ve added a “+1” (the bin width). That is because arange
will only return values that are strictly less than the upper limit. Adding in “+1” is a safety measure to ensure that the rightmost bin edge is at least the maximum data value, so that all of the data points are plotted. The leftmost bin is set as a hardcoded value to get a nice, interpretable value, though you could use functions like numpy’s around
if you wanted to approach that end programmatically.
When creating histograms, it’s useful to play around with different bin widths to see what represents the data best. Too many bins, and you may see too much noise that interferes with identification of the underlying signal. Too few bins, and you may not be able to see the true signal in the first place.
plt.figure(figsize = [10, 5]) # larger figure size for subplots
# histogram on left, example of too-large bin size
plt.subplot(1, 2, 1) # 1 row, 2 cols, subplot 1
bin_edges = np.arange(0, df['num_var'].max()+4, 4)
plt.hist(data = df, x = 'num_var', bins = bin_edges)
# histogram on right, example of too-small bin size
plt.subplot(1, 2, 2) # 1 row, 2 cols, subplot 2
bin_edges = np.arange(0, df['num_var'].max()+1/4, 1/4)
plt.hist(data = df, x = 'num_var', bins = bin_edges)
This example puts two plots side by side through use of the subplot
function, whose arguments specify the number of rows, columns, and index of the active subplot (in that order). The figure()
function is called with the “figsize” parameter so that we can have a larger figure to support having multiple subplots. (More details on figures and subplots are coming up next in the lesson.)
Alternative Approach
The seaborn function distplot
can also be used to plot a histogram, and is integrated with other univariate plotting functions.
sb.distplot(df['num_var'])
When we specify the data to be plotted, note that the first argument must be the Series or array with the points to be plotted. This is in contrast to our ability to specify a data source and column as separate arguments, like we’ve seen with and countplot
and hist
.
The distplot
function has built-in rules for specifying histogram bins, and by default plots a curve depicting the kernel density estimate (KDE) on top of the data. The vertical axis is based on the KDE, rather than the histogram: you shouldn’t expect the total heights of the bars to equal 1, but the area under the curve should equal 1. If you want to learn more about KDEs, check out the extra page at the end of the lesson.
Despite the fact that the default bin-selection formula used by distplot
might be better than the choice of ten bins that .hist
uses, you’ll still want to do some tweaking to align the bins to ’round’ values. You can use other parameter settings to plot just the histogram and specify the bins like before:
bin_edges = np.arange(0, df['num_var'].max()+1, 1)
sb.distplot(df['num_var'], bins = bin_edges, kde = False,
hist_kws = {'alpha' : 1})
The alpha (transparency) setting must be associated as a dictionary to “hist_kws” since there are other underlying plotting functions, like the KDE, that have their own optional keyword parameters.
The result of the code above is exactly like the histogram above with bin width of 1. The units of the vertical axis are also back in terms of counts.
In summary, if your exploration is only interested in the histogram-depiction of the data, and not the additional functionality offered by distplot
, then you might be better off with just using Matplotlib’s hist
function for simplicity. On the other hand, if you want a quick start on choosing a representative bin size for histogram plotting, you might take a quick look at the basic distplot
first before getting into the customization.
not often i stumble across detailed information like this