Як розрахувати ймовірність у нормальному розподілі з урахуванням середнього та стандартного відхилення?


92

Як розрахувати ймовірність нормального розподілу, враховуючи середнє значення std в Python? Я завжди можу явно кодувати власну функцію відповідно до визначення, як це робив OP у цьому питанні: Обчислення ймовірності випадкової змінної у розподілі на Python

Просто цікаво, чи є виклик функції бібліотеки, дозволить вам це зробити. На мою думку, це хотілося б так:

nd = NormalDistribution(mu=100, std=12)
p = nd.prob(98)

У Perl є подібне запитання: як я можу обчислити ймовірність у точці, що має нормальний розподіл у Perl? . Але я не бачив такого в Python.

Numpyмає random.normalфункцію, але це як вибірка, не зовсім те, що я хочу.

Відповіді:


129

У scipy.stats є одна :

>>> import scipy.stats
>>> scipy.stats.norm(0, 1)
<scipy.stats.distributions.rv_frozen object at 0x928352c>
>>> scipy.stats.norm(0, 1).pdf(0)
0.3989422804014327
>>> scipy.stats.norm(0, 1).cdf(0)
0.5
>>> scipy.stats.norm(100, 12)
<scipy.stats.distributions.rv_frozen object at 0x928352c>
>>> scipy.stats.norm(100, 12).pdf(98)
0.032786643008494994
>>> scipy.stats.norm(100, 12).cdf(98)
0.43381616738909634
>>> scipy.stats.norm(100, 12).cdf(100)
0.5

[Одного, чого слід остерігатись - лише підказки - це те, що передавання параметрів є трохи широким. Через спосіб налаштування коду, якщо ви випадково напишете scipy.stats.norm(mean=100, std=12)замість scipy.stats.norm(100, 12)або scipy.stats.norm(loc=100, scale=12), тоді він прийме його, але мовчки відкине ці додаткові аргументи ключового слова і надасть вам значення за замовчуванням (0,1).]


3
Як би ви отримали ймовірності з діапазонів? Скажімо з 98 - 102?
Леон

2
@DSM: У наведеному вище прикладі, коли ви говорите scipy.stats.norm(100, 12).pdf(98), чи означає це ймовірність отримати 98 у розподілі з mean 100 і stddev 12є 0.032?
Шріватсан

14
@ThePredator: ні, ймовірність отримати 98 при нормальному розподілі із середнім значенням 100 і stddev 12 дорівнює нулю. :-) Імовірність щільність становить 0,032.
DSM

Щільність ймовірності в цьому випадку означає значення y, враховуючи значення x 1,42 для нормального розподілу. cdf означає те, що ми називаємо площею під кривою.
подрібнення

5
@ Леон, ось rv.cdf(102) - rv.cdf(98)де rv = scipy.stats.norm(100, 12).
fuglede

47

Scipy.stats - чудовий модуль. Щоб запропонувати інший підхід, ви можете обчислити його безпосередньо, використовуючи

import math
def normpdf(x, mean, sd):
    var = float(sd)**2
    denom = (2*math.pi*var)**.5
    num = math.exp(-(float(x)-float(mean))**2/(2*var))
    return num/denom

Тут використовується формула, яка знаходиться тут: http://en.wikipedia.org/wiki/Normal_distribution#Probability_density_function

тестувати:

>>> normpdf(7,5,5)  
0.07365402806066466
>>> norm(5,5).pdf(7)
0.073654028060664664

Гей, це справді приємна відповідь. Чи не могли б ви надати покрокове пояснення, можливо?
Llamageddon

Цей метод потребує менше часу обчислень, ніж scipy
mkm

Але scipy може обробляти масиви засобів, stdevs та вибірки: середнє = [5, 10, 20] stddev = [20, 30, 40] для x in ([5, 10, 20], [10, 20, 40], [15, 30, 50],): prob = scipy.stats.norm (середнє, stddev) .cdf (x) print (f'prob = {prob} ') виходи: prob = [0,5 0,5 0,5] prob = [ 0,59870633 0,63055866 0,69146246] prob = [0,69146246 0,74750746 0,77337265]
Джон Дейган

16

Ось додаткова інформація . Спочатку ви маєте справу із замороженим розподілом (заморожений в даному випадку означає, що його параметри встановлені на певні значення). Щоб створити заморожений розподіл:

import scipy.stats
scipy.stats.norm(loc=100, scale=12)
#where loc is the mean and scale is the std dev
#if you wish to pull out a random number from your distribution
scipy.stats.norm.rvs(loc=100, scale=12)

