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

การกระจายของข้อมูล

ประมาณ 25 นาที

เป้าหมายของบท

  • อ่านรูปร่างการกระจายของข้อมูล (สมมาตร vs เบ้ซ้าย/เบ้ขวา) ด้วยตา และวัดด้วย skewness
  • คำนวณ z-score และใช้หา outlier ด้วยกฎ \|z\| > 3
  • เข้าใจว่ากฎ z-score ตั้งอยู่บนสมมติฐานว่าข้อมูลใกล้เคียงการแจกแจงปกติ ถ้าข้อมูลเบ้มากอาจตีความผิดได้

ทำไมต้องดู “รูปร่าง” ของข้อมูล ไม่ใช่แค่ตัวเลขสรุป

บทที่แล้วเรียนเรื่อง mean/median/std/IQR ไปแล้ว — ตัวเลขพวกนี้สรุปข้อมูลเป็น “จุดเดียว” ได้ก็จริง แต่ข้อมูลชุดเดียวกันอาจมี mean/std เท่ากันทุกประการ ทั้งที่หน้าตาการกระจาย (distribution) ต่างกันคนละเรื่อง บทนี้จะเรียนวิธีอ่าน “รูปร่าง” ของข้อมูลเพิ่มอีกชั้นหนึ่ง ผ่านสองแนวคิด: skewness (ความเบ้) และ z-score

Skewness: ข้อมูลสมมาตรหรือเบ้

ข้อมูลที่ “สมมาตร” (symmetric) จะมีหางซ้าย-ขวายาวพอๆ กัน ส่วนข้อมูลที่ “เบ้” (skewed) จะมีหางข้างใดข้างหนึ่งยาวกว่า

import pandas as pd

products = pd.read_csv("data/products.csv")
products['price'].skew()

.skew() คืนตัวเลขเดียวที่บอกทั้งทิศทางและความรุนแรงของความเบ้:

ค่า skew ความหมาย
ใกล้ 0 สมมาตรพอประมาณ
มากกว่า 0 (เบ้ขวา / right-skewed) หางยาวไปทางขวา มีค่าสูงผิดปกติอยู่บ้าง → มักทำให้ mean > median
น้อยกว่า 0 (เบ้ซ้าย / left-skewed) หางยาวไปทางซ้าย มีค่าต่ำผิดปกติอยู่บ้าง → มักทำให้ mean < median

ข้อมูลยอดขาย/รายได้แทบทุกธุรกิจมักเบ้ขวา เพราะลูกค้าส่วนใหญ่ซื้อของราคาปกติ แต่มีบางออเดอร์ที่ใหญ่ผิดปกติคอยดึงหางออกไปทางขวา

z-score: ค่านี้ห่างจากค่าเฉลี่ยกี่ std

z-score แปลงค่าดิบให้เป็น “จำนวน standard deviation ที่ห่างจากค่าเฉลี่ย”:

z = (x - mean) / std
  • z = 0 แปลว่าค่านั้นเท่ากับค่าเฉลี่ยพอดี
  • z = 2 แปลว่าค่านั้นสูงกว่าค่าเฉลี่ย 2 เท่าของ std
  • z = -1.5 แปลว่าค่านั้นต่ำกว่าค่าเฉลี่ย 1.5 เท่าของ std

กฎที่ใช้กันบ่อยคือ |z| > 3 = ผิดปกติ (outlier) เพราะถ้าข้อมูลแจกแจงแบบปกติ (normal distribution) จริงๆ โอกาสที่จะเจอค่าที่ห่างเกิน 3 std ทั้งสองด้านมีแค่ประมาณ 0.27% เท่านั้น (scipy.stats.norm.sf(3)*2*100) — ถือว่าหายากมาก

กับดัก: กฎ \|z\| > 3 ตั้งอยู่บนสมมติฐานว่าข้อมูลใกล้เคียง normal

ปัญหาคือ ข้อมูลยอดขาย/รายได้จริงมักไม่ใกล้เคียง normal distribution เลย — มันเบ้ขวาอย่างที่เห็นด้านบน ลองดูยอดรายได้ต่อออเดอร์ (เฉพาะออเดอร์ที่ completed) ของร้านนี้:

import pandas as pd

orders = pd.read_csv("data/orders.csv")
order_items = pd.read_csv("data/order_items.csv")
completed = orders[orders['status'] == 'completed']
merged = order_items.merge(completed, on='order_id')
merged['line'] = merged['quantity'] * merged['unit_price']
order_rev = merged.groupby('order_id')['line'].sum()

