numpy.histogram
numpy.histogram(a, bins=10, range=None, normed=None, weights=None, density=None)
Функция histogram() вычисляет гистограмму набора данных.
В данном случае речь идет об одномерной гистограме, которая позволяет ответить на вопрос о количестве вхождений значений элементов массива в определенные числовые интервалы. Например, у нас есть последовательность чисел [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
.
Замечание
Интервалы ширины каждой ячейки гистограммы являются полуоткрытыми, кроме самой правой. Например, если ширины интервалов ячеек заданы следующей последовательностью [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()
Строить гистограммы таким образом так же можно и с указанием массива с границами ячеек:
>>> 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()
Если же вы все-таки сначала вычислили гистограмму данных в 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()
Однако, на графике ничего нет. Все дело в толщине получившихся прямоугольников. Если вы попробуете увеличить данный график, то увидите очень тонкие линии:
Все дело в установленной по умолчанию ширине отображаемых прямоугольников, которая по умолчанию равна 0.8 что очень мало в используемых нами масштабах:
>>> plt.bar(bin_edges[:-1], hist, width = 50)
<BarContainer object of 50 artists>
>>>
>>> plt.show()
Теперь все отображается как надо.
Весовые коэфициенты
Используем предыдущий результат для рассмотрения параметра 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