เทคนิคที่ 097 · PYTHON / JAVASCRIPT

กราฟผลลัพธ์สมมติHypothetical Outcome Plot

ทำให้ผู้อ่านรู้สึกถึงความไม่แน่นอนแทนที่จะอ่านมัน

4
ขั้นสูงควรรู้ก่อน · เข้าใจว่าแบบจำลองให้การกระจายไม่ใช่ค่าเดียว
ลองเล่น

01ภาพรวมของกราฟนี้

Hypothetical outcome plot แสดงผลลัพธ์ที่เป็นไปได้ทีละแบบสลับกันไป แทนที่จะสรุปเป็นแถบ ทำให้ผู้ชมที่ไม่เข้าใจสถิติรับรู้ความไม่แน่นอนได้ถูกต้องกว่าแถบความเชื่อมั่น แลกกับการที่ต้องเป็นสื่อเคลื่อนไหวและอ่านค่าที่แม่นไม่ได้

เปรียบเทียบให้เห็นภาพ

เหมือนดูคนทอยลูกเต๋าหลายครั้งแล้วเข้าใจว่าผลไม่แน่นอน ซึ่งเข้าใจง่ายกว่าการอ่านตารางความน่าจะเป็น

ใช้ที่ไหนบ้าง — สื่อสารความเสี่ยงกับสาธารณะ แสดงผลการเลือกตั้งที่ยังไม่แน่นอน หรืออธิบายพยากรณ์ให้ผู้ไม่มีพื้นฐานสถิติ

สร้างอย่างไร

  1. ขั้นที่ 1สุ่มผลลัพธ์จากการกระจายของแบบจำลอง
  2. ขั้นที่ 2แสดงทีละผลลัพธ์ด้วยจังหวะประมาณสี่ร้อยมิลลิวินาที
  3. ขั้นที่ 3เก็บร่องรอยของผลก่อนหน้าไว้จาง ๆ
  4. ขั้นที่ 4ให้ผู้ใช้หยุดและเลื่อนดูทีละเฟรมได้

ตัวอย่างคลาสสิก · งานวิจัยของ Hullman และคณะเรื่องการรับรู้ความไม่แน่นอน

Jessica Hullman และเพื่อนร่วมงานทดสอบว่าผู้คนประเมินความไม่แน่นอนได้แม่นแค่ไหนจากภาพแบบต่าง ๆ แล้วพบว่าผู้ที่ดูผลลัพธ์สมมติที่สลับไปมาประเมินได้ดีกว่าผู้ที่ดูแถบความเชื่อมั่น ซึ่งชี้ว่าการสรุปทางสถิติที่ดูสะอาดอาจสื่อสารได้แย่กว่าการแสดงความผันผวนตรง ๆ

Wikipedia · Uncertainty visualization

02อธิบายภาษาคนเข้าใจง่าย ๆ

งานวิจัยด้านการรับรู้พบเรื่องที่น่าตกใจ คือคนส่วนใหญ่ตีความแถบความเชื่อมั่นผิด หลายคนเข้าใจว่าเส้นกลางคือคำตอบและแถบคือส่วนตกแต่ง

ปัญหาคือแถบเป็นการสรุปทางสถิติที่ต้องเรียนมาก่อนจึงจะอ่านถูก ซึ่งผู้ชมส่วนใหญ่ไม่ได้เรียน

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

ข้อดีที่วัดได้จริงคือผู้ชมที่ไม่มีพื้นฐานสถิติประเมินความไม่แน่นอนได้แม่นกว่าเมื่อดูภาพแบบนี้ เทียบกับการดูแถบความเชื่อมั่น

ราคาที่จ่ายอย่างแรกคือมันต้องเป็นสื่อเคลื่อนไหว จึงใช้ในสิ่งพิมพ์หรือสไลด์แบบนิ่งไม่ได้เลย

อย่างที่สองคืออ่านค่าที่แม่นไม่ได้ ถ้าผู้อ่านต้องการตัวเลขไปคำนวณต่อ ต้องมีแถบหรือตารางควบคู่ไปด้วยเสมอ

03ข้อมูลที่ต้องใช้

รูปทรงของข้อมูลข้อมูลดิบรายแถว (ยังไม่สรุป)
จำนวนมิติที่เข้ารหัสได้2 มิติ
จำนวนแถวที่เหมาะ10–60 จุด และ 20–50 เฟรมขั้นต่ำ 5 แถว
เส้นฐานศูนย์เลือกได้สื่อความผันผวนของค่า ไม่ใช่ปริมาณสะสม

