如何在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.statsgaussian_kde,以下是网上的示例,但到目前为止我一直没有成功。


Answers:


124

Sven展示了如何使用gaussian_kdeScipy中的类,但是您会注意到它与您使用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()

我懂了

替代文字

这与您从R获得的收益非常接近。我做了什么?gaussian_kde使用可变函数covariance_factor来计算其带宽。在更改函数之前,covariance_factor针对此数据返回的值约为0.5。降低它会降低带宽。我必须_compute_covariance在更改该函数后调用,以便可以正确计算所有因素。它与R中的bw参数并不完全对应,但是希望它可以帮助您朝正确的方向前进。


6
@Justin Nice答案(+1),不想开始任何Python v R的火焰大战或其他任何事情,但是我喜欢R处理数据的方式比python和其他语言简洁得多。我确信python比R有很多优点(我不是Python用户,所以我非常统一,可以评论),并且可以用于比分析数据更多的工作,但是作为R用户我确实忘记了这种任务的语言多么简洁,直到出现这样的例子。
加文·辛普森

4
(仍在与编辑评论进行斗争)这是gaussian_kde的子类,该子类允许将带宽设置为参数以及更多示例:mail.scipy.org/pipermail/scipy-user/2010-January/023877.html,并且进行了增强在售票projects.scipy.org/scipy/ticket/1092。注意,gaussian_kde是为n维数据设计的。
约瑟夫(Josef)2010年

11
@Gavin Simpson,是的,R更简洁,因为它的范围更窄。它用于统计计算和图形。Python是一种通用的编程语言,几乎可以完成您想做的任何事情。因此,语法可能不那么简洁。其中一部分是Numpy / Scipy中的不同设计,但一部分只是Python上的模块化设置。如果您只需要执行计算和图形处理,R就是很好的选择,但是如果您需要在某些更复杂的应用程序中使用这些计算,那么您可能需要Python之类的东西。但是,您也可以从Python使用R ...
Justin Peel 2010年

10
在每期scipy 0.11.0中向gaussian_kde中添加了一个set_bandwidth方法和一个bw_method构造函数参数1619
eddygeek

1
过时的答案。参见下文有关Seaborn解决方案的信息,该解决方案现在在Python中更为标准。
LudvigH

148

五年后,当我用Google搜索“如何使用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)

在此处输入图片说明


非常感谢..自从几天以来一直在寻找这样的东西..您能解释为什么bw=0.5给出了吗?
Sitz Blogz '16

4
@SitzBlogz该bw参数代表带宽。我试图匹配OP的设置(请参阅他最初的第一个代码示例)。有关bw控件的详细说明,请参见en.wikipedia.org/wiki/…。基本上,它控制着密度图的平滑程度。bw越大,将越平滑。
2016年

我还有一个查询要问我的数据本质上是离散的,在尝试阅读scipy doc之后,我试图为此绘制PDF,我理解PMF = PDF关于如何绘制它的任何建议?
Sitz Blogz '16

1
当我尝试这个时,我会得到TypeError: slice indices must be integers or None or have an __index__ method
endolith '17

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:

使用distplotseaborn

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.density(bw_method = 0.5)
Anake

3
@Aziz不需要pandas.DataFrame,可以使用pandas.Series(data).plot(kind='density')@Anake,不需要将df.plot.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])      

该代码返回以下密度图

在此处输入图片说明

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.