order_rev.skew()

ข้อมูลนี้เบ้ขวารุนแรง (skew สูงกว่า 3) พอเอากฎ |z| > 3 มาใช้จริง กลับเจอสัดส่วนออเดอร์ที่ “ผิดปกติ” มากกว่าที่ทฤษฎีทำนายไว้หลายเท่า เพราะข้อมูลจริงมีหางยาวกว่าการแจกแจงปกติมาก — ไม่ได้แปลว่าใช้ z-score ไม่ได้เลย แต่ต้องตีความอย่างระมัดระวัง และควรเทียบกับวิธีอื่น (เช่น IQR จากบทที่แล้ว) ประกอบกันเสมอ ไม่เชื่อกฎเดียวแบบไม่คิด

ตัวอย่างแก้โจทย์

กด "ขั้นต่อไป" ทีละขั้น ลองรันและแก้โค้ดในแต่ละขั้นได้

เทียบความเบ้ของราคาสินค้า กับยอดรายได้ต่อออเดอร์

อยากรู้ว่าราคาสินค้ากับยอดรายได้ต่อออเดอร์ (เฉพาะออเดอร์ที่สำเร็จ) มีรูปร่างการกระจายแบบไหน สมมาตรหรือเบ้

  1. หา skew ของราคาสินค้าก่อน (เหมือนที่เคยดู mean/median ใน Lesson 1 ที่ต่างกันมาก)

    Python

z-score ของออเดอร์ที่ยอดรายได้สูงที่สุด

อยากรู้ว่าออเดอร์ที่มียอดรายได้สูงที่สุด "ผิดปกติ" แค่ไหนเมื่อเทียบกับค่าเฉลี่ยของออเดอร์ทั้งหมด

  1. สร้างยอดรายได้ต่อออเดอร์เหมือนตัวอย่างที่แล้ว แล้วหาค่าเฉลี่ยกับ std

    Python

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

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

ยังไม่ได้ทำ

เติมสูตร z-score (x - mean) / std ให้ครบ เพื่อหาว่าออเดอร์ที่ยอดรายได้สูงที่สุดมี z-score เท่าไร เก็บไว้ในตัวแปร z_max เติม ___ ให้ครบ

แบบฝึกท้ายบท

บทนี้จะนับว่าเสร็จเมื่อผ่านข้อพื้นฐานและประยุกต์ครบ ข้อท้าทายได้ดาวเพิ่ม

🟢 พื้นฐาน

🟢 พื้นฐานยังไม่ได้ทำ

skewness ของราคาสินค้า (products['price']) เก็บไว้ในตัวแปร skew_price

🟢 พื้นฐานยังไม่ได้ทำ

สร้างยอดรายได้ต่อออเดอร์ (เฉพาะออเดอร์ที่ status == 'completed', line = quantity * unit_price แล้ว groupby ตาม order_id) แล้วหา skewness ของยอดรายได้นี้ เก็บไว้ในตัวแปร skew_order_rev

🟢 พื้นฐานยังไม่ได้ทำ

ยอดรายได้ต่อออเดอร์ (สร้างเหมือน e2) เบ้ขวาไหม (skew > 0) เก็บผลบูลีนไว้ในตัวแปร is_right_skewed

🟢 พื้นฐานยังไม่ได้ทำ

คำนวณ z-score ของยอดรายได้ ทุกออเดอร์ (ไม่ใช่แค่ออเดอร์เดียว) ด้วยสูตร (x - mean) / std ตั้งชื่อ Series ผลลัพธ์ว่า z แล้วเก็บไว้ในตัวแปร result

🟡 ประยุกต์

🟡 ประยุกต์ยังไม่ได้ทำ

นับจำนวนออเดอร์ที่ \|z\| > 3 (จากยอดรายได้ต่อออเดอร์) เก็บไว้ในตัวแปร n_outliers_z

🟡 ประยุกต์ยังไม่ได้ทำ

z-score สูงสุดในบรรดาออเดอร์ทั้งหมด (ปัด 2 ตำแหน่ง) เก็บไว้ในตัวแปร max_z

🟡 ประยุกต์ยังไม่ได้ทำ

เทียบวิธีหา outlier สองแบบบนยอดรายได้ต่อออเดอร์เดียวกัน: วิธี IQR (fence = Q3 + 1.5*IQR) กับวิธี z-score (\|z\| > 3) — วิธี IQR เจอ outlier มากกว่าวิธี z-score ไหม เก็บผลบูลีนไว้ในตัวแปร iqr_flags_more

