Python:如何获取连续数据值的累积分布函数?

时间:2018-09-07 11:40:29

标签: python statistics

我有一组数据值,并且我想获得该数据集的CDF(累积分布函数)。

由于这是一个连续变量,因此我们不能使用(How to get cumulative distribution function correctly for my data in python?)中提到的合并方法。所以我想出了以下方法。

import scipy.stats as st

def trapezoidal_2(ag, a, b, n):
    h = np.float(b - a) / n
    s = 0.0
    s += ag(a)[0]/2.0
    for i in range(1, n):
        s += ag(a + i*h)[0]
    s += ag(b)[0]/2.0
    return s * h

def get_cdf(data):
    a = np.array(data)
    ag = st.gaussian_kde(a)

    cdf = [0]
    x = []
    k = 0

    max_data = max(data)

    while (k < max_data):
        x.append(k)
        k = k + 1

    sum_integral = 0

    for i in range(1, len(x)):
        sum_integral = sum_integral + (trapezoidal_2(ag, x[i - 1], x[i], 2))
        cdf.append(sum_integral)

    return x, cdf

这就是我使用此方法的方式。

b = 1
data = st.pareto.rvs(b, size=10000)
data = list(data)    x_cdf, y_cdf = get_cdf(data)

理想情况下,我应该在y_cdf列表的末尾获得接近1的值。但是我得到的值接近0.57。

这是怎么回事?我的方法正确吗?

谢谢。

3 个答案:

答案 0 :(得分:2)

x处cdf的值是-inf和x之间pdf的整数,但是您正在计算0到x之间的pdf。也许您假设x <0的pdf为0,但事实并非如此:

rs = np.random.RandomState(seed=52221829)
b = 1
data = st.pareto.rvs(b, size=10000, random_state=rs)
ag = st.gaussian_kde(data)

x = np.linspace(-100, 100)
plt.plot(x, ag.pdf(x))

enter image description here

所以这可能是这里出了问题:您没有检查自己的假设。

您用于计算积分的代码非常慢,有更好的方法使用scipy来实现,但是gaussian_kde提供了方法integrate_box_1d来集成pdf。如果从-inf中取积分,则一切看起来都正确。

cdf = np.vectorize(lambda x: ag.integrate_box_1d(-np.inf, x))
plt.plot(x, cdf(x))

enter image description here

在0和x之间进行积分,您将得到与现在所看到的相同(在0的右边),但这根本不是cdf:

wrong_cdf = np.vectorize(lambda x: ag.integrate_box_1d(0, x))
plt.plot(x, wrong_cdf(x))

enter image description here

答案 1 :(得分:0)

不确定为什么您的函数不能正常运行,而是计算CDF的一种方法如下:

def get_cdf_1(data):

    # start with sorted list of data
    x = [i for i in sorted(data)]

    cdf = []

    for xs in x:
        # get the sum of the values less than each data point and store that value
        # this is normalised by the sum of all values
        cum_val = sum([i for i in data if i <= xs])/sum(data) 
        cdf.append(cum_val)

    return x, cdf

毫无疑问,使用numpy数组而不是将值附加到列表中可以更快地计算出来,但这会返回与原始示例相同的格式的值。

答案 2 :(得分:0)

我认为这仅仅是:

def get_cdf(data):
  return sorted(data), np.linspace(0, 1, len(data))

但是我可能会误解这个问题!

当我将其与分析结果进行比较时,我得到相同的结果:

x_cdf, y_cdf = get_cdf(st.pareto.rvs(1, size=10000))

import matplotlib.pyplot as plt
plt.semilogx(x_cdf, y_cdf)
plt.semilogx(x_cdf, st.pareto.cdf(x_cdf, 1))