การสุ่มตัวอย่างและช่วงความเชื่อมั่น
ประมาณ 30 นาที
เป้าหมายของบท
- เข้าใจว่าทำไมต้องสุ่มตัวอย่างแทนการดูข้อมูลทั้งประชากร
- คำนวณ standard error ของค่าเฉลี่ยตัวอย่าง
- สร้างช่วงความเชื่อมั่น (confidence interval) ด้วย t-distribution
- ตีความ confidence interval ให้ถูกต้อง ไม่ใช่แบบ "มีโอกาส 95% ที่ค่าเฉลี่ยจริงอยู่ในช่วงนี้"
ทำไมต้องสุ่มตัวอย่างแทนการดูข้อมูลทั้งหมด
ในความเป็นจริง เรามักไม่มีข้อมูลทั้งประชากร (population) ให้ดูตรงๆ — บางทีข้อมูลทั้งหมดมีมากเกินกว่าจะประมวลผลได้เร็ว บางทีก็เก็บมาไม่ครบทุกหน่วยจริงๆ (เช่น สำรวจความเห็นลูกค้าทุกคนบนโลกเป็นไปไม่ได้) เราจึงต้องสุ่มตัวอย่าง (sample) มาส่วนหนึ่ง แล้วใช้สถิติจากตัวอย่างนั้นมาประมาณค่าจริงของประชากร
คำถามสำคัญคือ: ถ้าเราสุ่มตัวอย่างมาแค่ส่วนหนึ่ง ค่าเฉลี่ยที่คำนวณได้จากตัวอย่างจะ “ใกล้เคียง” ค่าเฉลี่ยจริงแค่ไหน และเราจะบอกความไม่แน่นอนนั้นออกมาเป็นตัวเลขได้ยังไง — นี่คือสิ่งที่ standard error และ confidence interval (CI) ตอบ
การสุ่มตัวอย่างแบบทำซ้ำได้ (reproducible)
ทุกตัวอย่างและแบบฝึกในบทนี้ใช้ยอดขายต่อออเดอร์ (completed-order revenue) ชุดเดียวกัน สร้างจาก order_items
รวมกับ orders เฉพาะออเดอร์ที่ status == 'completed' แล้ว group ตาม order_id:
import pandas as pd
import numpy as np
orders = pd.read_csv("data/orders.csv")
order_items = pd.read_csv("data/order_items.csv")
merged = order_items.merge(orders, on='order_id')
completed = merged[merged['status'] == 'completed'].copy()
completed['line'] = completed['quantity'] * completed['unit_price']
order_rev = completed.groupby('order_id')['line'].sum()
order_rev คือ Series ของยอดขายต่อออเดอร์ทั้งหมด 6232 ออเดอร์ — นี่คือ “ประชากร” ในบทนี้ (ค่าเฉลี่ยจริง ≈ 5220.15 บาท)
จากนั้นสุ่มตัวอย่างมา 200 ออเดอร์ด้วย numpy.random.default_rng — การกำหนด seed (ในที่นี้คือ 42) ทำให้สุ่มได้ผลลัพธ์
เดิมทุกครั้งที่รันใหม่ ซึ่งสำคัญมากสำหรับการเรียน (ทุกคนได้ตัวเลขตรงกัน ตรวจคำตอบได้แน่นอน):
rng = np.random.default_rng(42)
sample = rng.choice(order_rev.values, size=200, replace=False)
สำคัญ: ทุกแบบฝึกในบทนี้ต้องสร้าง sample ด้วยวิธีนี้เป๊ะๆ (seed 42, size=200, replace=False)
ถ้าเปลี่ยน seed หรือขนาดตัวอย่าง จะได้ตัวเลขคนละชุด
Standard error — ความไม่แน่นอนของค่าเฉลี่ยตัวอย่าง
ค่าเฉลี่ยของตัวอย่าง (sample.mean()) ไม่มีทางเท่ากับค่าเฉลี่ยจริงของประชากรเป๊ะๆ เสมอไป — มันแกว่งไปมาได้ตามตัวอย่างที่สุ่มมา
standard error (SE) คือค่าที่บอกว่าค่าเฉลี่ยตัวอย่างแกว่งได้มากแค่ไหนโดยเฉลี่ย คำนวณจาก:
SE = ส่วนเบี่ยงเบนมาตรฐานของตัวอย่าง (sample std) / รากที่สองของขนาดตัวอย่าง (sqrt(n))
sample_mean = sample.mean() # ≈ 6233.38
sample_std = sample.std(ddof=1) # ≈ 9141.73
se = sample_std / np.sqrt(200) # ≈ 646.42
สังเกตว่า sample_mean (≈ 6233.38) สูงกว่าค่าเฉลี่ยจริงของประชากร (≈ 5220.15) พอสมควร — นี่คือโชคของตัวอย่างนี้เพียงชุดเดียว
ล้วนๆ (ยอดขายเบ้ขวามาก มีออเดอร์ก้อนใหญ่หลุดเข้ามาในตัวอย่างพอดี) นี่คือเหตุผลว่าทำไมเราไม่ควรรายงานค่าเฉลี่ยตัวอย่างเป็น
“จุดเดียว” เฉยๆ โดยไม่บอกช่วงความไม่แน่นอนกำกับไว้ด้วย
ยิ่งขนาดตัวอย่าง (n) ใหญ่ขึ้น SE จะยิ่งเล็กลง (หารด้วย sqrt(n) ที่ใหญ่ขึ้น) — ตัวอย่างใหญ่ขึ้นทำให้ค่าเฉลี่ยตัวอย่างนิ่งขึ้น
ใกล้เคียงค่าจริงมากขึ้นโดยเฉลี่ย
Confidence interval (ช่วงความเชื่อมั่น) ด้วย t-distribution
แทนที่จะรายงานแค่ sample_mean ค่าเดียว เรารายงานเป็นช่วง ที่คาดว่าครอบคลุมค่าเฉลี่ยจริง — เรียกว่า confidence interval (CI)
สูตรทั่วไป:
CI = sample_mean ± (ค่าวิกฤต) × SE
เมื่อเราไม่รู้ส่วนเบี่ยงเบนมาตรฐานของประชากรจริง (ต้องประมาณจากตัวอย่างเอง) ค่าวิกฤตที่ถูกต้องมาจาก
t-distribution (ไม่ใช่ normal distribution ตรงๆ) โดยใช้ degrees of freedom df = n - 1:
from scipy import stats
tcrit = stats.t.ppf(0.975, df=199) # ≈ 1.972 (95% CI ใช้ 0.975 เพราะเผื่อสองด้าน)
ci_low = sample_mean - tcrit * se # ≈ 4958.67
ci_high = sample_mean + tcrit * se # ≈ 7508.08
ในตัวอย่างนี้ ค่าเฉลี่ยประชากรจริง (≈ 5220.15) อยู่ภายใน ช่วง [4958.67, 7508.08] พอดี — เป็นภาพสะท้อนที่ซื่อสัตย์ของข้อมูลจริง
(ไม่ได้จัดฉากให้ตรงเป๊ะเสมอไป)
ข้อควรระวัง: บางคนใช้ค่าวิกฤตจาก normal distribution (
1.96) แทน t-distribution เพราะจำได้ขึ้นใจ — กับdf=199(ตัวอย่างใหญ่) ตัวเลขทั้งสองใกล้กันมาก (1.972vs1.96) เลยดูเหมือนไม่มีปัญหา แต่ถ้าตัวอย่างมีขนาดเล็ก (เช่นn=10) ค่าวิกฤตจาก t-distribution กับ normal distribution จะต่างกันมาก — ใช้1.96ผิดๆ ตอนตัวอย่างเล็กจะทำให้ CI แคบเกินจริง (มั่นใจเกินความเป็นจริง)
ตีความ CI ให้ถูก
การตีความที่ผิดที่พบบ่อยที่สุดคือ: “มีโอกาส 95% ที่ค่าเฉลี่ยจริงอยู่ในช่วงนี้” — ประโยคนี้ฟังดูเป็นธรรมชาติแต่ผิดหลักการ
เพราะค่าเฉลี่ยจริงของประชากรไม่ใช่ตัวแปรสุ่ม มันเป็นค่าคงที่ค่าหนึ่ง (แค่เราไม่รู้) ส่วนช่วง [ci_low, ci_high]
ต่างหากที่เป็นตัวแปรสุ่ม (เปลี่ยนไปตามตัวอย่างที่สุ่มมาได้)
การตีความที่ถูกต้อง: “ถ้าเราสุ่มตัวอย่างขนาดเท่านี้ซ้ำแบบนี้ 100 ครั้ง แล้วคำนวณ CI ทุกครั้ง จะมีประมาณ 95 ครั้ง ที่ช่วงที่ได้ครอบคลุมค่าเฉลี่ยจริง” — ความเชื่อมั่น 95% อยู่ที่กระบวนการสุ่มตัวอย่างและคำนวณ ไม่ใช่ความน่าจะเป็นของช่วงใดช่วงหนึ่งโดยเฉพาะ
สรุปภาพรวม
| ค่า | สูตร | ในตัวอย่างนี้ |
|---|---|---|
| standard error | sample_std / sqrt(n) |
≈ 646.42 |
| t-critical (95%, df=199) | stats.t.ppf(0.975, df) |
≈ 1.972 |
| 95% CI | sample_mean ± tcrit × se |
[4958.67, 7508.08] |
ตัวอย่างแก้โจทย์
กด "ขั้นต่อไป" ทีละขั้น ลองรันและแก้โค้ดในแต่ละขั้นได้
สุ่มตัวอย่างยอดขาย 200 ออเดอร์ แล้วดู standard error
อยากรู้ยอดขายเฉลี่ยต่อออเดอร์ แต่แทนที่จะดูข้อมูลทั้งหมด (6232 ออเดอร์) ลองสุ่มมาดูแค่ 200 ออเดอร์ก่อน
สร้างยอดขายต่อออเดอร์ (เฉพาะออเดอร์ที่ completed) แล้วสุ่มตัวอย่างมา 200 ออเดอร์ด้วย seed คงที่ (
np.random.default_rng(42)) เพื่อให้สุ่มซ้ำได้ผลเดิมทุกครั้ง
คำนวณ 95% confidence interval ด้วย t-distribution
ต่อจากตัวอย่างที่แล้ว อยากรายงานเป็นช่วงที่น่าจะครอบคลุมยอดขายเฉลี่ยจริง แทนที่จะรายงานแค่ตัวเลขเดียว
หาค่าวิกฤต (critical value) จาก t-distribution ที่
df = n - 1 = 199สำหรับความเชื่อมั่น 95%
เติมช่องว่าง
แทน ___ ด้วยโค้ดที่ถูกต้อง แล้วกดตรวจคำตอบ
เติม ___ ให้ครบในสูตร standard error (ส่วนเบี่ยงเบนมาตรฐานของตัวอย่าง หารด้วยรากที่สองของขนาดตัวอย่าง)
เก็บไว้ในตัวแปร se
แบบฝึกท้ายบท
บทนี้จะนับว่าเสร็จเมื่อผ่านข้อพื้นฐานและประยุกต์ครบ ข้อท้าทายได้ดาวเพิ่ม
🟢 พื้นฐาน
สุ่มตัวอย่างยอดขายต่อออเดอร์ (เฉพาะออเดอร์ที่ completed) มา 200 ออเดอร์ ด้วย rng = np.random.default_rng(42)
แล้วหาค่าเฉลี่ยของตัวอย่างนั้น เก็บไว้ในตัวแปร sample_mean
หาส่วนเบี่ยงเบนมาตรฐาน (ddof=1) ของตัวอย่างเดียวกัน (seed 42, size 200) เก็บไว้ในตัวแปร sample_std
หา standard error ของตัวอย่างเดียวกัน (ส่วนเบี่ยงเบนมาตรฐานของตัวอย่าง หารด้วยรากที่สองของขนาดตัวอย่าง 200) เก็บไว้ในตัวแปร se
หาค่าวิกฤต (t-critical) สำหรับช่วงความเชื่อมั่น 95% เมื่อ df = 199 (ขนาดตัวอย่าง 200 ลบ 1)
เก็บไว้ในตัวแปร tcrit
🟡 ประยุกต์
คำนวณขอบล่างของ 95% confidence interval (sample_mean - tcrit * se) ของตัวอย่างเดียวกัน (seed 42, size 200)
เก็บไว้ในตัวแปร ci_low
คำนวณขอบบนของ 95% confidence interval (sample_mean + tcrit * se) ของตัวอย่างเดียวกัน เก็บไว้ในตัวแปร ci_high
หาค่าเฉลี่ยจริงของประชากรทั้งหมด (จาก order_rev ทั้งชุด อย่า hardcode ตัวเลข) แล้วเช็คว่าค่านี้อยู่ใน
95% CI ที่คำนวณจากตัวอย่าง ([ci_low, ci_high]) หรือไม่ เก็บผลลัพธ์ true/false ไว้ในตัวแปร mean_in_ci
🔴 ท้าทาย
หาความกว้างของ 95% CI (ci_high - ci_low) ของตัวอย่างเดียวกัน เก็บไว้ในตัวแปร ci_width
ถ้าสุ่มตัวอย่างมา 800 ออเดอร์แทน 200 ออเดอร์ (ใช้ seed เดิม 42 แต่เปลี่ยน size เป็น 800) standard error ของตัวอย่างใหม่นี้ (เก็บไว้ในตัวแปร se_800) จะเล็กกว่า standard error ของตัวอย่างขนาด 200 เดิม (se) หรือไม่ เก็บผลลัพธ์ true/false ไว้ในตัวแปร is_smaller
Quiz
สรุป
- เราสุ่มตัวอย่างแทนการดูข้อมูลทั้งประชากร แล้วใช้สถิติจากตัวอย่างมาประมาณค่าจริง
- standard error (sample_std / sqrt(n)) บอกว่าค่าเฉลี่ยตัวอย่างแกว่งได้มากแค่ไหน ยิ่ง n มาก SE ยิ่งเล็ก
- confidence interval สร้างจาก sample_mean ± t-critical × SE โดยใช้ t-distribution (ไม่ใช่ normal) เพราะไม่รู้ population std ที่แท้จริง
- การตีความ CI ที่ถูกต้องคือ "ถ้าสุ่มซ้ำหลายครั้ง ~95% ของช่วงจะครอบคลุมค่าเฉลี่ยจริง" ไม่ใช่ "มีโอกาส 95% ที่ค่าเฉลี่ยจริงอยู่ในช่วงนี้ช่วงเดียว"
คำถามสัมภาษณ์
อธิบายว่า 95% confidence interval หมายความว่าอะไรให้คนที่ไม่ใช่สายสถิติฟัง
พูดง่ายๆ ว่า: "ถ้าเราสุ่มตัวอย่างขนาดเท่านี้มาคำนวณช่วงแบบนี้ซ้ำๆ กัน 100 ครั้ง จะมีประมาณ 95 ครั้ง ที่ช่วงตัวเลขที่ได้ครอบคลุมค่าเฉลี่ยจริงของทั้งประชากรพอดี" — มันไม่ใช่การบอกว่า "มีโอกาส 95% ที่ค่าเฉลี่ยจริงอยู่ในช่วงนี้ช่วงเดียว" เพราะค่าเฉลี่ยจริงเป็นตัวเลขคงที่ค่าหนึ่งอยู่แล้ว (แค่เราไม่รู้ค่ามัน) สิ่งที่ไม่แน่นอนคือช่วงตัวเลขที่เราคำนวณได้จากตัวอย่างต่างหาก ไม่ใช่ค่าเฉลี่ยจริง
ทำไมขนาดตัวอย่างยิ่งใหญ่ ยิ่งมั่นใจในค่าประมาณมากขึ้น
เพราะ standard error (ความไม่แน่นอนของค่าเฉลี่ยตัวอย่าง) คำนวณจาก sample_std หารด้วยรากที่สองของขนาด ตัวอย่าง (sqrt(n)) — ยิ่ง n ใหญ่ขึ้น ตัวหารก็ใหญ่ขึ้นตาม ทำให้ SE เล็กลง ค่าเฉลี่ยตัวอย่างจึงแกว่งน้อยลง รอบๆ ค่าจริง และ confidence interval ที่ได้ก็จะแคบลง (แม่นยำกว่า) แต่ก็มีจุดคุ้มทุน เพราะ SE ลดลงตาม sqrt(n) ไม่ใช่ตาม n ตรงๆ เพิ่มตัวอย่างจาก 100 เป็น 400 (4 เท่า) SE ลดลงแค่ครึ่งเดียว ไม่ใช่ 4 เท่า