🟡 ประยุกต์ยังไม่ได้ทำ

นับจำนวนออเดอร์ที่ z > 2 (ดูด้านเดียว คือหางบนเท่านั้น ไม่รวม z < -2) เก็บไว้ในตัวแปร n_above_2sigma

🔴 ท้าทาย

🔴 ท้าทายยังไม่ได้ทำ

ยอดรายได้ (บาท) ที่จุด 3 standard deviation เหนือค่าเฉลี่ย (mean + 3*std) เก็บไว้ในตัวแปร threshold_3sigma

🔴 ท้าทายยังไม่ได้ทำ

เทียบ % ของออเดอร์จริงที่ \|z\| > 3 (ปัด 2 ตำแหน่ง เก็บไว้ในตัวแปร actual_pct) กับ % ทางทฤษฎีที่ควรเจอ ถ้าข้อมูลเป็น normal distribution จริง (scipy.stats.norm.sf(3)*2*100 ปัด 2 ตำแหน่ง เก็บไว้ในตัวแปร theoretical_pct)

Quiz

1. skew เป็นบวก แปลว่าอะไร
2. z-score คำนวณจากสูตรไหน
3. กฎ \|z\| > 3 = ผิดปกติ ตั้งอยู่บนสมมติฐานอะไร
4. ทำไมข้อมูลเบ้ขวาถึงมี z-score เกิน 3 บ่อยกว่าที่ทฤษฎีทำนายไว้มาก

สรุป

  • skewness (.skew()) บอกทิศทางและขนาดของความเบ้: skew > 0 เบ้ขวา (มักทำให้ mean > median), skew < 0 เบ้ซ้าย
  • z-score = (x - mean) / std บอกว่าค่าห่างจากค่าเฉลี่ยกี่เท่าของ std กฎที่ใช้บ่อยคือ \|z\| > 3 = ผิดปกติ
  • กฎ z-score ตั้งอยู่บนสมมติฐานว่าข้อมูลใกล้เคียง normal distribution — ข้อมูลยอดขาย/รายได้ที่เบ้ขวารุนแรงมักมีค่า |z|>3 บ่อยกว่าที่ทฤษฎีทำนายไว้มาก ควรใช้ร่วมกับวิธีอื่น (เช่น IQR) เสมอ

คำถามสัมภาษณ์

ทำไมกฎ \|z\| > 3 อาจใช้ไม่ได้ดีกับข้อมูลยอดขาย/รายได้ที่มักเบ้ขวา

กฎนี้อ้างอิงคุณสมบัติของ normal distribution ที่บอกว่าค่าซึ่งห่างจากค่าเฉลี่ยเกิน 3 std จะเจอได้แค่ประมาณ 0.27% แต่ข้อมูลยอดขาย/รายได้จริงมักเบ้ขวารุนแรง (ลูกค้าส่วนใหญ่ซื้อของราคาปกติ แต่มีบางออเดอร์ใหญ่ผิดปกติดึงหางออกไป) พอเอากฎนี้ไปใช้จริง จะเจอสัดส่วนที่ \|z\|>3 สูงกว่าทฤษฎีทำนายไว้มาก (ในข้อมูลชุดนี้สูงกว่าเกือบ 8.5 เท่า) เพราะฉะนั้นควรใช้ z-score เป็นสัญญาณเบื้องต้น ไม่ใช่กฎตายตัว และควรเทียบกับวิธีอื่นประกอบเสมอ

นอกจาก z-score แล้ว มีวิธีอื่นหา outlier อะไรอีกบ้าง

วิธีที่ใช้บ่อยที่สุดอีกแบบคือ IQR method จาก Lesson ที่แล้ว (ค่าที่อยู่นอก Q1 - 1.5*IQR ถึง Q3 + 1.5*IQR) ซึ่งทนทานต่อความเบ้ของข้อมูลมากกว่า z-score เพราะอิงตำแหน่ง (percentile) ไม่ใช่ค่าเฉลี่ย/std ที่ถูกดึงง่ายโดยค่าสุดขั้ว นอกจากนี้ยังมีวิธีดูจาก domain knowledge ตรงๆ (เช่น รู้ว่าราคาสินค้าติดลบเป็นไปไม่ได้อยู่แล้ว) หรือดูกราฟ (histogram/boxplot) ประกอบ ไม่พึ่งตัวเลขสรุปตัวเดียว