#To find the probability that the variable has a value LESS than or equal
#let's say 113, you'd use CDF cumulative Density Function
scipy.stats.norm.cdf(113,100,12)
Output: 0.86066975255037792
#or 86.07% probability

#To find the probability that the variable has a value GREATER than or
#equal to let's say 125, you'd use SF Survival Function 
scipy.stats.norm.sf(125,100,12)
Output: 0.018610425189886332
#or 1.86%

#To find the variate for which the probability is given, let's say the 
#value which needed to provide a 98% probability, you'd use the 
#PPF Percent Point Function
scipy.stats.norm.ppf(.98,100,12)
Output: 124.64498692758187

Я не можу подякувати достатньо тому, хто написав цю відповідь. Я шукав скрізь, щоб це вирішити, але не зміг знайти. А додавання коментарів із кодом справді допомогло мені зрозуміти, що відбувається. Дуже дякую.
бхола прасад,

Просто хочу задати одне питання, як обчислити ці ймовірності, коли дані зазвичай не розподіляються? Що мені робити в цьому випадку?
бхола прасад,

13

Починаючи із того Python 3.8, що стандартна бібліотека надає NormalDistоб’єкт як частину statisticsмодуля.

За його допомогою можна отримати функцію щільності ймовірності ( pdf- ймовірність того, що випадкова вибірка X буде поблизу заданого значення x) для даного середнього значення ( mu) та стандартного відхилення ( sigma):

from statistics import NormalDist

NormalDist(mu=100, sigma=12).pdf(98)
# 0.032786643008494994

Також зауважте, що NormalDistоб'єкт також забезпечує функцію кумулятивного розподілу ( cdf- ймовірність того, що випадкова вибірка X буде меншою або дорівнює x):

NormalDist(mu=100, sigma=12).cdf(98)
# 0.43381616738909634

4

Якщо ви хочете знайти область між 2 значеннями x x = 1; стандартне відхилення = 2; ймовірність x між [0,5,2]

import scipy.stats
scipy.stats.norm(1, 2).cdf(2) - scipy.stats.norm(1,2).cdf(0.5)

3

Формула, наведена у вікіпедії, згадана у відповідях, не може бути використана для обчислення нормальних ймовірностей. Вам потрібно було б записати функцію наближення числового інтегрування, використовуючи цю формулу, щоб обчислити ймовірність.

Ця формула обчислює значення функції щільності ймовірності. Оскільки нормальний розподіл безперервний, вам потрібно обчислити інтеграл, щоб отримати ймовірності. На сайті wikipedia згадується CDF, який не має закритої форми для нормального розповсюдження.


3
Дякуємо за ваш внесок, хоча він більше підходить як коментар до відповіді, на яку ви посилаєтесь: якщо я добре розумію, ви насправді не відповідаєте на вихідне питання. Таким чином, кожен на перший погляд побачить, про що ви говорите.
П’єр Принетті,

1

Я написав цю програму, щоб порахувати за вас. Просто введіть у зведені статистичні дані. Не потрібно надавати масив:

Одиночний Z-тест на частку населення:

Щоб зробити це для середнього значення, а не пропорції, змініть формулу z відповідно

EDIT:
Ось вміст за посиланням:

import scipy.stats as stats
import math

def one_sample_ztest_pop_proportion(tail, p, pbar, n, alpha):
    #Calculate test stat

    sigma = math.sqrt((p*(1-p))/(n))
    z = round((pbar - p) / sigma, 2)

    if tail == 'lower':
        pval = round(stats.norm(p, sigma).cdf(pbar),4)
        print("Results for a lower tailed z-test: ")


    elif tail == 'upper':
        pval = round(1 - stats.norm(p, sigma).cdf(pbar),4)
        print("Results for an upper tailed z-test: ")


    elif tail == 'two':
        pval = round(stats.norm(p, sigma).cdf(pbar)*2,4)
        print("Results for a two tailed z-test: ")


    #Print test results
    print("Test statistic = {}".format(z))   
    print("P-value = {}".format(pval))
    print("Confidence = {}".format(alpha))

    #Compare p-value to confidence level
    if pval <= alpha:
        print("{} <=  {}. Reject the null hypothesis.".format(pval, alpha))
    else:
        print("{} > {}. Do not reject the null hypothesis.".format(pval, alpha))


#one_sample_ztest_pop_proportion('upper', .20, .25, 400, .05)

#one_sample_ztest_pop_proportion('two', .64, .52, 100, .05)

2
Незважаючи на те, що посилання може дати цінну відповідь, SO просить користувачів розміщувати свій код тут на SO. Посилання корисні як посилання, але вони, як правило, через деякий час ламаються, роблячи рішення недоступними для майбутніх відвідувачів.
Містер Т,

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.