Как получить сигмодальную кривую CDF с использованием scipy.stats.norm.cdf и matplotlib? - PullRequest
0 голосов
/ 02 августа 2020

Я пытаюсь построить S-образную кривую кумулятивной функции распределения (cdf) нормального распределения. Однако в итоге я получил равномерное распределение. Что я делаю не так?

Тестовый сценарий

import numpy as np
from numpy.random import default_rng
from scipy.stats import norm
import matplotlib.pyplot as plt

siz = 1000
rg = default_rng( 12345 )
a = rg.random(size=siz)
rg = default_rng( 12345 )
b = norm.rvs(size=siz, random_state=rg)
c = norm.cdf(b)

print( 'a = ', a)
print( 'b = ', b)
print( 'c = ', c)

fig, ax = plt.subplots(3, 1)
acount, abins, aignored = ax[0].hist( a, bins=20, histtype='bar', label='a', color='C0' )
bcount, bbins, bignored = ax[1].hist( b, bins=20, histtype='bar', label='b', color='C1' )
ccount, cbins, cignored = ax[2].hist( c, bins=20, histtype='bar', label='c', color='C2' )
print( 'acount, abins, aignored = ', acount, abins, aignored)
print( 'bcount, bbins, bignored = ', bcount, bbins, bignored)
print( 'ccount, cbins, cignored = ', ccount, cbins, cignored)
ax[0].legend()
ax[1].legend()
ax[2].legend()
plt.show()

введите описание изображения здесь

Ответы [ 3 ]

1 голос
/ 03 августа 2020

Для построения сигмоидального результата CDF нормально распределенных случайных величин мне не следовало использовать функцию hist() из matplotlib. Скорее, я мог бы использовать функцию bar() для построения своих результатов.

@ Laaggan и @ dumbPy в ответах говорилось, что использование упорядоченного и упорядоченного значения x является способ получения сигмоидальной кривой cdf. Хотя обычно это делается, это не применимо, когда используются случайные переменные. Я сравнил решения упомянутого подхода с тем, что я сделал, чтобы показать, что оба подхода дают одинаковый результат. Однако мои результаты (см. Рисунок ниже) показывают, что обычный подход к получению значений cdf дает больше случаев экстремальных значений нормального распределения, чем при использовании случайных величин. За исключением двух крайностей, вхождения кажутся распределенными равномерно.

Я пересмотрел свой сценарий и предоставил комментарии, чтобы продемонстрировать, как я сравнивал два подхода. Я надеюсь, что мой ответ принесет пользу другим, кто учится использовать функции rvs(), pdf() и cdf() класса scipy.stats.norm.

import numpy as np
from numpy.random import default_rng
from scipy.stats import norm
import matplotlib.pyplot as plt

mu = 0
sigma = 1
samples = 1000

rg = default_rng( 12345 )
a = rg.random(size=samples) #Get a  uniform distribution of numbers in the range of 0 to 1.
print( 'a = ', a)

# Get pdf and cdf values using normal random variates. 
rg = default_rng( 12345 ) #Recreate Bit Generator to ensure a same starting point  
b_pdf = norm.rvs( loc=mu, scale=sigma, size=samples, random_state=rg ) #Get pdf of normal distribution(mu=0, sigma=1 gives -3.26 to +3.26).
b_cdf = norm.cdf( b_pdf, loc=mu, scale=sigma ) #get cdf of normal distribution using pdf values (always gives between 0 to 1).
print( 'b_pdf = ', b_pdf)
print( 'b_cdf = ', b_cdf)

#To check b is normally distributed. Using the ordered x (commonly practiced): 
c_x = np.linspace( mu - 3.26*sigma, mu + 3.26*sigma, samples )
c_pdf = norm.pdf( c_x, loc=mu, scale=sigma )
c_cdf = norm.cdf( c_x, loc=mu, scale=sigma  )
print( 'c_x = ', c_x )
print( 'c_pdf = ', c_pdf )
print( 'c_cdf = ', c_cdf )


fig, ax = plt.subplots(3, 1)
bins=np.linspace( 0, 1, num=10 )
acount, abins, aignored = ax[0].hist( a, bins=50, histtype='bar', label='a', color='C0', alpha=0.2, density=True  )
bcount, bbins, bignored = ax[0].hist( b_cdf, bins=50, histtype='bar', label='b_cdf', color='C1', alpha=0.2, density=True )
ccount, cbins, cignored = ax[0].hist( c_cdf, bins=50, histtype='bar', label='c_cdf', color='C2', alpha=0.2, density=True )

bcount, bbins, bignored = ax[1].hist( b_pdf, bins=20, histtype='bar', label='b_pdf', color='C1', alpha=0.4, density=True  )
cpdf_line = ax[1].plot(c_x, c_pdf, label='c_pdf', color='C2')

bpdf_bar = ax[2].bar( b_pdf, b_cdf, label='b_cdf', color='C1', alpha=0.4, width=0.01)
ccdf_line = ax[2].plot(c_x, c_cdf, label='c_cdf', color='C2')
print( 'acount, abins, aignored = ', acount, abins, aignored)
print( 'bcount, bbins, bignored = ', bcount, bbins, bignored)
print( 'ccount, cbins, cignored = ', ccount, cbins, cignored)

ax[0].legend(loc='upper left')
ax[1].legend(loc='upper left')
ax[2].legend(loc='upper left')
plt.show()

Полученные результаты

1 голос
/ 02 августа 2020

Теперь я не знаю вашего конкретного приложения. Но я думаю, что проблема заключается в том, что вы создаете значения cdf для ряда нормально распределенных случайных чисел. Ниже вы можете увидеть пример кода, который отображает CDF стандартной нормы от -3 до + 3

import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as plt

x = np.arange(-3, 3, 0.1)
c = norm.cdf(x)

plt.plot(x, c)
plt.show()

CDF стандартной нормы. 1

0 голосов
/ 02 августа 2020

Вы наносите неправильные значения. когда вы выполняете b = norm.rvs(size=siz, random_state=rg), вы получаете 10 независимо выбранных случайных выборок из стандартного нормального распределения, т.е. z значения

, следовательно, их гистограмма представляет собой то, что вы видите в виде колоколообразной кривой.

norm.cdf возвращает значение cfd при заданном значении z. Если вам нужна S-кривая cdf, вы можете равномерно нарисовать от -3 до 3 значений z и получить их значения cdf во всех точках. затем вы наносите на график значения вероятности вывода.

EDIT: другой ответ дает код для этого подхода, поэтому я не буду добавлять снова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...