OneCompiler

自主學習程式成果

252


程式成果

主程式

本程式只能產生的機率分布為二項分布,
使用者可輸入生成圖片數量n、二項分布次數n、機率p和顯著水準alpha

  • 可產生任意數量的二項分布機率圖
  • 可用紅色在圖表中標出拒絕域
  • 可將機率及圖表存至word檔
  • 程式內有存檔程式,且沒有經過存檔相關調整,因此不建議在未改動的情況直接執行,
    若想實際操作程式可參考底下的拒絕域程式介紹和附錄中的拒絕域雙尾檢定.py
    想進行存檔相關調整可改變程式中的資料夾路徑 folder_path 和 graph_folder_path
import matplotlib.pyplot as plt
import random 
from docx import Document
from docx.shared import Pt
import os                        

# 設定資料與圖片的資料夾路徑
folder_path = r"D:\Ethan\程式\python\bionmial distribution"
graph_folder_path = r"D:\Ethan\程式\python\bionmial distribution\
binomial distribution graph"

# 儲存機率數據與拒絕域文字
Data = []
reject_region_text = []

# 階乘函式
def factorial(n:int):
    n=int(n)
    if n==1 or n==0:
        return 1
    return factorial(n-1)*n
f=factorial  

# 組合函式 C(n,m) = n! / (m! * (n - m)!)
def combination(n:int, m:int):
    n=int(n)
    m=int(m)
    if m > n :
        n,m = m,n
    return int(f(n)/(f(m)*f(n-m)))
c=combination  

# 二項分布公式 P(X=k) = c(n,k)*(p^k)*(q^(n-k))
def binomial_distribution(k:int, n:int, p:float):
    n=int(n)
    p=float(p)
    k=int(k)
    q=1-p
    return (c(n,k)*(p**k)*(q**(n-k)))
bd=binomial_distribution

# 繪製機率分布圖
def drawing(n:int, p:float, alpha:float):

    index = [i for i in range(n+1)]
    output=[bd(i,n,p) for i in range(n+1)]
    Data.append({f'B({n},{p:.3f})': 
    [f'P(X={i})={data}' for i, data in enumerate(output)]})

    filename = "B({},{}).png".format(n,f"{p:.3f}")    
    
    # 繪圖設定
    fig, ax = plt.subplots()
    x_labels = [f"k={i}" for i in index]
    bars = ax.bar(x_labels, output)
    ax.set_title(f'B({n},{p})')
    ax.set_ylabel("P")
    ax.set_xlabel("X=k")

    # 找出拒絕域
    i=0
    while True:
        if sum(output[i::-1]+output[-1*i-1::1])>= alpha:
            i-=1
            reject_region = index[i::-1]+index[-1*i-1::1]
            reject_region_text.append(
            f"X={', '.join(str(k) for k in sorted(reject_region))}是拒絕域"
            )
            break
        i+=1
    
    # 將拒絕域標成紅色
    for bar in bars:
        for num in output[i::-1]+output[-1*i-1::1]:
            if bar.get_height()==num:
                bar.set_color("red")    

    for label in ax.get_xticklabels():
        for index in reject_region:
            if label.get_text() == f"k={index}":
                label.set_color("red")

    # 儲存圖表為PNG
    plt.savefig(os.path.join(graph_folder_path, filename))
    plt.close()


# 刪除舊的 PNG 圖片檔
for file in os.listdir(graph_folder_path):
    if os.path.exists(os.path.join(graph_folder_path, file)):
        os.remove(os.path.join(graph_folder_path, file))

# 刪除舊的 Word 文件
if os.path.exists(os.path.join(folder_path,'binomial distribution.docx')):
    os.remove(os.path.join(folder_path,'binomial distribution.docx'))

# 生成圖片數量、二項分布次數n、機率p和顯著水準alpha在底下的程式修改

m = 10 #圖片數量
n = 100 #二項分布次數
p = random.random() #機率為0到1隨機的有理數
alpha = 0.05 #顯著水準

# 下面程式為生成十組隨機 p 值的B(100,p) 顯著水準為0.05的機率分布圖片
for _ in range(m):
    drawing(n,p,alpha)

# 建立 Word 文件並插入資料與圖片
document = Document()

document.add_heading('Binomial Distribution', 0)
for data in Data:
        for key, val in data.items():
            document.add_paragraph(key)  
        for text in reject_region_text:
            document.add_paragraph(text).style.font.size = Pt(16)
            for p in val:
                document.add_paragraph(p)
            document.add_picture(os.path.join(graph_folder_path,key+".png"))

document.save('binomial distribution.docx')

範例輸出結果
Word檔
binomial distribution.docx

random模組實作練習

為了解決駱駝大賽(一款桌遊)的擲骰不公問題
因為規則關係,值骰結果須分次查看,所以此程式會接收使用者的任意輸入並顯示骰子結果,在輸入q時程式會停止運行
駱駝大賽骰子金字塔.png
上圖為駱駝大賽的擲骰裝置
駱駝大賽骰子.png
上圖為駱駝大賽骰子外觀

import random
dices=["yellow", "blue", "green", "orange", "white"] 
dice_numbers=[1,1,2,2,3,3]
output = {}
for _ in range(5):
	dice=random.choice(dices)
	number=random.choice(dice_numbers)
	output[dice]=number
	dices.remove(dice)

print("press q to exit")
print("press any key to show result")
exit = True
while exit:
	for i, (key, val) in enumerate(output.items()):
		user_input=input()
		if user_input=="q":
			print("program end")
			exit = False
			break
		if user_input:
			if i != len(output)-1:
				print(key+str(val))
			else:
				print("program end")
				exit = False
				break

拒絕域程式

本程式同樣只能產生二項分布的機率分布圖,使用者可輸入二項分布次數n和機率p

from random import random
import matplotlib.pyplot as plt
def factorial(n:int):
    n=int(n)
    if n==1 or n==0:
        return 1
    return factorial(n-1)*n
f=factorial

def combination(n:int, m:int):
    n=int(n)
    m=int(m)
    if m > n :
        n,m = m,n
    return int(f(n)/(f(m)*f(n-m)))
c=combination

def binomial_distribution(k:int, n:int, p:int):
    n=int(n)
    p=float(p)
    k=int(k)
    q=1-p
    return (c(n,k)*(p**k)*(q**(n-k)))
bd=binomial_distribution

#二項分布項數n和機率p(可更改)
n=100
p=0.97

output=[bd(i,n,p) for i in range(n+1)]
index = [i for i in range(n+1)]

fig, ax = plt.subplots()
x_labels = [f"k={i}" for i in index]
bars = ax.bar(x_labels, output)
ax.set_title(f'B({n},{p})')
ax.set_ylabel("P")
ax.set_xlabel("X=k")
i=0
while True:
    if sum(output[i::-1]+output[-1*i-1::1])>= 0.05:
        i-=1
        reject_region = index[i::-1]+index[-1*i-1::1]
        print(f"X={', '.join(str(k) for k in sorted(reject_region))}是拒絕域")
        break
    i+=1

for bar in bars:
    for num in output[i::-1]+output[-1*i-1::1]:
        if bar.get_height()==num:
            bar.set_color("red")

for label in ax.get_xticklabels():
    for index in reject_region:
        if label.get_text() == f"k={index}":
            label.set_color("red")

plt.show()

附錄

主程式
binomial_distribution_正式.py

random模組實作練習
駱駝大賽骰子.py

拒絕域程式
拒絕域雙尾檢定.py