我有一组数据值,并且我想获得该数据集的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。
这是怎么回事?我的方法正确吗?
谢谢。
答案 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))
所以这可能是这里出了问题:您没有检查自己的假设。
您用于计算积分的代码非常慢,有更好的方法使用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))
在0和x之间进行积分,您将得到与现在所看到的相同(在0的右边),但这根本不是cdf:
wrong_cdf = np.vectorize(lambda x: ag.integrate_box_1d(0, x))
plt.plot(x, wrong_cdf(x))
答案 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))