Как создать график плотности в matplotlib?

122

В RI можно создать желаемый результат, выполнив:

data = c(rep(1.5, 7), rep(2.5, 2), rep(3.5, 8),
         rep(4.5, 3), rep(5.5, 1), rep(6.5, 8))
plot(density(data, bw=0.5))

График плотности в R

В python (с matplotlib) самое близкое, что я получил, было с простой гистограммой:

import matplotlib.pyplot as plt
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
plt.hist(data, bins=6)
plt.show()

Гистограмма в matplotlib

Я также попробовал параметр normed = True, но ничего не получил, кроме попытки подогнать гауссову к гистограмме.

Мои последние попытки были вокруг scipy.statsи gaussian_kde, следуя примерам в сети, но пока безуспешно.

unode
источник
Взгляните на seaborn stackoverflow.com/a/32803224/1922302
johk95

Ответы:

124

Свен показал, как использовать класс gaussian_kdeиз Scipy, но вы заметите, что он не совсем похож на то, что вы сгенерировали с помощью R. Это потому, что gaussian_kdeпытается автоматически определить полосу пропускания. Вы можете играть с пропускной способностью таким образом, изменяя функцию covariance_factorиз gaussian_kdeкласса. Во-первых, вот что вы получите без изменения этой функции:

альтернативный текст

Однако, если я использую следующий код:

import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
density = gaussian_kde(data)
xs = np.linspace(0,8,200)
density.covariance_factor = lambda : .25
density._compute_covariance()
plt.plot(xs,density(xs))
plt.show()

я получил

альтернативный текст

что довольно близко к тому, что вы получаете от Р. Что я наделал? gaussian_kdeиспользует изменяемую функцию covariance_factorдля расчета пропускной способности. Перед изменением функции значение, возвращаемое covariance_factor для этих данных, было около 0,5. Уменьшение этого уменьшило пропускную способность. Мне пришлось позвонить _compute_covarianceпосле изменения этой функции, чтобы все факторы были рассчитаны правильно. Это не точное соответствие параметру bw из R, но, надеюсь, поможет вам двигаться в правильном направлении.

Джастин Пил
источник
6
@Justin Хороший ответ (+1) и я не хочу начинать какие-либо пламенные войны Python v R или что-то еще, но мне нравится, как R работает с данными намного более лаконично, чем python и другие языки. Я уверен, что у python есть много хороших моментов по сравнению с R (я не являюсь пользователем Python, поэтому я полностью одет, чтобы, возможно, комментировать) и может использоваться для гораздо большей работы, чем анализ данных, но как давний R user Я забываю, насколько лаконичен язык для таких задач, пока не появятся такие примеры.
Гэвин Симпсон
4
(все еще борется с редактированием комментариев) Вот подкласс gaussian_kde, который позволяет установить полосу пропускания в качестве аргумента и другие примеры: mail.scipy.org/pipermail/scipy-user/2010-January/023877.html и есть улучшение билет на сайте projects.scipy.org/scipy/ticket/1092 . Обратите внимание, что gaussian_kde предназначен для n-мерных данных.
Josef
11
@Gavin Simpson, да, R более лаконичен, потому что у него более узкая область применения. Он предназначен для статистических вычислений и графиков. Python - это общий язык программирования, который может делать практически все, что вы хотите. Из-за этого синтаксис может быть не таким лаконичным. Частично это другой дизайн в Numpy / Scipy, но частично это просто модульная установка на Python. R отлично подходит, если вам нужно только выполнять вычисления и графику, но если вам нужно использовать эти вычисления в каком-то более продвинутом приложении, вам может понадобиться что-то вроде Python. Однако вы также можете использовать R из Python ...
Джастин Пил,
10
set_bandwidthМетод и bw_methodконструктор аргумент были добавлены к gaussian_kde в SciPy 0.11.0 на выпуск 1619
eddygeek
1
устаревший ответ. См. Ниже решение Seaborn, которое теперь является более стандартным для Python.
LudvigH
148

Пять лет спустя, когда я гуглил, «как создать график плотности ядра с помощью python», этот поток все еще отображается наверху!

Сегодня гораздо проще сделать это с помощью пакета seaborn , который предоставляет множество удобных функций построения графиков и хорошее управление стилями.

import numpy as np
import seaborn as sns
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
sns.set_style('whitegrid')
sns.kdeplot(np.array(data), bw=0.5)

введите описание изображения здесь

Xin
источник
Большое вам спасибо .. Искал что-то подобное уже несколько дней .. не могли бы вы объяснить, почему bw=0.5дается?
Sitz Blogz
4
@SitzBlogz bwПараметр обозначает пропускную способность. Я пытался сопоставить настройку OP (см. Его первый пример исходного кода). Подробное объяснение того, какие bwэлементы управления, см. На en.wikipedia.org/wiki/… . В основном он контролирует, насколько гладким вы хотите, чтобы график плотности был. Чем больше ЧБ, тем более гладким он будет.
Синь
У меня есть еще один запрос, чтобы спросить, что мои данные дискретны по своей природе, и я пытаюсь построить для этого PDF-файл, после прочтения scipy doc я понял, что PMF = PDF какие-либо предложения о том, как его построить?
Sitz Blogz
1
Когда я пытаюсь это я получаюTypeError: slice indices must be integers or None or have an __index__ method
эндолиты
48

Опция 1:

Используйте pandasграфик фрейма данных (построенный поверх matplotlib):

import pandas as pd
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
pd.DataFrame(data).plot(kind='density') # or pd.Series()

введите описание изображения здесь

Вариант 2:

Использование distplotв seaborn:

import seaborn as sns
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
sns.distplot(data, hist=False)

введите описание изображения здесь

Азиз Альто
источник
4
Чтобы добавить параметр пропускной способности: df.plot.de density (bw_method = 0.5)
Anake
3
@Aziz Не нужно pandas.DataFrame, можно использовать pandas.Series(data).plot(kind='density')@Anake, не нужно устанавливать df.plot.de density как отдельный шаг; может просто bw_methodпревратиться в ваш кварг вpd.Series(data).plot(kind='density', bw_method=0.5)
Красный горошек
45

Может попробовать что-нибудь вроде:

import matplotlib.pyplot as plt
import numpy
from scipy import stats
data = [1.5]*7 + [2.5]*2 + [3.5]*8 + [4.5]*3 + [5.5]*1 + [6.5]*8
density = stats.kde.gaussian_kde(data)
x = numpy.arange(0., 8, .1)
plt.plot(x, density(x))
plt.show()

Вы можете легко заменить gaussian_kde()его другой оценкой плотности ядра.

Свен Марнах
источник
0

График плотности также можно создать с помощью matplotlib: функция plt.hist (data) возвращает значения y и x, необходимые для графика плотности (см. Документацию https://matplotlib.org/3.1.1/api/_as_gen/ matplotlib.pyplot.hist.html ). В результате следующий код создает график плотности с помощью библиотеки matplotlib:

import matplotlib.pyplot as plt
dat=[-1,2,1,4,-5,3,6,1,2,1,2,5,6,5,6,2,2,2]
a=plt.hist(dat,density=True)
plt.close()
plt.figure()
plt.plot(a[1][1:],a[0])      

Этот код возвращает следующий график плотности

введите описание изображения здесь

tetrisforjeff
источник