#!/usr/bin/env python # coding: utf-8 # # ให้คอมพิวเตอร์นับจำนวน คำนวณความน่าจะเป็น # # คอมพิวเตอร์ทำงานหลายๆอย่างได้เร็วมาก สามารถช่วยแก้ปัญหาที่คนทำแล้วเหนื่อยหรือไม่อยากทำ เช่นคราวนี้เราจะให้มันคำนวณความน่าจะเป็นให้ # # คำถามมีอยู่ว่า: ซื้อขนมชนิดนึง ในกล่องมีให้สะสมตุ๊กตากล่องละแบบ มีตุ๊กตาทั้งหมด 4 แบบ สะสมครบ 4 แบบจะได้รับรางวัลพิเศษ เราไม่รู้ว่าแต่ละกล่องมีตุ๊กตาแบบไหนแต่ตุ๊กตาแต่ละตัวมีโอกาสเท่าๆกันที่จะอยู่ในขนมแต่ละกล่อง ถ้าซื้อขนมนี้มา 8 กล่องถามว่าความน่าจะเป็นที่จะได้รางวัลพิเศษมีเท่าไหร่ # # เราจะแก้ปัญหานี้โดยให้คอมพิวเตอร์สร้างรูปแบบที่ขนม 8 กล่องจะเป็นไปได้ทั้งหมด ดูว่ารูปแบบไหนมีตุ๊กตาครบ 4 แบบ แล้วคำนวณความน่าจะเป็นที่จะได้รางวัลพิเศษ # # เราเรียกตุ๊กตาว่ามีแบบที่ 1, 2, 3, 4 ดังนี้: # In[1]: ตุ๊กตา = (1,2,3,4) # เราสร้างรูปแบบขนม 8 กล่องที่เป็นได้ทั้งหมด และนับว่ารูปแบบไหนมีตุ๊กตาครบ 4 แบบดังนี้: # In[2]: แบบที่เป็นไปได้ = 0 แบบที่ได้รางวัล = 0 for a in ตุ๊กตา: for b in ตุ๊กตา: for c in ตุ๊กตา: for d in ตุ๊กตา: for e in ตุ๊กตา: for f in ตุ๊กตา: for g in ตุ๊กตา: for h in ตุ๊กตา: แบบที่เป็นไปได้ = แบบที่เป็นไปได้ + 1 รูปแบบ = (a,b,c,d,e,f,g,h) #ดูว่าได้รางวัลหรือไม่ คือดูว่า 1,2,3,4 ต้องมีใน 8 กล่อง if 1 in รูปแบบ and 2 in รูปแบบ and 3 in รูปแบบ and 4 in รูปแบบ: แบบที่ได้รางวัล = แบบที่ได้รางวัล + 1 print(f"จำนวนแบบที่เป็นไปได้ทั้งหมด = {แบบที่เป็นไปได้}") print(f"จำนวนแบบที่ได้รางวัล = {แบบที่ได้รางวัล}") print(f"ความน่าจะเป็นที่จะได้รางวัล = {100 * แบบที่ได้รางวัล/แบบที่เป็นไปได้:.1f}%") # เราหัดใช้ [all()](https://www.programiz.com/python-programming/methods/built-in/all) และ [any()](https://www.programiz.com/python-programming/methods/built-in/any) เพื่อตรวจดูว่าสมาชิกทุกตัวในลิสต์เป็นจริง หรือสมาชิกบางตัวในหลิสต์เป็นจริงหรือไม่ (all และ any ใช้กับสิ่งอื่นๆที่เรียกว่า iterable เช่น dictionary, tuple, string, range,... ได้ด้วย) # In[3]: def ได้รางวัล(รูปแบบขนม): ตุ๊กตาอยู่ในขนมไหม = [x in รูปแบบขนม for x in ตุ๊กตา] #จะเป็นลิสต์ยาวเท่ากับจำนวนตุ๊กตา #โดยสมาชิกแต่ละตัวจะเป็น True หรือ False #ขึ้นกับว่าตุ๊กตาแบบนั้นอยู่ในรูปแบบขนมหรือไม่ return all(ตุ๊กตาอยู่ในขนมไหม) #ให้ค่าเป็น True เมื่อตุ๊กตาทุกแบบมีอยู่ในขนม # In[4]: # (1,2,3,4,3,2,1,4) มีตุ๊กตาครบทุกแบบ 1,2,3,4 ได้รางวัล((1,2,3,4,3,2,1,4)) # In[5]: # (1,1,1,1,1,2,2,3) มีตุ๊กตาไม่ครบ ขาดแบบที่ 4 ไป ได้รางวัล((1,1,1,1,1,2,2,3)) # เราเลยเขียนโปรแกรมเราดูอีกทีโดยใช้ all() ด้วย: # In[6]: ตุ๊กตา = (1,2,3,4) def ได้รางวัล(รูปแบบขนม): ตุ๊กตาอยู่ในขนมไหม = [x in รูปแบบขนม for x in ตุ๊กตา] #จะเป็นลิสต์ยาวเท่ากับจำนวนตุ๊กตา #โดยสมาชิกแต่ละตัวจะเป็น True หรือ False #ขึ้นกับว่าตุ๊กตาแบบนั้นอยู่ในรูปแบบขนมหรือไม่ return all(ตุ๊กตาอยู่ในขนมไหม) #ให้ค่าเป็น True เมื่อตุ๊กตาทุกแบบมีอยู่ในขนม แบบที่เป็นไปได้ = 0 แบบที่ได้รางวัล = 0 for a in ตุ๊กตา: for b in ตุ๊กตา: for c in ตุ๊กตา: for d in ตุ๊กตา: for e in ตุ๊กตา: for f in ตุ๊กตา: for g in ตุ๊กตา: for h in ตุ๊กตา: แบบที่เป็นไปได้ += 1 #หัดใช้ += ความหมายของ x += 1 คือ x = x + 1 รูปแบบ = (a,b,c,d,e,f,g,h) if ได้รางวัล(รูปแบบ): #ใช้ฟังก์ชั่น ได้รางวัล() ที่ใช้ all() ข้างบน แบบที่ได้รางวัล += 1 #หัดใช้ += print(f"จำนวนแบบที่เป็นไปได้ทั้งหมด = {แบบที่เป็นไปได้}") print(f"จำนวนแบบที่ได้รางวัล = {แบบที่ได้รางวัล}") print(f"ความน่าจะเป็นที่จะได้รางวัล = {100 * แบบที่ได้รางวัล/แบบที่เป็นไปได้:.1f}%") # ทดลองคำนวณความน่าจะเป็นถ้าซื้อแค่ 3 กล่อง ซึ่งไม่มีทางที่จะได้รางวัลเพราะของเล่นมีอย่างมาก 3 แบบ: # In[7]: #ซื้อขนม 3 กล่อง ตุ๊กตา = (1,2,3,4) def ได้รางวัล(รูปแบบขนม): ตุ๊กตาอยู่ในขนมไหม = [x in รูปแบบขนม for x in ตุ๊กตา] return all(ตุ๊กตาอยู่ในขนมไหม) #ให้ค่าเป็น True เมื่อตุ๊กตาทุกแบบมีอยู่ในขนม แบบที่เป็นไปได้ = 0 แบบที่ได้รางวัล = 0 for a in ตุ๊กตา: for b in ตุ๊กตา: for c in ตุ๊กตา: แบบที่เป็นไปได้ += 1 รูปแบบ = (a,b,c) if ได้รางวัล(รูปแบบ): แบบที่ได้รางวัล += 1 print(f"จำนวนแบบที่เป็นไปได้ทั้งหมด = {แบบที่เป็นไปได้}") print(f"จำนวนแบบที่ได้รางวัล = {แบบที่ได้รางวัล}") print(f"ความน่าจะเป็นที่จะได้รางวัล = {100 * แบบที่ได้รางวัล/แบบที่เป็นไปได้:.1f}%") # ทดลองคำนวณความน่าจะเป็นถ้าซื้อ 4 กล่อง: # In[8]: #ซื้อขนม 4 กล่อง ตุ๊กตา = (1,2,3,4) def ได้รางวัล(รูปแบบขนม): ตุ๊กตาอยู่ในขนมไหม = [x in รูปแบบขนม for x in ตุ๊กตา] return all(ตุ๊กตาอยู่ในขนมไหม) #ให้ค่าเป็น True เมื่อตุ๊กตาทุกแบบมีอยู่ในขนม แบบที่เป็นไปได้ = 0 แบบที่ได้รางวัล = 0 for a in ตุ๊กตา: for b in ตุ๊กตา: for c in ตุ๊กตา: for d in ตุ๊กตา: แบบที่เป็นไปได้ += 1 รูปแบบ = (a,b,c,d) if ได้รางวัล(รูปแบบ): แบบที่ได้รางวัล += 1 print(f"จำนวนแบบที่เป็นไปได้ทั้งหมด = {แบบที่เป็นไปได้}") print(f"จำนวนแบบที่ได้รางวัล = {แบบที่ได้รางวัล}") print(f"ความน่าจะเป็นที่จะได้รางวัล = {100 * แบบที่ได้รางวัล/แบบที่เป็นไปได้:.1f}%") # ทดลองคำนวณความน่าจะเป็นถ้าซื้อ 5 กล่อง: # In[9]: #ซื้อขนม 5 กล่อง ตุ๊กตา = (1,2,3,4) def ได้รางวัล(รูปแบบขนม): ตุ๊กตาอยู่ในขนมไหม = [x in รูปแบบขนม for x in ตุ๊กตา] return all(ตุ๊กตาอยู่ในขนมไหม) #ให้ค่าเป็น True เมื่อตุ๊กตาทุกแบบมีอยู่ในขนม แบบที่เป็นไปได้ = 0 แบบที่ได้รางวัล = 0 for a in ตุ๊กตา: for b in ตุ๊กตา: for c in ตุ๊กตา: for d in ตุ๊กตา: for e in ตุ๊กตา: แบบที่เป็นไปได้ += 1 รูปแบบ = (a,b,c,d,e) if ได้รางวัล(รูปแบบ): แบบที่ได้รางวัล += 1 print(f"จำนวนแบบที่เป็นไปได้ทั้งหมด = {แบบที่เป็นไปได้}") print(f"จำนวนแบบที่ได้รางวัล = {แบบที่ได้รางวัล}") print(f"ความน่าจะเป็นที่จะได้รางวัล = {100 * แบบที่ได้รางวัล/แบบที่เป็นไปได้:.1f}%") # ทดลองคำนวณความน่าจะเป็นถ้าซื้อ 6 กล่อง: # In[10]: #ซื้อขนม 6 กล่อง ตุ๊กตา = (1,2,3,4) def ได้รางวัล(รูปแบบขนม): ตุ๊กตาอยู่ในขนมไหม = [x in รูปแบบขนม for x in ตุ๊กตา] return all(ตุ๊กตาอยู่ในขนมไหม) #ให้ค่าเป็น True เมื่อตุ๊กตาทุกแบบมีอยู่ในขนม แบบที่เป็นไปได้ = 0 แบบที่ได้รางวัล = 0 for a in ตุ๊กตา: for b in ตุ๊กตา: for c in ตุ๊กตา: for d in ตุ๊กตา: for e in ตุ๊กตา: for f in ตุ๊กตา: แบบที่เป็นไปได้ += 1 รูปแบบ = (a,b,c,d,e,f) if ได้รางวัล(รูปแบบ): แบบที่ได้รางวัล += 1 print(f"จำนวนแบบที่เป็นไปได้ทั้งหมด = {แบบที่เป็นไปได้}") print(f"จำนวนแบบที่ได้รางวัล = {แบบที่ได้รางวัล}") print(f"ความน่าจะเป็นที่จะได้รางวัล = {100 * แบบที่ได้รางวัล/แบบที่เป็นไปได้:.1f}%") # ทดลองคำนวณความน่าจะเป็นถ้าซื้อ 7 กล่อง จะพบว่าความน่าจะเป็นเริ่มเกิน 50%: # In[11]: #ซื้อขนม 7 กล่อง ตุ๊กตา = (1,2,3,4) def ได้รางวัล(รูปแบบขนม): ตุ๊กตาอยู่ในขนมไหม = [x in รูปแบบขนม for x in ตุ๊กตา] return all(ตุ๊กตาอยู่ในขนมไหม) #ให้ค่าเป็น True เมื่อตุ๊กตาทุกแบบมีอยู่ในขนม แบบที่เป็นไปได้ = 0 แบบที่ได้รางวัล = 0 for a in ตุ๊กตา: for b in ตุ๊กตา: for c in ตุ๊กตา: for d in ตุ๊กตา: for e in ตุ๊กตา: for f in ตุ๊กตา: for g in ตุ๊กตา: แบบที่เป็นไปได้ += 1 รูปแบบ = (a,b,c,d,e,f,g) if ได้รางวัล(รูปแบบ): แบบที่ได้รางวัล += 1 print(f"จำนวนแบบที่เป็นไปได้ทั้งหมด = {แบบที่เป็นไปได้}") print(f"จำนวนแบบที่ได้รางวัล = {แบบที่ได้รางวัล}") print(f"ความน่าจะเป็นที่จะได้รางวัล = {100 * แบบที่ได้รางวัล/แบบที่เป็นไปได้:.1f}%") # ทดลองคำนวณความน่าจะเป็นถ้าซื้อ 9 กล่อง: # In[12]: #ซื้อขนม 9 กล่อง ตุ๊กตา = (1,2,3,4) def ได้รางวัล(รูปแบบขนม): ตุ๊กตาอยู่ในขนมไหม = [x in รูปแบบขนม for x in ตุ๊กตา] return all(ตุ๊กตาอยู่ในขนมไหม) #ให้ค่าเป็น True เมื่อตุ๊กตาทุกแบบมีอยู่ในขนม แบบที่เป็นไปได้ = 0 แบบที่ได้รางวัล = 0 for a in ตุ๊กตา: for b in ตุ๊กตา: for c in ตุ๊กตา: for d in ตุ๊กตา: for e in ตุ๊กตา: for f in ตุ๊กตา: for g in ตุ๊กตา: for h in ตุ๊กตา: for i in ตุ๊กตา: แบบที่เป็นไปได้ += 1 รูปแบบ = (a,b,c,d,e,f,g,h,i) if ได้รางวัล(รูปแบบ): แบบที่ได้รางวัล += 1 print(f"จำนวนแบบที่เป็นไปได้ทั้งหมด = {แบบที่เป็นไปได้}") print(f"จำนวนแบบที่ได้รางวัล = {แบบที่ได้รางวัล}") print(f"ความน่าจะเป็นที่จะได้รางวัล = {100 * แบบที่ได้รางวัล/แบบที่เป็นไปได้:.1f}%") # ทดลองคำนวณความน่าจะเป็นถ้าซื้อ 10 กล่อง: # In[13]: #ซื้อขนม 10 กล่อง ตุ๊กตา = (1,2,3,4) def ได้รางวัล(รูปแบบขนม): ตุ๊กตาอยู่ในขนมไหม = [x in รูปแบบขนม for x in ตุ๊กตา] return all(ตุ๊กตาอยู่ในขนมไหม) #ให้ค่าเป็น True เมื่อตุ๊กตาทุกแบบมีอยู่ในขนม แบบที่เป็นไปได้ = 0 แบบที่ได้รางวัล = 0 for a in ตุ๊กตา: for b in ตุ๊กตา: for c in ตุ๊กตา: for d in ตุ๊กตา: for e in ตุ๊กตา: for f in ตุ๊กตา: for g in ตุ๊กตา: for h in ตุ๊กตา: for i in ตุ๊กตา: for j in ตุ๊กตา: แบบที่เป็นไปได้ += 1 รูปแบบ = (a,b,c,d,e,f,g,h,i,j) if ได้รางวัล(รูปแบบ): แบบที่ได้รางวัล += 1 print(f"จำนวนแบบที่เป็นไปได้ทั้งหมด = {แบบที่เป็นไปได้}") print(f"จำนวนแบบที่ได้รางวัล = {แบบที่ได้รางวัล}") print(f"ความน่าจะเป็นที่จะได้รางวัล = {100 * แบบที่ได้รางวัล/แบบที่เป็นไปได้:.1f}%") # # Advanced Topics: ใช้ itertools.product # # ถ้าเราสนใจจะเขียนฟังก์ชั่นที่คำนวณความน่าจะเป็นเมื่อซื้อขนมกี่กล่องก็ได้โดยไม่ต้องก๊อปปี้โค้ดแล้วแก้ด้วยมือ เราสามารถใช้ความสามารถของ [itertools.product()](https://docs.python.org/3/library/itertools.html#itertools.product) ได้ # # itertools.product(A,B) ทำหน้าที่วนเอาของใน A, B มาให้เราเหมือน # # for a in A: # for b in B: # ... # # หรือถ้ามีวนสามชั้น itertools.product(A,B,C) ก็วนเอาของใน A, B, C มาให้เราเหมือน # # for a in A: # for b in B: # for c in C: # ... # # นอกจากนี้เราสามารถใส่ตัวแปร repeat ให้ itertools.product วนเอาของจาก A ซ้ำๆได้ด้วยเช่น itertools.product(A, repeat=3) จะวนเอาของใน A มาให้สามชั้นเหมือน # # for a in A: # for b in A: # for c in A: # ... # # ตัวอย่างเช่นถ้าซื้อขนมมาสองกล่อง รูปแบบตุ๊กตาที่เป็นไปได้ก็จะมี 16 แบบดังนี้: # In[14]: import itertools for รูปแบบ in itertools.product(ตุ๊กตา, repeat=2): print(รูปแบบ) # เราจึงสามารถเขียนฟังก์ชั่นคำนวณความน่าจะเป็นเมื่อซื้อขนมกี่กล่องก็ได้ดังนี้: # In[15]: import itertools ตุ๊กตา = (1,2,3,4) def ได้รางวัล(รูปแบบขนม): ตุ๊กตาอยู่ในขนมไหม = [x in รูปแบบขนม for x in ตุ๊กตา] #จะเป็นลิสต์ยาวเท่ากับจำนวนตุ๊กตา #โดยสมาชิกแต่ละตัวจะเป็น True หรือ False #ขึ้นกับว่าตุ๊กตาแบบนั้นอยู่ในรูปแบบขนมหรือไม่ return all(ตุ๊กตาอยู่ในขนมไหม) #ให้ค่าเป็น True เมื่อตุ๊กตาทุกแบบมีอยู่ในขนม def แสดงความน่าจะเป็นเมื่อซื้อขนม_N_กล่อง(N): แบบที่เป็นไปได้ = 0 แบบที่ได้รางวัล = 0 for รูปแบบ in itertools.product(ตุ๊กตา, repeat = N): แบบที่เป็นไปได้ += 1 if ได้รางวัล(รูปแบบ): แบบที่ได้รางวัล += 1 print(f"ขนม {N} กล่อง: จำนวนแบบที่เป็นไปได้ทั้งหมด = {แบบที่เป็นไปได้}") print(f"ขนม {N} กล่อง: จำนวนแบบที่ได้รางวัล = {แบบที่ได้รางวัล}") print(f"ขนม {N} กล่อง: ความน่าจะเป็นที่จะได้รางวัล = {100 * แบบที่ได้รางวัล/แบบที่เป็นไปได้:.1f}%") # In[16]: #ทดลองกับ 8 กล่อง: แสดงความน่าจะเป็นเมื่อซื้อขนม_N_กล่อง(8) # In[17]: #ลองไล่ไปถึง 12 กล่อง: for n in range(0,13): แสดงความน่าจะเป็นเมื่อซื้อขนม_N_กล่อง(n) print("-"*50) # จำนวนแบบที่เป็นไปได้เพิ่มขึ้นรวดเร็วมากเมื่อจำนวนกล่องเพิ่ม (เท่ากับ $4^{N}$ เมื่อ $N$ คือจำนวนกล่อง) ถ้าเราซื้อ 20 กล่อง จำนวนที่เป็นไปได้จะเป็นล้านล้านแบบ (เลข 12 หลัก) ถ้าซื้อ 30 กล่อง จำนวนที่เป็นไปได้จะเป็นล้านล้านล้านแบบ (เลข 18 หลัก) เราต้องใช้วิธีอื่นประมาณความน่าจะเป็น # # วิธีสุ่ม (Sampling) # # เราสามารถใช้คอมพิวเตอร์ประมาณความน่าจะเป็นที่เราไม่สามารถแจกแจงทุกรูปแบบที่เป็นไปได้โดยการสุ่ม วิธีก็ง่ายมากคือสมมุติให้คอมพิวเตอร์เข้าไปซื้อขนมหลายๆครั้ง แล้วดูว่าได้รางวัลกี่ครั้ง อัตราส่วนจำนวนครั้งที่ได้รางวัลต่อจำนวนครั้งที่เข้าไปซื้อก็คือค่าประมาณของความน่าจะเป็นที่ได้รางวัล # # ตัวอย่างโค้ดที่ให้คอมพิวเตอร์ลองซื้อขนมหลายๆครั้งเป็นดังนี้: # In[18]: import random #จะใช้ random.choice()เพื่อสุ่มเลือกตุ๊กตา ตุ๊กตา = (1,2,3,4) def ซื้อ_N_กล่อง(N): #จะให้รูปแบบกล่องที่มีตุ๊กตาสุ่มมาเมื่อซื้อขนม N กล่อง รูปแบบ = [] for i in range(N): รูปแบบ.append(random.choice(ตุ๊กตา)) return รูปแบบ def ได้รางวัล(รูปแบบขนม): ตุ๊กตาอยู่ในขนมไหม = [x in รูปแบบขนม for x in ตุ๊กตา] #จะเป็นลิสต์ยาวเท่ากับจำนวนตุ๊กตา #โดยสมาชิกแต่ละตัวจะเป็น True หรือ False #ขึ้นกับว่าตุ๊กตาแบบนั้นอยู่ในรูปแบบขนมหรือไม่ return all(ตุ๊กตาอยู่ในขนมไหม) #ให้ค่าเป็น True เมื่อตุ๊กตาทุกแบบมีอยู่ในขนม def ประมาณความน่าจะเป็นเมื่อซื้อ_N_กล่อง(N, จำนวนครั้งที่ลองซื้อ): จำนวนครั้งที่ได้รางวัล = 0 for i in range(จำนวนครั้งที่ลองซื้อ + 1): รูปแบบ = ซื้อ_N_กล่อง(N) if ได้รางวัล(รูปแบบ): จำนวนครั้งที่ได้รางวัล += 1 print(f"ความน่าจะเป็นโดยประมาณที่จะได้รางวัลเมื่อซื้อ {N} กล่อง = {100* จำนวนครั้งที่ได้รางวัล/จำนวนครั้งที่ลองซื้อ:.1f}") # In[19]: #ทดลองกับ 8 กล่อง ประมาณความน่าจะเป็นเมื่อซื้อ_N_กล่อง(8,10_000) # In[20]: #ลองกับหลายๆกล่อง จำนวนครั้งที่ลอง = 100_000 for i in range(31): ประมาณความน่าจะเป็นเมื่อซื้อ_N_กล่อง(i, จำนวนครั้งที่ลอง) # ถ้าวาดเป็นกราฟจะมีหน้าตาประมาณนี้: # # ![Screen%20Shot%202562-11-23%20at%2012.15.07.jpg](attachment:Screen%20Shot%202562-11-23%20at%2012.15.07.jpg) # In[ ]: