วิธีการคำนวณความน่าจะเป็นในการแจกแจงปกติโดยให้ค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐาน?


93

วิธีการคำนวณความน่าจะเป็นในการแจกแจงปกติค่าเฉลี่ยที่กำหนด std ใน Python ฉันสามารถเขียนโค้ดฟังก์ชันของตัวเองอย่างชัดเจนได้ตลอดเวลาตามคำจำกัดความเช่นเดียวกับ OP ในคำถามนี้: การคำนวณความน่าจะเป็นของตัวแปรสุ่มในการกระจายใน Python

เพียงแค่สงสัยว่ามีการเรียกใช้ฟังก์ชันไลบรารีจะช่วยให้คุณทำสิ่งนี้ได้หรือไม่ ในจินตนาการของฉันมันต้องการสิ่งนี้:

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

มีคำถามที่คล้ายกันใน Perl: ฉันจะคำนวณความน่าจะเป็น ณ จุดหนึ่งที่แจกแจงปกติใน Perl ได้อย่างไร . แต่ฉันไม่เห็นหนึ่งใน Python

Numpyมีrandom.normalฟังก์ชัน แต่เหมือนกับการสุ่มตัวอย่างไม่ใช่สิ่งที่ฉันต้องการ

คำตอบ:


130

มีหนึ่งใน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?
Leon

2
@DSM: ในตัวอย่างข้างต้นของคุณเมื่อคุณพูดscipy.stats.norm(100, 12).pdf(98)นั่นหมายถึงความน่าจะเป็นที่จะได้รับ 98 ในการแจกแจงด้วยmean 100 และstddev 12คือ0.032อะไร?
Srivatsan

14
@ThePredator: ไม่ความน่าจะเป็นที่จะได้ 98 ในการแจกแจงปกติโดยมีค่าเฉลี่ย 100 และ stddev 12 เป็นศูนย์ :-) ความหนาแน่นของความน่าจะเป็นคือ 0.032
DSM

ความหนาแน่นของความน่าจะเป็นในกรณีนั้นหมายถึงค่า y ที่กำหนด x-value 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 สามารถจัดการอาร์เรย์ของวิธีการมาตรฐานและตัวอย่าง: mean = [5, 10, 20] stddev = [20, 30, 40] สำหรับ x ใน ([5, 10, 20], [10, 20, 40], [15, 30, 50],): prob = scipy.stats.norm (mean, 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]
John Deighan

17

นี่คือข้อมูลเพิ่มเติม ก่อนอื่นคุณต้องจัดการกับการกระจายแบบเยือกแข็ง (ในกรณีนี้การตรึงหมายความว่าพารามิเตอร์ถูกตั้งค่าเป็นค่าเฉพาะ) ในการสร้างการกระจายแบบแช่แข็ง:

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

ฉันไม่สามารถขอบคุณใครที่เขียนคำตอบนี้ได้ ฉันมองหาทุกที่เพื่อแก้ปัญหานี้ แต่ไม่พบ และการเพิ่มความคิดเห็นด้วยรหัสช่วยให้ฉันเข้าใจสิ่งที่เกิดขึ้น ขอบคุณมาก.
bhola prasad

แค่อยากถามคำถามเดียวว่าจะคำนวณความน่าจะเป็นเหล่านี้ได้อย่างไรเมื่อข้อมูลไม่กระจายตามปกติ ฉันต้องทำอย่างไรในกรณีนี้?
bhola prasad

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

6

ในกรณีที่คุณต้องการหาพื้นที่ระหว่าง 2 ค่าของ x mean = 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

สูตรที่อ้างถึงจากวิกิพีเดียที่กล่าวถึงในคำตอบไม่สามารถใช้คำนวณความน่าจะเป็นปกติได้ คุณจะต้องเขียนฟังก์ชันการประมาณค่าการรวมเชิงตัวเลขโดยใช้สูตรนั้นเพื่อคำนวณความน่าจะเป็น

สูตรนั้นจะคำนวณค่าสำหรับฟังก์ชันความหนาแน่นของความน่าจะเป็น เนื่องจากการแจกแจงปกติเป็นแบบต่อเนื่องคุณจึงต้องคำนวณอินทิกรัลเพื่อให้ได้ความน่าจะเป็น เว็บไซต์วิกิพีเดียกล่าวถึง CDF ซึ่งไม่มีรูปแบบปิดสำหรับการแจกแจงปกติ


3
ขอบคุณสำหรับการสนับสนุนของคุณแม้ว่ามันจะเหมาะสมกว่าในการแสดงความคิดเห็นสำหรับคำตอบที่คุณอ้างถึง: ถ้าฉันเข้าใจดีคุณก็ไม่ได้ตอบคำถามเดิมจริงๆ วิธีนี้ทุกคนจะเห็นได้อย่างรวดเร็วก่อนว่าคุณกำลังพูดถึงอะไร
Pierre Prinetti

1

ฉันเขียนโปรแกรมนี้เพื่อทำคณิตศาสตร์ให้คุณ เพียงแค่ใส่สถิติสรุป ไม่จำเป็นต้องจัดเตรียมอาร์เรย์:

การทดสอบ Z หนึ่งตัวอย่างสำหรับสัดส่วนประชากร:

หากต้องการทำสิ่งนี้เพื่อหาค่าเฉลี่ยแทนที่จะเป็นสัดส่วนให้เปลี่ยนสูตรสำหรับ z ตามนั้น

แก้ไข:
นี่คือเนื้อหาจากลิงค์:

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 Links มีประโยชน์ในการอ้างอิง แต่พวกเขามักจะพังหลังจากนั้นสักครู่ทำให้ไม่สามารถเข้าถึงโซลูชันสำหรับผู้เยี่ยมชมในอนาคตได้
นาย T

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.