如何绘制由值加权的累积分布函数(例如,有多少人居住在> 1m的城市中)

时间:2019-03-27 12:05:59

标签: python numpy matplotlib seaborn

我有一个很少有非常大观察值的数据集,我对直方图和由值本身加权的累积分布函数感兴趣。

就像有一张表格可以显示一个地区/国家/地区中每个城市的居民一样。 我不在乎有多少个城镇,我只关心的是,例如,有20%的人口居住在人口少于10,000的城镇,有10%的人口居住在人口众多的大城市超过一百万的人,等等。

Matplotlib和seaborn可以计算加权直方图-请参见下面的代码。

我的问题是CDF

  • numpy.histogram,density = True返回so the values do not necessarily sum to 1分箱处的概率密度函数的值
  • matplotlib.pyplot.hist,密度= True,返回的值确实等于1,但它还会绘制直方图,而我只希望这些值自己绘制一条线(线,不是直方图)
  • statsmodels.distributions.empirical_distribution.ECDF无法接受权重

我想出的是使用numpy.histogram,然后重新缩放自己:

hist_nodens, bin_edges_nodens=np.histogram(d, 100, weights=d, density=False)
hist_nodens /= np.sum(hist_nodens)
sns.lineplot(bin_edges_nodens[1:], np.cumsum(hist_nodens))

它可以工作,但是我想知道是否还有其他方法?使用matplotlib.pyplot.hist创建一个图,然后关闭它似乎比较麻烦。

我在这里整理了一个玩具示例。在图表D中,y轴变为1,而在C中则没有。

import numpy as np
from statsmodels.distributions.empirical_distribution import ECDF
import matplotlib.pyplot as plt
import seaborn as sns

d= np.hstack([\
              np.random.randint(100,1000,4000),
              np.arange(10000,100000,100), \
              np.linspace(200e3,900e3,20), \
              1e6,2e6,4e6
              ])

s=np.sum(d) / 1e6

d /= 1e3

fig,ax=plt.subplots(1,5)

ax[0].set_title('A) Histogram - weighted')
sns.distplot( d, 100,  kde=False, norm_hist=True, ax=ax[0], hist_kws={'weights':d} )

ax[1].set_title('B) Cumulative weighted histogram')
sns.distplot( d, 100, kde=False, norm_hist=True, ax=ax[1], hist_kws={'weights':d,'cumulative':True} )

ax[2].set_title('C) Weighted ECDF \n from np.histogram dens=True')
hist, bin_edges=np.histogram(d, 100, weights=d, density=True)
hist=np.cumsum(hist)
sns.lineplot(bin_edges[1:], hist, ax=ax[2])

ax[3].set_title('D) Weighted ECDF \n from np.histogram dens=False')
hist_nodens, bin_edges_nodens=np.histogram(d, 100, weights=d, density=False)
hist_nodens /= np.sum(hist_nodens)
sns.lineplot(bin_edges_nodens[1:], np.cumsum(hist_nodens), ax=ax[3])

py_n,py_bins,py_patches=plt.hist( d,100, weights=d, density=True, cumulative=True)

ax[4].set_title('E) ECDF - not weighted')
ecdf=ECDF( d  )
x=np.linspace( min(d), max(d), num=1000 )
y=ecdf(x)
ax[4].step(x,y)

1 个答案:

答案 0 :(得分:1)

您的NumPy解决方案是一个很好的解决方案。 matplotlib.pyplot.hist还有一些其他选项,您可能会觉得有用。具体来说,使用cumulative = True选项将其设置为带有histt​​ype ='step'的CDF,以创建线图而不是柱线。