Tag Archives: ไพธอน

วิทย์ม.ต้น: StanDard Error of Mean = SEM = ประมาณคุณภาพของคำตอบจากการสุ่ม, “ปัญหาเลือกคู่” (Optimal Stopping Problem)

สัปดาห์ที่แล้วเด็กๆม.2-3 รู้จักการสุ่มหาคำตอบเมื่อปัญหาใหญ่เกินกำลังที่จะแก้แบบเป๊ะๆได้ สัปดาห์นี้จึงมาเข้าใจว่าคำตอบที่สุ่มได้มาพอเชื่อได้แค่ไหน

วิธีตรงไปตรงมาเข้าใจง่ายก็คือลองสุ่มหลายๆรอบแล้วเก็บคำตอบการสุ่มแต่ละรอบเอาไว้ แล้วเอาคำตอบที่เก็บไว้ทั้งหมดมาหาค่าเฉลี่ย (mean) และค่าเบี่ยงเบนของค่าเฉลี่ย (standard error of mean หรือ SEM) ถ้า SEM เล็กคำตอบก็พอเชื่อถือได้

เราคำนวณ SEM จาก ค่าเบี่ยงเบนมาตรฐานของตัวอย่าง (sample standard deviation หรือ s) กัน โดยที่ SEM = s/รูทที่สองของจำนวนคำตอบที่เก็บมา

เด็กๆรู้จักวิธีคำนวณ mean และ sample standard deviation แบบหน้าตาประมาณนี้:

แต่จริงๆแล้วเราสามารถใช้ฟังก์ชั่นที่มีในไพธอนอยู่แล้วมาคำนวณให้ก็ได้คือฟังก์ชั่น numpy.mean() และ numpy.std()

ใส่ doff = 1 ใน numpy.std() เพื่อหา sample standard deviation

หน้าตาของการหาค่าเฉลี่ยและ SEM ก็จะเป็นประมาณนี้ (เก็บข้อมูล n_trials ครั้ง):

ถ้าเก็บคำตอบมาหลายครั้ง (จำนวนครั้ง = n_trials) เราก็จะมั่นใจในคำตอบมากขึ้นเมื่อ SEM เล็กลงเรื่อยๆแบบนี้:

ผมแนะนำให้เด็กๆรู้จักกับ “ปัญหาเลือกคู่” (marriage problem หรือ secretary problem) หรือรู้จักในชื่อทั่วไปคือ optimal stopping problem คือสมมุติว่าเรามีโอกาสคบคนทั้งหมด n คน โดยที่ต้องคบทีละคน และต้องเลิกคบกับคนปัจจุบันก่อนที่จะไปคบคนต่อไป เมื่อเลิกคบกับใครแล้วห้ามกลับไปคบกับเขาอีก แล้วต้องตัดสินใจว่าจะเลือกใครเป็นคู่ โดยหวังว่าจะเลือกคนที่ดีที่สุดใน n คนนี้

ปรากฎว่ามีวิธีที่ทำให้เรามีโอกาสประมาณ 37% ที่จะเลือกคนที่ดีที่สุดได้ ไม่ว่าจำนวน n จะเป็น 3, 10, 100, หรือ 1 ล้าน คือให้คบคนไป n/e คนก่อน (e เป็นค่าคงที่ 2.71828… เรียกว่าค่าอีหรือค่าคงที่ของออยเลอร์) อย่าพึ่งเลือกคนเหล่านี้ จากนั้นให้เลือกคนแรกที่ดีกว่าคนที่เคยคบมา (หรือเลือกคนสุดท้ายเมื่อไม่เหลือใครแล้ว) ยกตัวอย่างเช่นถ้าเราคิดว่าคงมีเวลาคบคน 10 คน ค่า n ของเราก็คือ 10 ดังนั้นให้เราคบไป 10/e = 10/2.71828… = 3.6787.. เท่ากับประมาณ 4 โดยที่เรายังไม่ตัดสินใจเลือกใครใน 4 คนนี้ ต่อไปเราคบกับคนที่เหลือทีละคน แล้วเลือกคนแรกที่ดีกว่าคนที่เราเคยคบมา ถ้าหาไม่ได้ก็เลือกคนสุดท้าย

