numpy.histogram

numpy.histogram(a, bins=10, range=None, normed=None, weights=None, density=None)

Функция numpy.histogram() вычисляет гистограмму набора данных.

В данном случае речь идет об одномерной гистограме, которая позволяет ответить на вопрос о количестве вхождений значений элементов массива в определенные числовые интервалы. Например, у нас есть последовательность чисел [1, 2, 1, 4, 1, 3] гистограмма этих чисел для двух интервалов [1, 3) и [3, 4] будет равна [4, 2].

Данная функция часто используется в статистике при анализе случайных рядов, так как позволяет проанализировать распределение плотности вероятности значений, что может помоч в установлении вида функции вероятности.

Параметры:
a - массив NumPy или подобный массиву объект.
Входные данные. Многомерные массивы сжимаются до одной оси.
bins - целое число, последовательность целых чисел или строка (необязательный параметр).

Если указано целое число, то оно определяет количество интервалов равной ширины всех ячеек (по умолчанию 10 ячеек). Если указана последовательность целых чисел, то границы интервалов определяют соседние числа в данной последовательности.

В NumPy начиная с версии 1.11.0 в качестве данного параметра можно указывать строку с названием метода расчета оптимальной ширины ячеек. Подробнее см. в histogram_bin_edges().

range - (float_1, float_2) (необязательный параметр).

Определяет минимальное и максимальное значение ширины ячеек, при этом значения выходящие за пределы диапазона игнорируются. Если range = None то границы определяются интервалом (a.min(), a.max()). Должно выполняться условие float_1 < float_2.

Если в параметре bins указана строка с методом расчета ширины, то значения в range повлияют на эти вычисления. В этом случае по прежнему будет вычисляться оптимальная ширина ячеек, но только на основе тех данных, которые находятся в пределах указанного интервала. В любом случае, количество ячеек будет заполнять весь интервал, даже в тех участках, которые не содержат никаких данных.

normed - True или False (необязательный параметр).
Считается устаревшим начиная с версии 1.6.0.
weights - массив NumPy или подобный массиву объект (необязательный параметр).
Массив весовых коэфициентов той же формы что и a. Каждое значение в a добавляет величину к соответствующей ячейке в соответствии с указанным весом (который по умолчанию считается равным 1). Если параметр density = True, то все коэфициенты в weights нормализуются так, что интеграл плотности по диапазону range будет равен 1.
density - True или False (необязательный параметр).
Если density = True, то результатом вычислений окажется функция (точнее ее значения) плотности вероятности, а интеграл по диапазону значений range будет равен 1. Однако, интеграл не будет равен 1 если ширина ячеек не равна 1. Не путайте данную функцию плотности вероятности с функцией вероятности.
Возвращает:
hist - массив NumPy
Значения гистограммы.
bin_edges - массив NumPy
Массив с границами каждой ячейки. len(bin_edges) = len(hist) + 1.

Смотрите так же:
histogram2d, histogramdd, histogram_bin_edges, bincount, digitize

Замечание

Интервалы ширины каждой ячейки гистограммы являются полуоткрытыми, кроме самой правой. Например, если ширины интервалов ячеек заданы следующей последовательностью [0, 1, 3, 6], то интервал определяющий ширину каждой из трех ячеек будет выглядеть как [0, 1) для первой, [1, 3) для второй и [3, 6] для третьей.


Примеры

Путаница с границами

Использование функции histogram() без параметра bins приводит к тому, что границы ячеек рассчитываются автоматически, а это невсегда удобно:

>>> import numpy as np
>>> 
>>> a = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
>>> 
>>> np.histogram(a)
(array([1, 0, 0, 2, 0, 0, 3, 0, 0, 4], dtype=int32), array([1. , 1.3, 1.6, ..., 3.4, 3.7, 4. ]))

Теперь укажем границы ячеек:

>>> b = [0, 1, 2, 3, 4, 5]
>>> 
>>> np.histogram(a, b)
(array([0, 1, 2, 3, 4], dtype=int32), array([0, 1, 2, 3, 4, 5]))

Как видим, это вполне наглядный результат - в массиве a действительно нет нулей, одна единица, две двойки и т.д. Но давайте укажем немного другой массив с границами ячеек:

>>> b_1 = [0, 1, 2, 3, 4]
>>> 
>>> np.histogram(a, b_1)
(array([0, 1, 2, 7], dtype=int32), array([0, 1, 2, 3, 4]))

