Как получить кумулятивную функцию распределения с NumPy?
Я хочу создать CDF с NumPy, мой код следующий:
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)
Я иду по массиву, но долго выполняю выполнение программы. Есть встроенная функция с этой функцией, не?
Ответы
Ответ 1
Я не совсем уверен, что делает ваш код, но если у вас есть 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])
Ответ 2
Использование гистограммы - это одно решение, но оно включает в себя объединение данных. Это не обязательно для построения CDF эмпирических данных. Пусть F(x)
будет подсчитывать, сколько записей меньше, чем x
, тогда оно поднимается на единицу, точно там, где мы видим измерение. Таким образом, если мы сортируем наши выборки, то в каждой точке мы увеличиваем счет на единицу (или на долю на 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()
Он выводит следующие
![enter image description here]()
Ответ 3
обновление для 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. ])
>>>
Ответ 4
В дополнение к решению Дэн.
В случае, когда в вашем примере несколько значений идентификатора, вы можете использовать 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)
Ответ 5
Есть много дистрибутивов, встроенных в scipy, которые предоставляют cdf
для вас, см. scipy нормальная документация по распространению или эти ответы, например:
Как рассчитать кумулятивное нормальное распределение в Python
Ответ 6
Я не уверен, есть ли готовый ответ, то, что нужно сделать, - это определить такую функцию, как:
def _cdf(x,data):
return(sum(x>data))
Это будет довольно быстро.