如何在Python中绘制matplotlib中的经验cdf?

如何在Python中绘制matplotlib中的数字数组的经验CDF? 我正在寻找pylab的“hist”函数的cdf模拟。

我能想到的一件事是:

from scipy.stats import cumfreq a = array([...]) # my array of numbers num_bins = 20 b = cumfreq(a, num_bins) plt.plot(b) 

那是正确的吗? 有更简单/更好的方法吗?

谢谢。

这看起来(几乎)正是你想要的。 两件事情:

首先,结果是一个四元组的元组。 第三个是箱子的大小。 第二个是最小的bin的起点。 首先是每个垃圾桶中或下面的点数。 (最后一个是限制点以外的点数,但是因为你没有设置任何点数,所有的点数都将被分组。

其次,您需要重新调整结果,使最终值为1,遵循CDF的惯例,否则就是正确的。

以下是它的function:

 def cumfreq(a, numbins=10, defaultreallimits=None): # docstring omitted h,l,b,e = histogram(a,numbins,defaultreallimits) cumhist = np.cumsum(h*1, axis=0) return cumhist,l,b,e 

它做直方图,然后产生每个箱的计数的累计和。 因此,结果的第i个值是小于或等于第i个仓的最大值的数组值的数目。 所以,最终的值只是初始数组的大小。

最后,要绘制它,您将需要使用bin的初始值以及bin的大小来确定您将需要的x轴值。

另一个select是使用numpy.histogram可以做归一化并返回bin边缘。 你需要自己做累计的总数。

 a = array([...]) # your array of numbers num_bins = 20 counts, bin_edges = numpy.histogram(a, bins=num_bins, normed=True) cdf = numpy.cumsum(counts) pylab.plot(bin_edges[1:], cdf) 

bin_edges[1:]是每个bin的上边缘。)

您可以使用scikits.statsmodels库中的ECDF函数:

 import numpy as np import scikits.statsmodels as sm import matplotlib.pyplot as plt sample = np.random.uniform(0, 1, 50) ecdf = sm.tools.ECDF(sample) x = np.linspace(min(sample), max(sample)) y = ecdf(x) plt.step(x, y) 

随着版本0.4 scicits.statsmodels被重命名为statsmodelsECDF现在位于distributions模块中(而statsmodels.tools.tools.ECDF已折旧)。

 import numpy as np import statsmodels.api as sm # recommended import according to the docs import matplotlib.pyplot as plt sample = np.random.uniform(0, 1, 50) ecdf = sm.distributions.ECDF(sample) x = np.linspace(min(sample), max(sample)) y = ecdf(x) plt.step(x, y) plt.show() 

如果你喜欢linspace并且喜欢单线,你可以这样做:

 plt.plot(np.sort(a), np.linspace(0, 1, len(a), endpoint=False)) 

鉴于我的口味,我几乎总是这样做:

 # a is the data array sorted_ = np.sort(a) yvals = np.arange(len(sorted_))/float(len(sorted_)) plt.plot(sorted_, yvals) 

即使有>O(1e6)数据值,这也适用于我。 如果你真的需要减less样本,我会设置

 sorted_ = np.sort(a)[::down_sampling_step] 

编辑回应评论/编辑为什么我使用endpoint=False或上面定义的yvals 。 以下是一些技术细节。

经验CDF通常被正式定义为

 CDF(x) = "number of samples <= x"/"number of samples" 

为了完全匹配这个forms化的定义,你需要使用yvals = np.arange(1,len(sorted_)+1)/float(len(sorted_))这样我们得到yvals = [1/N, 2/N ... 1] 。 这个估计是一个无偏估计,将收敛到真正的CDF在极限无限样本维基百科参考。 。

我倾向于使用yvals = [0, 1/N, 2/N ... (N-1)/N]因为(a)更容易编码/更自命,(b)但是从一个在收敛certificate中总是可以用1-CDF(x)交换CDF(x) ,并且(c)与上述的(简单)下采样方法一起工作。

在某些特定情况下,定义是有用的

 yvals = (arange(len(sorted_))+0.5)/len(sorted_) 

这是这两个公约之间的中间环节。 其中,实际上,“有一个价值低于我在我的样本中看到的最低价值的1/(2N)机会,以及比最大的价值更大的1/(2N)目前为止已经看到。

然而,对于大样本和合理的分布,答案的主体中给出的约定很容易写出,是真正的CDF的无偏估计,并与下采样方法一起工作。

您是否尝试过pyplot.hist的cumulative = True参数?

