Data Analyst › สถิติสำหรับ DA

การสุ่มตัวอย่างและช่วงความเชื่อมั่น

ประมาณ 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.972 vs 1.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 ออเดอร์ก่อน

  1. สร้างยอดขายต่อออเดอร์ (เฉพาะออเดอร์ที่ completed) แล้วสุ่มตัวอย่างมา 200 ออเดอร์ด้วย seed คงที่ (np.random.default_rng(42)) เพื่อให้สุ่มซ้ำได้ผลเดิมทุกครั้ง

    Python

คำนวณ 95% confidence interval ด้วย t-distribution

ต่อจากตัวอย่างที่แล้ว อยากรายงานเป็นช่วงที่น่าจะครอบคลุมยอดขายเฉลี่ยจริง แทนที่จะรายงานแค่ตัวเลขเดียว

  1. หาค่าวิกฤต (critical value) จาก t-distribution ที่ df = n - 1 = 199 สำหรับความเชื่อมั่น 95%

    Python

เติมช่องว่าง

แทน ___ ด้วยโค้ดที่ถูกต้อง แล้วกดตรวจคำตอบ

ยังไม่ได้ทำ

เติม ___ ให้ครบในสูตร 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

1. standard error ของค่าเฉลี่ยตัวอย่างคำนวณจากอะไร
2. ถ้าขนาดตัวอย่างใหญ่ขึ้น (n มากขึ้น) standard error จะเป็นแบบไหน
3. การตีความ 95% confidence interval ที่ถูกต้องคือแบบไหน
4. ทำไมต้องใช้ t-distribution แทน normal distribution ตอนคำนวณ CI จากตัวอย่าง

สรุป

  • เราสุ่มตัวอย่างแทนการดูข้อมูลทั้งประชากร แล้วใช้สถิติจากตัวอย่างมาประมาณค่าจริง
  • 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 เท่า