Теперь результат может показаться немного неправльным, но границы каждой ячейки являются полуоткрытыми интервалами, т.е. мы имеем следующие интервалы:

  • [0, 1) в него входит 0 значений;
  • [1, 2) в него входит 1 значение;
  • [2, 3) в него входит 2 значения;
  • [3, 4] в него входит 7 значений, потому что он является открытым.

Путаница с отображением в виде графиков

Еще может возникнуть путаница с отображением результатов на графике с помощью библиотеки Matplotlib, так как данная библиотека уже иммеет метод hist(), который, по сути, и основан на функции histogram() библиотеки NumPy. То есть, что бы отобразить гистограмму какого-то набора данных с помощью hist() нам не нужно вычислять эту гистограмму с помощью NumPy:

>>> import matplotlib.pyplot as plt
>>> 
>>> plt.hist(a)
(array([1., 0., 0., 2., 0., 0., 3., 0., 0., 4.]), array([1. , 1.3, 1.6, ..., 3.4, 3.7, 4. ]), <a list of 10 Patch objects>)
>>> plt.show()

Отображение гистограммы набора данных в matplotlib

Строить гистограммы таким образом так же можно и с указанием массива с границами ячеек:

>>> plt.hist(a, b)
(array([0., 1., 2., 3., 4.]), array([0, 1, 2, 3, 4, 5]), <a list of 5 Patch objects>)
>>> plt.show()

Отображение гистограммы набора данных в matplotlib с указанием ширины ячеек

Если же вы все-таки сначала вычислили гистограмму данных в NumPy а затем вам необходимо отобразить результат в Matplotlib то воспользуйтесь методом bar():

>>> np.random.seed(777)
>>> 
>>> a = np.random.randint(0, 5000, size = (1000))
>>> 
>>> bin_edges = np.arange(0, 5001, 100)
>>> 
>>> hist = np.histogram(a, bin_edges)[0]
>>> 
>>> 
>>> plt.bar(bin_edges[:-1], hist)
<BarContainer object of 50 artists>
>>> plt.show()

Отображение гистограммы набора данных в matplotlib с помощью метода bar

Однако, на графике ничего нет. Все дело в толщине получившихся прямоугольников. Если вы попробуете увеличить данный график, то увидите очень тонкие линии:

Отображение гистограммы набора данных в matplotlib с помощью метода bar

Все дело в установленной по умолчанию ширине отображаемых прямоугольников, которая по умолчанию равна 0.8 что очень мало в используемых нами масштабах:

>>> plt.bar(bin_edges[:-1], hist, width = 50)
<BarContainer object of 50 artists>
>>> 
>>> plt.show()

Отображение гистограммы набора данных в matplotlib с помощью метода bar

Теперь все отображается как надо.

Весовые коэфициенты

Используем предыдущий результат для рассмотрения параметра weights:

>>> a = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
>>> 
>>> b = [1, 2, 3, 4, 5]
>>> 
>>> np.histogram(a, b)[0]
array([1, 2, 3, 4], dtype=int32)

Теперь зададим вес каждого элемента в массиве a и вычислим гистограмму:

>>> w = [12, 6, 6, 4, 4, 4, 3, 3, 3, 3]
>>> 
>>> np.histogram(a, b, weights = w)[0]
array([12, 12, 12, 12])

Плотность распределения

Параметр density позволяет вычислить гистограмму в виде плотности распределения значений в исходных данных:

>>> a = np.random.normal(loc = -1, scale = 2, size = 1000)
>>> b = np.random.normal(loc = 11, scale = 2, size = 1000)
>>> 
>>> data = np.hstack((a, b))
>>> 
>>> 
>>> hist = np.histogram(data, bins = 50)[0]
>>> 
>>> plt.bar(np.linspace(data.min(), data.max()), hist)
<BarContainer object of 50 artists>
>>> plt.show()

Гистограмма значений набора данных

Теперь посмотрим на плотность распределения значений в исходных данных:

>>> hist_d = np.histogram(data, bins = 50, density = True)[0]
>>> 
>>> plt.bar(np.linspace(data.min(), data.max()), hist_d)
<BarContainer object of 50 artists>
>>> plt.show()

Плотность распределения значений

Из-за того что сумма (интеграл) данных значений не равен 1, опять, может показаться, что результат не является верным:

>>> hist_d.sum()
2.166278614494252
>>> 
>>> np.trapz(hist_d)
2.1608629179580165

Но дело в том что функции np.trapz() и sum() складывают высоты получаемых прямоугольников, а не их площади. Давайте проссумируем площади всех прямоугольников составляющих нашу гистограмму:

>>> np.sum(hist_d * np.diff(bin_edges))
1.0