Добавить Автора
Публичный аккаунт WeChat:PythonНаука о данных
Знаю почти:аналитик данных Python
Гистограмма — это инструмент, который может быстро отображать распределение вероятностей данных, он интуитивно понятен и прост для понимания и очень любим любителями данных. Вы, вероятно, видите больше всегоmatplotlib
,seaborn
и другие упакованные пакеты библиотек высокого уровня, подобные следующим рисункам.
Этот блогер суммирует все методы использования Python для рисования гистограмм, которые можно условно разделить на три категории (детальное деление — пять категорий, см. резюме в конце статьи):
- Pure Python реализует гистограмму без использования какой-либо сторонней библиотеки.
- использовать
Numpy
построить гистограмму, суммирующую данные - использовать
matplotlib
,pandas
,seaborn
нарисовать гистограмму
Ниже мы рассмотрим входы и выходы каждого метода один за другим.
Чистая реализация Python гистограммы
Когда дело доходит до построения гистограмм в чистом Python, самая простая идея — сообщать о количестве вхождений каждого значения. В этом случае используйте字典
Для выполнения этой задачи очень подходит, давайте посмотрим, как реализован следующий код.
>>> a = (0, 1, 1, 1, 2, 3, 7, 7, 23)
>>> def count_elements(seq) -> dict:
... """Tally elements from `seq`."""
... hist = {}
... for i in seq:
... hist[i] = hist.get(i, 0) + 1
... return hist
>>> counted = count_elements(a)
>>> counted
{0: 1, 1: 3, 2: 1, 3: 1, 7: 2, 23: 1}
Мы видели,count_elements()
Возвращается словарь, ключи в словаре — это все уникальные значения в целевом списке, а значения — это частота появления всех значений.hist[i] = hist.get(i, 0) + 1
Реализовано накопление количества повторений каждого значения, и каждый раз добавляется единица.
На самом деле эту функцию можно использовать со стандартной библиотекой Python.collection.Counter
класс, который совместим со словарями Python и переопределяет класс словаря..update()
метод.
>>> from collections import Counter
>>> recounted = Counter(a)
>>> recounted
Counter({0: 1, 1: 3, 3: 1, 2: 1, 7: 2, 23: 1})
Видно, что результат этого метода такой же, как и у метода, который мы реализовали сами.collection.Counter
проверить, равны ли результаты, полученные двумя методами.
>>> recounted.items() == counted.items()
True
Мы используем вышеуказанную функцию для восстановления колесаASCII_histogram
, и, наконец, формат вывода через Pythonformat
Чтобы добиться отображения гистограммы, код выглядит следующим образом:
def ascii_histogram(seq) -> None:
"""A horizontal frequency-table/histogram plot."""
counted = count_elements(seq)
for k in sorted(counted):
print('{0:5d} {1}'.format(k, '+' * counted[k]))
Эта функция строит графики в числовом порядке, а количество вхождений значения обозначается символом (+). обратиться к словарюsorted()
вернет список в ключевом порядке, а затем вы можете получить соответствующее количество разcounted[k]
.
>>> import random
>>> random.seed(1)
>>> vals = [1, 3, 4, 6, 8, 9, 10]
>>> # `vals` 里面的数字将会出现5到15次
>>> freq = (random.randint(5, 15) for _ in vals)
>>> data = []
>>> for f, v in zip(freq, vals):
... data.extend([v] * f)
>>> ascii_histogram(data)
1 +++++++
3 ++++++++++++++
4 ++++++
6 +++++++++
8 ++++++
9 ++++++++++++
10 ++++++++++++
В этом кодеvals
Значения внутри не повторяются, а частота появления каждого значения определяется нами самими, в5和15
Случайным образом выбирать между. Затем используйте функцию, которую мы инкапсулировали выше, чтобы получить чистую версию Python для отображения гистограммы.
Резюме: Таблица частот (нестандартная гистограмма) реализована на чистом питоне, который можно реализовать напрямую с помощью метода collection.Counter.
Реализовать гистограмму с помощью Numpy
Выше приведена простая гистограмма, сделанная на чистом Python, но в математическом смысле,Гистограмма представляет собой отображение интервалов в частоты, которое можно использовать для оценки функции плотности вероятности переменной.. Приведенная выше версия реализации на чистом Python — это просто подсчет частоты, а не настоящая гистограмма.
Поэтому мы продолжаем обновлять простую гистограмму, реализованную выше. Настоящая гистограмма должна сначала разделить переменную на области (бины), то есть на разные интервалы, а затем подсчитать количество наблюдений в каждом интервале. по совпадению,Numpy
Метод гистограммы может сделать это, и не только это, он также является основой для использования matplotlib и pandas, которые будут упомянуты позже.
В качестве примера рассмотрим набор выборочных данных с плавающей запятой, взятых из распределения Лапласа. Это распределение имеет более широкие хвосты, чем стандартное нормальное распределение, и имеет два описательных параметра (местоположение и масштаб):
>>> import numpy as np
>>> np.random.seed(444)
>>> np.set_printoptions(precision=3)
>>> d = np.random.laplace(loc=15, scale=3, size=500)
>>> d[:5]
array([18.406, 18.087, 16.004, 16.221, 7.358])
Поскольку это непрерывное распределение, оно не очень хорошо маркирует каждое отдельное значение с плавающей запятой (т. е. все бесконечные десятичные разряды) (потому что точек очень много). Тем не менее, вы можете преобразовать данные, чтобы сделатьхранениеобработка, а затем подсчет количества наблюдений в каждом бине, вот что делает настоящая гистограмма.
Давайте посмотрим, как использовать Numpy для реализации статистики частоты гистограммы.
>>> hist, bin_edges = np.histogram(d)
>>> hist
array([ 1, 0, 3, 4, 4, 10, 13, 9, 2, 4])
>>> bin_edges
array([ 3.217, 5.199, 7.181, 9.163, 11.145, 13.127, 15.109, 17.091,
19.073, 21.055, 23.037])
Этот результат может быть не очень интуитивным. Давай поговорим об этом,np.histogram()
Используйте 10 бинов (бинов) одного размера по умолчанию, затем верните кортеж(频数,分箱的边界)
, как показано выше. Следует отметить, что количество границ на единицу больше, чем количество бинов, что легко подтверждается следующим кодом.
>>> hist.size, bin_edges.size
(10, 11)
Вопрос в том, как Numpy выполняет биннинг? просто простоnp.histogram()
Это сделано, но мы до сих пор не знаем, как именно. Давайте сейчасnp.histogram()
разобрать внутренности, чтобы посмотреть, как это реализовано (в качестве примера возьмем вышеупомянутый а-список).
>>> # 取a的最小值和最大值
>>> first_edge, last_edge = a.min(), a.max()
>>> n_equal_bins = 10 # NumPy得默认设置,10个分箱
>>> bin_edges = np.linspace(start=first_edge, stop=last_edge,
... num=n_equal_bins + 1, endpoint=True)
...
>>> bin_edges
array([ 0. , 2.3, 4.6, 6.9, 9.2, 11.5, 13.8, 16.1, 18.4, 20.7, 23. ])
Объясните: сначала получите минимальное и максимальное значение списка, затем установите количество ячеек по умолчанию и, наконец, используйте Numpy.linspace
метод сегментации сегмента данных. Результаты интервала биннинга также точно соответствуют реальной ситуации, от 0 до 23 поровну разделены на 10 частей, 23/10, тогда ширина каждой части составляет 2,3.
В дополнение к np.histogram есть два других метода, которые могут выполнять ту же функцию:np.bincount()
иnp.searchsorted()
, посмотрите на приведенный ниже код и сравните результаты.
>>> bcounts = np.bincount(a)
>>> hist, _ = np.histogram(a, range=(0, a.max()), bins=a.max() + 1)
>>> np.array_equal(hist, bcounts)
True
>>> # Reproducing `collections.Counter`
>>> dict(zip(np.unique(a), bcounts[bcounts.nonzero()]))
{0: 1, 1: 3, 2: 1, 3: 1, 7: 2, 23: 1}
Резюме: чтобы реализовать гистограмму через Numpy, вы можете напрямую использовать np.histogram() или np.bincount().
Визуализация гистограммы с помощью Matplotlib и Pandas
Из приведенного выше обучения мы увидели, как использовать основные инструменты Python для построения гистограммы.Давайте посмотрим, как использовать более мощный пакет библиотеки Python для завершения гистограммы.Matplotlib
Гистограмма на основе Numpy упакована различными способами и предоставляет более полные функции визуализации.
import matplotlib.pyplot as plt
# matplotlib.axes.Axes.hist() 方法的接口
n, bins, patches = plt.hist(x=d, bins='auto', color='#0504aa',
alpha=0.7, rwidth=0.85)
plt.grid(axis='y', alpha=0.75)
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.title('My Very Own Histogram')
plt.text(23, 45, r'$\mu=15, b=3$')
maxfreq = n.max()
# 设置y轴的上限
plt.ylim(ymax=np.ceil(maxfreq / 10) * 10 if maxfreq % 10 else maxfreq + 10)
Раньше мы определяли границу бинирования по оси X, а по оси Y — соответствующую частоту. Нетрудно заметить, что все мы вручную определяли количество бинов. Но в приведенном выше расширенном методе мы можем установитьbins='auto'
Автоматически выберите лучший из двух написанных алгоритмов и, наконец, рассчитайте наиболее подходящее количество бинов. Здесь целью алгоритма является выбор подходящей ширины интервала (бина) и создание гистограммы, которая наилучшим образом представляет данные.
Если вы используете инструменты научных вычислений Python, вы можете использовать PandasSeries.histogram()
, и пройтиmatplotlib.pyplot.hist()
чтобы нарисовать гистограмму входной серии, как показано в следующем коде.
import pandas as pd
size, scale = 1000, 10
commutes = pd.Series(np.random.gamma(scale, size=size) ** 1.5)
commutes.plot.hist(grid=True, bins=20, rwidth=0.9,
color='#607c8e')
plt.title('Commute Times for 1,000 Commuters')
plt.xlabel('Counts')
plt.ylabel('Commute Time')
plt.grid(axis='y', alpha=0.75)
pandas.DataFrame.histogram()
используется так же, как Series, но создает гистограмму для каждого столбца в DataFrame.
Резюме: чтобы реализовать гистограмму через pandas, вы можете использовать Seris.plot.hist(), DataFrame.plot.hist(), а matplotlib может использовать matplotlib.pyplot.hist().
Постройте оценку плотности ядра (KDE)
KDE (оценка плотности ядра) означает оценку плотности ядра, которая используется для оценки функции плотности вероятности случайных величин, что может сделать данные более сглаженными.
Используя библиотеку Pandas, вы можете использоватьplot.kde()
построить график плотности ядра,plot.kde()
Работает со структурами данных как Series, так и DataFrame. Но сначала давайте сгенерируем две разные выборки данных для сравнения (две выборки из нормального распределения):
>>> # 两个正太分布的样本
>>> means = 10, 20
>>> stdevs = 4, 2
>>> dist = pd.DataFrame(
... np.random.normal(loc=means, scale=stdevs, size=(1000, 2)),
... columns=['a', 'b'])
>>> dist.agg(['min', 'max', 'mean', 'std']).round(decimals=2)
a b
min -1.57 12.46
max 25.32 26.44
mean 10.12 19.94
std 3.94 1.94
Как показано выше, мы создали два набора нормально распределенных выборок и провели простое сравнение двух наборов данных с помощью некоторых описательных статистических параметров. Теперь мы можем построить каждую гистограмму вместе с соответствующим kde на той же оси Matplotlib, используя функцию pandas.plot.kde()
Преимущества:Он автоматически отобразит гистограмму и kde всех столбцов., очень удобно использовать, конкретный код выглядит следующим образом:
fig, ax = plt.subplots()
dist.plot.kde(ax=ax, legend=False, title='Histogram: A vs. B')
dist.plot.hist(density=True, ax=ax)
ax.set_ylabel('Probability')
ax.grid(axis='y')
ax.set_facecolor('#d8dcd6')
Описание: для реализации графов kde через pandas можно использовать Seris.plot.kde() и DataFrame.plot.kde().
Прекрасная альтернатива использованию Seaborn
Более продвинутый инструмент визуализацииSeaborn
, который является мощным инструментом, дополнительно инкапсулированным на основе matplotlib. Для гистограмм Seaborn имеетdistplot()
метод, гистограмму и kde одномерного распределения можно рисовать одновременно, и это очень удобно в использовании.Ниже приведен код реализации (в качестве примера возьмем сгенерированный выше d):
import seaborn as sns
sns.set_style('darkgrid')
sns.distplot(d)
distplot
Метод отрисовывает kde по умолчанию, и этот метод предоставляетfit
Параметры, вы можете выбрать специальное распределение, чтобы соответствовать реальному положению данных.
sns.distplot(d, fit=stats.laplace, kde=False)
Обратите внимание на небольшую разницу между двумя цифрами. В первом случае вы оцениваете неизвестную функцию плотности вероятности (PDF), а во втором случае вы знаете распределение и хотите знать, какие параметры лучше описывают данные.
Описание: Чтобы реализовать гистограмму через seaborn, вы можете использовать seaborn.distplot(), а у seaborn также есть отдельный отрисовщик kde seaborn.kde().
Другие инструменты в пандах
В дополнение к инструментам рисования панды также предоставляют удобный.value_counts()
метод, который используется для расчета гистограммы ненулевых значений и преобразования ее в структуру ряда панд, Пример выглядит следующим образом:
>>> import pandas as pd
>>> data = np.random.choice(np.arange(10), size=10000,
... p=np.linspace(1, 11, 10) / 60)
>>> s = pd.Series(data)
>>> s.value_counts()
9 1831
8 1624
7 1423
6 1323
5 1089
4 888
3 770
2 535
1 347
0 170
dtype: int64
>>> s.value_counts(normalize=True).head()
9 0.1831
8 0.1624
7 0.1423
6 0.1323
5 0.1089
dtype: float64
также,pandas.cut()
Это также удобный метод принудительного объединения данных. Допустим, у нас есть данные о возрасте некоторых людей, и мы хотим классифицировать эти данные по возрастным группам, вот пример:
>>> ages = pd.Series(
... [1, 1, 3, 5, 8, 10, 12, 15, 18, 18, 19, 20, 25, 30, 40, 51, 52])
>>> bins = (0, 10, 13, 18, 21, np.inf) # 边界
>>> labels = ('child', 'preteen', 'teen', 'military_age', 'adult')
>>> groups = pd.cut(ages, bins=bins, labels=labels)
>>> groups.value_counts()
child 6
adult 5
teen 3
military_age 2
preteen 1
dtype: int64
>>> pd.concat((ages, groups), axis=1).rename(columns={0: 'age', 1: 'group'})
age group
0 1 child
1 1 child
2 3 child
3 5 child
4 8 child
5 10 child
6 12 preteen
7 15 teen
8 18 teen
9 18 teen
10 19 military_age
11 20 military_age
12 25 adult
13 30 adult
14 40 adult
15 51 adult
16 52 adult
Помимо того, что они просты в использовании, еще лучше то, что эти операции в конечном итоге будут использоваться.Cython
Код завершен, и эффект от скорости работы тоже очень быстрый.
Резюме: для других способов реализации гистограмм используйте .value_counts() и pandas.cut().
Какой метод использовать?
До сих пор мы видели много способов реализации гистограммы. Но каковы недостатки каждого из них? Как их выбрать? Конечно, нет одного метода для решения всех проблем.Нам также необходимо подумать о том, как выбрать в соответствии с реальной ситуацией.Ниже приведены рекомендации по использованию методов в некоторых случаях, только для справки.
Ссылка: https://realpython.com/python-histograms/
Обратите внимание на публичный аккаунт WeChat:PythonНаука о данныхчтобы увидеть больше отличного контента.