คอลัมน์ที่ต้องเตรียม

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
dateลำดับหรือเวลามีลำดับx5–100 จุดแกนที่ผลลัพธ์กระจายอยู่
valueค่าที่สุ่มได้ตัวเลขต่อเนื่องyต่อเนื่องแต่ละเฟรมคือหนึ่งผลลัพธ์ที่เป็นไปได้
low
ไม่บังคับ
ขอบล่างอ้างอิงช่วงค่าyใช้กำหนดการสุ่มไม่ได้วาดเป็นเส้น
high
ไม่บังคับ
ขอบบนอ้างอิงช่วงค่าyใช้กำหนดการสุ่มไม่ได้วาดเป็นเส้น

ต้องเตรียมข้อมูลอย่างไรก่อนวาด

  1. สุ่มผลลัพธ์จากการกระจายที่แบบจำลองให้
  2. ★ ล็อกค่าเริ่มต้นของการสุ่มเพื่อให้ทุกคนเห็นลำดับเดียวกัน
  3. เลือกจังหวะการเปลี่ยนเฟรมที่ตาตามทัน

ค่าที่หายไป — ถ้าสุ่มผลลัพธ์ไม่ได้ในบางจุด ต้องเว้นในทุกเฟรมเหมือนกัน

สเกลของแกน — ★ แกนค่าต้องคงที่ทุกเฟรม ไม่อย่างนั้นการเด้งที่เห็นจะมาจากแกนไม่ใช่จากข้อมูล

กราฟจะเริ่มพังเมื่อไร

เฟรมเปลี่ยนเร็วกว่า 250 มิลลิวินาที ตาตามไม่ทัน

หน้าตาไฟล์ที่ต้องเตรียม

date,value,low,high,kind
2025-01-01,100.9,97.7,104.1,ข้อมูลจริง
2025-01-31,102.3,99.1,105.5,ข้อมูลจริง

04อ่านแล้วเห็นอะไร

สิ่งที่เห็นได้จากภาพ

  • ขนาดของความผันผวนที่รู้สึกได้ทันที
  • ผลลัพธ์สุดขั้วที่เป็นไปได้แต่ไม่บ่อย
  • ความแตกต่างของความไม่แน่นอนระหว่างช่วง

สิ่งที่กราฟนี้ตอบไม่ได้

  • ★ ค่าที่แม่นยำหรือช่วงความเชื่อมั่นที่ระบุเป็นตัวเลข
  • ความน่าจะเป็นที่แน่นอนของผลลัพธ์แต่ละแบบ

อ่านตามลำดับนี้

  1. ดูหลายเฟรมแล้วสังเกตว่าเส้นเด้งไปมาแค่ไหน
  2. สังเกตว่าบริเวณไหนเด้งมากและบริเวณไหนนิ่ง
  3. หยุดเฟรมเพื่อดูผลลัพธ์แบบหนึ่ง ๆ

คำถามที่ตอบได้

  • ผลมันเด้งได้แค่ไหน
  • ผลลัพธ์ที่แย่ที่สุดหน้าตาเป็นอย่างไร
  • เราแน่ใจแค่ไหนโดยไม่ต้องอ่านตัวเลข

สัญญาณว่ามีอะไรผิด

  • แกนค่าเปลี่ยนตามเฟรม
  • เฟรมเปลี่ยนเร็วเกินจนตาตามไม่ทัน
  • ไม่มีแถบหรือตารางควบคู่สำหรับคนที่ต้องการตัวเลข

05เหมาะกับการนำเสนอแบบไหน

ผู้ชมที่เหมาะผู้ชมทั่วไปที่ไม่มีพื้นฐานสถิติ
เวลาที่ผู้ชมต้องใช้ไม่กี่วินาที
ขนาดเล็กสุดที่ยังอ่านได้420×280 px
สื่อสารกับคนทั่วไป
dashboard ที่อัปเดตตลอด
สิ่งพิมพ์ต้องเป็นสื่อเคลื่อนไหวเท่านั้น
สไลด์ผู้บริหารอ่านค่าไม่ได้และต้องใช้เวลาดู
รายงานเชิงวิเคราะห์นักวิเคราะห์ต้องการตัวเลขที่อ่านได้

ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย

  1. ★ เขียนกำกับว่าแต่ละเฟรมคือหนึ่งผลลัพธ์ที่เป็นไปได้ ไม่ใช่ข้อมูลจริง
  2. ให้ปุ่มหยุดและเลื่อนทีละเฟรม
  3. ใส่ตารางหรือแถบควบคู่สำหรับคนที่ต้องการตัวเลข

รูปแบบชื่อกราฟที่ควรใช้

ผลลัพธ์ที่เป็นไปได้ของ <สิ่งที่พยากรณ์> แสดงทีละแบบ

06เอาไปใช้ต่อ

โค้ดทุกชิ้นอ่านไฟล์ hop-plot-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง

# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด hop-plot-sample.csv จากหน้านี้ แล้ววางไว้ข้างสคริปต์
import matplotlib
matplotlib.use("Agg")   # รันแบบไม่มีหน้าจอ ถ้ารันในเครื่องตัวเองลบบรรทัดนี้ได้
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib.animation import FuncAnimation

C1, C2, C3 = "#2a78d6", "#eb6834", "#1baf7a"   # palette ของคลัง เปลี่ยนเป็นสีองค์กรได้
INK, SURFACE = "#0b0b0b", "#fcfcfb"

df = pd.read_csv("hop-plot-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
df["low"] = pd.to_numeric(df["low"], errors="coerce")
df["high"] = pd.to_numeric(df["high"], errors="coerce")
FRAME = 0   # ← ค่าจาก Playground

fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)

d = df.sort_values("date").reset_index(drop=True)
sd = (d["high"] - d["low"]) / 3.92                   # ประมาณ SD จากช่วง 95%
rng = np.random.default_rng(42)                      # ★ ล็อกเพื่อให้ทุกคนเห็นเหมือนกัน
lo, hi = d["low"].min(), d["high"].max()
(line,) = ax.plot(d.index, d["value"], color=C1, linewidth=2.4)
ax.set_ylim(lo, hi)                                  # ★ แกนคงที่ทุกเฟรม
def frame(_):
    line.set_ydata(d["value"] + rng.normal(0, sd))
    return (line,)
anim = FuncAnimation(fig, frame, frames=40, interval=400, blit=True)
anim.save("hop.gif", writer="pillow")                # แสดงเป็นภาพเคลื่อนไหวเท่านั้น

ax.spines[["top", "right"]].set_visible(False)   # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("hop-plot.png", dpi=160)
print("เขียน hop-plot.png แล้ว ·", len(df), "แถว")

ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*" · ทดสอบกับเวอร์ชัน 3.10

07ลองเล่นเพื่อเข้าใจ

ข้อมูลตัวอย่าง · 24 แถว · seed 401● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
แต่ละเฟรมคือหนึ่งความเป็นไปได้
ค่าประมาณกลางผลลัพธ์ที่เป็นไปได้ชุดนี้
80.090.01001101201301400.005.0010.015.020.0ลำดับข้อมูลผลลัพธ์ที่เป็นไปได้ชุดที่ 1

ต้องเลื่อนดูหลายชุดถึงจะเข้าใจความไม่แน่นอน — ดูชุดเดียวแล้วเชื่อว่าเป็นคำตอบคือการอ่านผิด

ชุดที่แสดง1
ส่วนเบี่ยงเบน9.11
ต่างจากค่ากลางมากสุด8.20
ดูข้อมูลเป็นตาราง (24 แถว)
hypothetical outcome plot ชุดที่ 1
ลำดับค่ากลางชุดนี้
1101109
2102100
310193.4
4103107
5104110
610397.5
710397.7
8101108
999.7103
1099.691.7
11102101
12103111
13103102
1410697.9
15109112
16112119
17113108
18116110
19118124
20119124
21123116
22125122
23127135
24126126

ลองแล้วจะเห็นอะไร

  • ผลลัพธ์ที่: เลื่อนไปมาหลายเฟรมแล้วสังเกตว่าเส้นเด้งแค่ไหน — ความรู้สึกนั้นคือสิ่งที่แถบความเชื่อมั่นสื่อไม่ได้

ข้อควรระวัง

  1. ★ ปล่อยให้แกนค่าเปลี่ยนตามเฟรม ทำให้การเด้งที่เห็นมาจากแกนไม่ใช่จากข้อมูล
  2. เปลี่ยนเฟรมเร็วเกินจนผู้ชมตามไม่ทัน
  3. ใช้เป็นภาพเดียวโดยไม่มีแถบหรือตารางควบคู่ ทำให้คนที่ต้องการตัวเลขใช้ไม่ได้
  4. ไม่บอกว่าแต่ละเฟรมคือผลลัพธ์สมมติ ทำให้ผู้ชมคิดว่าเป็นข้อมูลจริงที่เปลี่ยนไป

เมื่อไหร่ไม่ควรใช้กราฟนี้

  • ต้องพิมพ์หรือใส่สไลด์แบบนิ่งใช้แทน: fan-chart หรือ confidence-band
  • ผู้อ่านต้องการตัวเลขไปคำนวณต่อใช้แทน: error-bars
  • ผู้อ่านเป็นนักสถิติอยู่แล้วใช้แทน: confidence-band ที่อ่านค่าได้ตรง

กราฟที่เกี่ยวข้อง

เทคนิคถัดไป · ฟอเรสต์พล็อต