สำหรับการบ้านเด็กๆสัปดาห์นี้ ผมให้เด็กๆไปเขียนโปรแกรมตรวจว่าวิธีเลือกคู่แบบนี้ได้ผลจริงๆไหมสำหรับ n ต่างๆ

วิธีเลือกแบบนี้เป็นเรื่องเดียวกับการเลือกห้องน้ำในคอนเสิร์ตด้วยครับ 😃:

ถ้าสนใจว่า n/e มาได้อย่างไร ดูวิดีโอข้างบน จะมีลิงก์ไปวิดีโอที่แสดงวิธี หรืออ่านที่นี่ก็ได้ครับ

วิทย์ม.ต้น: ม.1 หัดเขียนฟังก์ชั่นในไพธอน, ค่าพายมาจากการบวกซ้ำๆได้ด้วย!

สัปดาห์นี้เด็กๆม.1 รู้จักเขียนฟังก์ชั่นเพื่อทำงานซ้ำๆหรืองานคล้ายๆกันครับ เริ่มจากการสั่งให้คอมพิวเตอร์บวกเลขให้เรา 1+2+3+…+1,000,000:

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

แบบฝึกหัดในห้องคือให้เด็กๆหัดเขียนฟังชั่นที่รวมกำลังสอง และกำลังสามของตัวเลขต่างๆกันดู

สักพักเด็กๆก็เขียนเป็นฟังก์ชั่นหน้าตาประมาณนี้ (ผมกำหนดชื่อฟังก์ชั่นไว้เป็น sumsqr และ sum3rd ย่อมาจาก sum of square คือบวกเลขยกกำลังสอง และ sum of 3rd power คือบวกเลขยกกำลังสาม):

เราทดลองพิมพ์ค่า n, ผลรวมจาก 1 ถึง n, ผลรวมกำลังสองของ 1 ถึง n, และ ผลรวมกำลังสามของ 1 ถึง n กันดู:

เมื่อผมทำให้เด็กประหลาดใจที่ผมสามารถหาผลรวมของกำลังสามในใจได้เร็วกว่าที่เด็กๆคิด ผมก็บอกเด็กๆว่ามันมีความสัมพันธ์กันอยู่ที่ว่า (1 + 2 + 3 + … + n)2 = 13 + 23 + 33 + … + n3 และ เราหา (1 + 2 + 3 + … + n) ได้ง่ายเพราะเหมือนการจับคู่หัวท้ายแล้วคูณด้วยจำนวนคู่ = 1/2 n (n+1)

ผมถามเด็กๆว่าถ้าเราต้องการคำนวณยกกำลังอื่นๆอีกจะทำอย่างไร ต้องเข้าไปสร้างฟังก์ชั่นใหม่ๆเรื่อยๆไหม ปรากฎว่าเราสามารถสร้างฟังก์ชั่นที่รับค่ายกกำลัง และค่าที่ว่าจะให้รวมถึงแค่ไหนก็สามารถใช้คำนวณยกกำลังอื่นๆได้เลย ไม่ต้องสร้างฟังก์ชั่นใหม่ๆสำหรับกำลังใหม่ๆ หน้าตาก็จะเป็นประมาณนี้:

ผมลองรวมยกกำลัง -2 ดู ให้คำนวณ 1/12 + 1/22 + 1/32 + … + 1/1,000,0002 ดูปรากฎว่าใกล้เคียงกับค่า π2/6 มาก:

เด็กๆก็ตื่นเต้นว่าค่า π มาเกี่ยวข้องกับผลรวมอย่างนี้ได้อย่างไร จริงๆแล้วเมื่อกำลังเป็นเลขคู่ที่เป็นลบจะมีความเกี่ยวข้องกับ Riemann zeta function ที่มีคนค้นพบว่ามีค่า π ติดอยู่ดังนี้ครับ:

