手把手教你用Python画直方图:其实跟柱状图完全
导读:直方图和柱状图都是数据分析中非常常见、常用的图表,由于两者外观上看起来非常相似,也就难免造成一些混淆。此前我们曾在《柱状图、堆叠柱状图、瀑布图有什么区别?怎样用Python绘制?》一文中带大家了解了柱状图,今天我们再来讲讲直方图。
相关链接:柱状图、堆叠柱状图、瀑布图……有什么区别?怎样用Python绘制?
作者:屈希峰,资深Python工程师,知乎多个专栏作者
来源:华章科技
01 概述直方图(Histogram),形状类似柱状图却有着与柱状图完全不同的含义。直方图牵涉统计学概念,首先要对数据进行分组,然后统计每个分组内数据元的数量。在平面直角坐标系中,横轴标出每个组的端点,纵轴表示频数,每个矩形的高代表对应的频数,这样的统计图称为频数分布直方图。
频数分布直方图需要经过频数乘以组距的计算过程才能得出每个分组的数量,同一个直方图的组距是一个固定不变的值,所以如果直接用纵轴表示数量,每个矩形的高代表对应的数据元数量,既能保持分布状态不变,又能直观地看出每个分组的数量,如图2-58所示。
通过直方图还可以观察和估计哪些数据比较集中,异常或者孤立的数据分布在何处。
首先,了解如下几个基本概念。
组数:在统计数据时,我们把数据按照不同的范围分成几个组,分成的组的个数称为组数。组距:每一组两个端点的差。频数:分组内数据元的数量除以组距。02 实例直方图代码示例如下所示。
代码示例 2-451plot=figure(plot_width=300,plot_height=300)
2plot.quad(top=[2,3,4],bottom=[1,2,3],left=[1,2,3],
3right=[1.2,2.5,3.7],color="#B3DE69")
4show(plot)
运行结果如图2-59所示。
代码示例2-45第2行使用quad ()方法通过定义矩形的四边边界绘制直方图,具体参数说明如下。
p .quad(left, right, top, bottom, **kwargs)参数说明。
left (:class:`~bokeh.core.properties.NumberSpec` ) : 直方x轴左侧边界right (:class:`~bokeh.core.properties.NumberSpec` ) : 直方x轴右侧边界top (:class:`~bokeh.core.properties.NumberSpec` ) : 直方y轴顶部边界bottom (:class:`~bokeh.core.properties.NumberSpec` ) : 直方y轴底部边界其他参数(**kwargs)说明。
alpha (float) : 一次性设置所有线条的透明度color (Color) : 一次性设置所有线条的颜色source (ColumnDataSource) : Bokeh特有数据格式(类似于Pandas Dataframe)legend (str) : 图元的图例x_range_name (str) : x轴范围名称y_range_name (str) : y轴范围名称level (Enum) : 图元渲染级别代码示例 2-46 1importnumpyasnp
2importscipy.special
3frombokeh.layoutsimportgridplot
4#绘图函数
5defmake_plot(title,hist,edges,x,pdf,cdf):
6p=figure(title=title,tools='',background_fill_color="#fafafa")
7p.quad(top=hist,bottom=0,left=edges[:-1],right=edges[1:],
8fill_color="navy",line_color="white",alpha=0.5)
9p.line(x,pdf,line_color="#ff8888",line_width=4,alpha=0.7,legend="PDF")
10p.line(x,cdf,line_color="orange",line_width=2,alpha=0.7,legend="CDF")
11
12p.y_range.start=0
13p.legend.location="center_right"
14p.legend.background_fill_color="#fefefe"
15p.xaxis.axis_label='x'
16p.yaxis.axis_label='Pr(x)'
17p.grid.grid_line_color="white"
18returnp
19#正态分布
20mu,sigma=0,0.5
21measured=np.random.normal(mu,sigma,1000)
22hist,edges=np.histogram(measured,density=True,bins=50)
23x=np.linspace(-2,2,1000)
24#拟合曲线
25pdf=1/(sigma*np.sqrt(2*np.pi))*np.exp(-(x-mu)**2/(2*sigma**2))
26cdf=(1+scipy.special.erf((x-mu)/np.sqrt(2*sigma**2)))/2
27p1=make_plot("NormalDistribution(μ=0,σ=0.5)",hist,edges,x,pdf,cdf)
28#对数正态分布
29mu,sigma=0,0.5
30measured=np.random.lognormal(mu,sigma,1000)
31hist,edges=np.histogram(measured,density=True,bins=50)
32x=np.linspace(0.0001,8.0,1000)
33pdf=1/(x*sigma*np.sqrt(2*np.pi))*np.exp(-(np.log(x)-mu)**2/(2*sigma**2))
34cdf=(1+scipy.special.erf((np.log(x)-mu)/(np.sqrt(2)*sigma)))/2
35p2=make_plot("LogNormalDistribution(μ=0,σ=0.5)",hist,edges,x,pdf,cdf)
36#伽玛分布
37k,theta=7.5,1.0
38measured=np.random.gamma(k,theta,1000)
39hist,edges=np.histogram(measured,density=True,bins=50)
40x=np.linspace(0.0001,20.0,1000)
41pdf=x**(k-1)*np.exp(-x/theta)/(theta**k*scipy.special.gamma(k))
42cdf=scipy.special.gammainc(k,x/theta)
43p3=make_plot("GammaDistribution(k=7.5,θ=1)",hist,edges,x,pdf,cdf)
44#韦伯分布
45lam,k=1,1.25
46measured=lam*(-np.log(np.random.uniform(0,1,1000)))**(1/k)
47hist,edges=np.histogram(measured,density=True,bins=50)
48x=np.linspace(0.0001,8,1000)
49pdf=(k/lam)*(x/lam)**(k-1)*np.exp(-(x/lam)**k)
50cdf=1-np.exp(-(x/lam)**k)
51p4=make_plot("WeibullDistribution(λ=1,k=1.25)",hist,edges,x,pdf,cdf)
52#显示
53show(gridplot([p1,p2,p3,p4],ncols=2,plot_width=400,plot_height=400,toolbar_location=None))
运行结果如图2-60所示。
代码示例2-46第5行自定义绘图函数make_plot (title, hist, edges, x, pdf, cdf),其中参数分别为图的标题、直方顶部边界、左右边界、拟合曲线的x坐标、方法通过定义矩形的四边边界,PDF为概率密度函数,CDF为累积分布函数。第53行通过gridplot()方法一次展示4张图(正态分布、对数正态分布、伽玛分布、韦伯分布)。
关于作者:屈希峰,资深Python工程师,Bokeh领域的实践者和布道者,对Bokeh有深入的研究。擅长Flask、MongoDB、Sklearn等技术,实践经验丰富。知乎多个专栏(Python中文社区、Python程序员、大数据分析挖掘)作者,专栏累计关注用户十余万人。
本文摘编自《Python数据可视化:基于Bokeh的可视化绘图》,经出版方授权发布。
推荐语:从图形绘制、数据动态展示、Web交互等维度全面讲解Bokeh功能和使用,不含复杂数据处理和算法,深入浅出,适合零基础入门,包含大量案例。