基于戴夫答案的单行:

 plt.plot(np.sort(arr), np.linspace(0, 1, len(arr), endpoint=False)) 

编辑:这也是由hans_meine在评论中提出的。

你想用CDF做什么? 为了绘制它,这是一个开始。 你可以尝试一些不同的值,例如:

 from __future__ import division import numpy as np from scipy.stats import cumfreq import pylab as plt hi = 100. a = np.arange(hi) ** 2 for nbins in ( 2, 20, 100 ): cf = cumfreq(a, nbins) # bin values, lowerlimit, binsize, extrapoints w = hi / nbins x = np.linspace( w/2, hi - w/2, nbins ) # care # print x, cf plt.plot( x, cf[0], label=str(nbins) ) plt.legend() plt.show() 

直方图列出了bin数目的各种规则,例如num_bins ~ sqrt( len(a) )

(精美图片:这里有两件截然不同的事情,

  • 对原始数据进行分箱/直方图
  • 曲线图通过所说的20个装仓值插入一条平滑的曲线。

其中任何一种都可能导致数据“丛生”或长尾,甚至对于1d数据 – 2d,3d数据变得越来越困难。
另请参阅Density_estimation和使用scipy高斯核密度估计 )。

我对AFoglia的方法有一个微不足道的补充,使CDF正常化

 n_counts,bin_edges = np.histogram(myarray,bins=11,normed=True) cdf = np.cumsum(n_counts) # cdf not normalized, despite above scale = 1.0/cdf[-1] ncdf = scale * cdf 

规范化的组织使其整体统一,这意味着cdf不会被归一化。 你必须自己扩展。

如果你想显示实际的真实ECDF(正如David B所说的是一个在每个数据点上增加1 / n的步进函数),我的build议是编写代码为每个数据点生成两个“绘图点”:

 a = array([...]) # your array of numbers sorted=np.sort(a) x2 = [] y2 = [] y = 0 for x in sorted: x2.extend([x,x]) y2.append(y) y += 1.0 / len(a) y2.append(y) plt.plot(x2,y2) 

这样,你将得到一个具有ECDF特征的n个步骤的情节,这对于足够小的步骤是可见的数据集尤其好。 此外,没有必要使用直方图进行任何分箱(这可能会对绘制的ECDF产生偏差)。

我们可以使用matplotlibstep函数,这个step函数是一个经验型CDF的定义:

 import numpy as np from matplotlib import pyplot as plt data = np.random.randn(11) levels = np.linspace(0, 1, len(data) + 1) # endpoint 1 is included by default plt.step(sorted(list(data) + [max(data)]), levels) 

max(data)垂直线是手动添加的。 否则,剧情只停留在1 - 1/len(data)

或者我们可以使用where='post'选项来step()

 levels = np.linspace(1. / len(data), 1, len(data)) plt.step(sorted(data), levels, where='post') 

在这种情况下,从零开始的垂直线不会被绘制出来。

(这是我对这个问题的答案的副本: 用python绘制pandas系列的CDF )

CDF或累积分布函数图基本上是X轴上的sorting值和Y轴上累积分布的图。 所以,我会创build一个新的系列,其sorting值为索引,累积分布为值。

先创build一个例子系列:

 import pandas as pd import numpy as np ser = pd.Series(np.random.normal(size=100)) 

对系列进行sorting:

 ser = ser.order() 

现在,在继续之前,再次追加最后(最大)的值。 为了得到一个无偏差的CDF,这一步对于小样本量尤为重要:

 ser[len(ser)] = ser.iloc[-1] 

创build一个新的系列,其sorting值为索引,累积分布为值

 cum_dist = np.linspace(0.,1.,len(ser)) ser_cdf = pd.Series(cum_dist, index=ser) 

最后,将该function绘制为步骤:

 ser_cdf.plot(drawstyle='steps') 

这是使用散景

“`

 from bokeh.plotting import figure, show from statsmodels.distributions.empirical_distribution import ECDF ecdf = ECDF(pd_series) p = figure(title="tests", tools="save", background_fill_color="#E8DDCB") p.line(ecdf.x,ecdf.y) show(p) 

“`

假设vals可以保存您的值,那么您可以简单地将CDF绘制如下:

 y = numpy.arange(0, 101) x = numpy.percentile(vals, y) plot(x, y) 

要在0和1之间缩放,只需将y除以100。

这是seaborn中使用cumulative = True参数的一行代码。 干得好,

 import seaborn as sns sns.kdeplot(a, cumulative=True)