จาก https://en.wikipedia.org/wiki/Particular_values_of_the_Riemann_zeta_function

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

วิทย์ม.ต้น: ให้คอมพิวเตอร์คำนวณความน่าจะเป็น และใช้วิธีสุ่ม (sampling) เมื่อปัญหาใหญ่เกิน

(ลิงก์ดาวโหลดอยู่ด้านล่าง)

ผมให้แบบฝึกหัดเด็กม.ต้นที่หัดเขียนโปรแกรมไพธอนโดยให้กลับไปคิดและเขียนโปรแกรมแก้ปัญหาที่ต้องทำด้วยมือในวิชาคณิตศาสตร์กันครับ ถ้าสั่งให้คอมพิวเตอร์ทำงานให้ได้ก็แสดงว่าเข้าใจหลักการต่างๆแล้ว นอกจากนี้คอมพิวเตอร์สามารถแก้ปัญหาใหญ่ๆที่เราทำด้วยมือไม่ไหวด้วย

คราวนี้ผมให้แบบฝึกหัดเด็กๆไปหาคำตอบของคำถามนี้ครับ: ซื้อขนมชนิดหนึ่ง ในกล่องมีให้สะสมตุ๊กตากล่องละแบบ มีตุ๊กตาทั้งหมด 4 แบบ สะสมครบ 4 แบบจะได้รับรางวัลพิเศษ เราไม่รู้ว่าแต่ละกล่องมีตุ๊กตาแบบไหนแต่ตุ๊กตาแต่ละตัวมีโอกาสเท่าๆกันที่จะอยู่ในขนมแต่ละกล่อง ถ้าซื้อขนมนี้มา 8 กล่องถามว่าความน่าจะเป็นที่จะได้รางวัลพิเศษมีเท่าไหร่

เราก็สามารถให้คอมพิวเตอร์สร้างรูปแบบขนม 8 กล่องที่เป็นได้ทั้งหมด และนับว่ารูปแบบไหนมีตุ๊กตาครบ 4 แบบดังนี้:

ผมให้เด็กๆหัดใช้ all() และ any() และ list comprehension ด้วย หน้าตาโปรแกรมก็อออกมาประมาณนี้:

ถ้าเราอยากรู้ว่าโอกาสได้รางวัลเป็นเท่าไรเมื่อซื้อมา 4 กล่อง เราก็สามารถแก้ไขโปรแกรมเราได้ประมาณนี้:

ถ้าเราอยากคำนวณความน่าจะเป็นเมื่อซื้อจำนวนกล่องอื่นๆโดยไม่ต้องเข้าไปแก้ไขโปรแกรมตลอด เราสามารถใช้ itertools.product() ได้:

ถ้าเราพยายามคำนวณสำหรับจำนวนกล่องมากๆ วิธีแจกแจงจำนวนกล่องที่เป็นไปได้ทั้งหมดจะทำได้ยาก เพราะจำนวนแบบที่เป็นไปได้เพิ่มขึ้นรวดเร็วมากเมื่อจำนวนกล่องเพิ่ม (เท่ากับ 4N เมื่อ N คือจำนวนกล่อง) ถ้าเราซื้อ 20 กล่อง จำนวนที่เป็นไปได้จะเป็นล้านล้านแบบ (เลข 12 หลัก) ถ้าซื้อ 30 กล่อง จำนวนที่เป็นไปได้จะเป็นล้านล้านล้านแบบ (เลข 18 หลัก) เราต้องใช้วิธีอื่นประมาณความน่าจะเป็น

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

เมื่อวาดกราฟความน่าจะเป็น vs. จำนวนกล่องก็จะได้ภาพแบบนี้:

ผมบันทึกตัวอย่างเหล่านี้ไว้ให้เด็กๆและผู้สนใจเข้ามาดูทบทวนโดยสามารถโหลด Jupyter Notebook ได้ที่นี่ หรือดูออนไลน์ได้ที่นี่นะครับ