我想用 NumPy 创建一个 CDF,我的代码是下一个:
histo = np.zeros(4096, dtype = np.int32)
for x in range(0, width):
for y in range(0, height):
histo[data[x][y]] += 1
q = 0
cdf = list()
for i in histo:
q = q + i
cdf.append(q)
我正在数组旁边行走,但程序执行时间很长。有一个具有此功能的内置函数,不是吗?
使用直方图是一种解决方案,但它涉及对数据进行分箱。这对于绘制经验数据的 CDF 不是必需的。令
F(x)
为小于 x
的条目数,然后它加一,正是我们看到的测量值。因此,如果我们对样本进行排序,那么在每个点我们将计数增加 1(或分数增加 1/N)并将其中一个与另一个相对绘制,我们将看到“精确”(即未分箱)经验 CDF。
以下代码示例演示了该方法
import numpy as np
import matplotlib.pyplot as plt
N = 100
Z = np.random.normal(size = N)
# method 1
H,X1 = np.histogram( Z, bins = 10, normed = True )
dx = X1[1] - X1[0]
F1 = np.cumsum(H)*dx
#method 2
X2 = np.sort(Z)
F2 = np.array(range(N))/float(N)
plt.plot(X1[1:], F1)
plt.plot(X2, F2)
plt.show()
它输出以下内容
我不太确定你的代码在做什么,但是如果你有
hist
返回的 bin_edges
和 numpy.histogram
数组,你可以使用 numpy.cumsum
生成直方图内容的累积和。
>>> import numpy as np
>>> hist, bin_edges = np.histogram(np.random.randint(0,10,100), normed=True)
>>> bin_edges
array([ 0. , 0.9, 1.8, 2.7, 3.6, 4.5, 5.4, 6.3, 7.2, 8.1, 9. ])
>>> hist
array([ 0.14444444, 0.11111111, 0.11111111, 0.1 , 0.1 ,
0.14444444, 0.14444444, 0.08888889, 0.03333333, 0.13333333])
>>> np.cumsum(hist)
array([ 0.14444444, 0.25555556, 0.36666667, 0.46666667, 0.56666667,
0.71111111, 0.85555556, 0.94444444, 0.97777778, 1.11111111])
更新 numpy 版本 1.9.0。 user545424的答案在1.9.0中不起作用。这有效:
>>> import numpy as np
>>> arr = np.random.randint(0,10,100)
>>> hist, bin_edges = np.histogram(arr, density=True)
>>> hist = array([ 0.16666667, 0.15555556, 0.15555556, 0.05555556, 0.08888889,
0.08888889, 0.07777778, 0.04444444, 0.18888889, 0.08888889])
>>> hist
array([ 0.1 , 0.11111111, 0.11111111, 0.08888889, 0.08888889,
0.15555556, 0.11111111, 0.13333333, 0.1 , 0.11111111])
>>> bin_edges
array([ 0. , 0.9, 1.8, 2.7, 3.6, 4.5, 5.4, 6.3, 7.2, 8.1, 9. ])
>>> np.diff(bin_edges)
array([ 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9])
>>> np.diff(bin_edges)*hist
array([ 0.09, 0.1 , 0.1 , 0.08, 0.08, 0.14, 0.1 , 0.12, 0.09, 0.1 ])
>>> cdf = np.cumsum(hist*np.diff(bin_edges))
>>> cdf
array([ 0.15, 0.29, 0.43, 0.48, 0.56, 0.64, 0.71, 0.75, 0.92, 1. ])
>>>
补充 Dan 的解决方案。 如果样本中有多个相同的值,您可以使用 numpy.unique :
Z = np.array([1,1,1,2,2,4,5,6,6,6,7,8,8])
X, F = np.unique(Z, return_index=True)
F=F/X.size
plt.plot(X, F)
现有答案要么诉诸使用直方图,要么不能很好地/正确地处理重复值(要么忽略重复值,要么生成包含相同 x 值的多个 y 值的 CDF)。我建议使用以下方法:
x, CDF_counts = np.unique(data, return_counts = True)
y = np.cumsum(CDF_counts)/np.sum(CDF_counts)
对 @Dan 的“Exact”#2 方法进行了微小改进。我相信第一个观察的 eCDF 不应该为 0,最后一个应该为 1,而且 eCDF 通常被可视化为阶跃函数(这三个值对于大
n
来说大多无关)。
有一个关于重复项的未解答问题,matplotlib 可以很好地可视化它们,但这里有一种删除它们的方法:
x = np.array([3, 3, 3.5, 4, 6, 0, 0.5, 1, 1, 2, 2.5])
# x = np.random.normal(size = 100)
x = np.sort(x)
n = x.shape[0]
# original
y = np.arange(n)/n
plt.plot(x, y, label='original')
plt.plot(x, y, '.', color='tab:red', label='original')
# step (0, 1]
y_step = np.arange(1,n+1)/n
plt.step(x, y_step, where='post', label='step')
# no duplicates
x_unique, inds = np.unique(x, return_index=True)
y_unique = [y_[-1] for y_ in np.split(y_step, inds[1:])]
plt.step(x_unique, y_unique, '--', where='post', label='step (unique)')
plt.plot(x_unique, y_unique, '.', color='tab:brown', label='step (unique)')
plt.ylim(-0.1, 1.1)
plt.legend()
我不确定是否有现成的答案,确切的做法是定义一个函数,例如:
def _cdf(x,data):
return(sum(x>data))
这会很快。