如何创建密度图
在R语言中,我可以通过以下方式创建想要的输出:
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))
在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()
我还尝试了normed=True这个参数,但除了尝试将高斯分布拟合到直方图上,我没有得到其他结果。
我最近的尝试是使用scipy.stats
和gaussian_kde
,参考网上的例子,但到目前为止都没有成功。
6 个回答
72
选项 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:
使用 seaborn
的 distplot
:
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)
202
五年后,当我在谷歌上搜索“如何用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)
147
Sven展示了如何使用Scipy中的gaussian_kde
类,但你会发现它和你在R中生成的结果看起来不太一样。这是因为gaussian_kde
会自动推测带宽。你可以通过改变gaussian_kde
类中的covariance_factor
函数来调整带宽。首先,下面是没有改变这个函数时的结果:
但是,如果我使用以下代码:
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参数并不完全对应,但希望能帮助你朝着正确的方向前进。