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

แผนภาพการย้ายหมวดAlluvial Diagram

ดูว่าใครย้ายจากกลุ่มไหนไปกลุ่มไหน

4
ขั้นสูงควรรู้ก่อน · อ่าน sankey diagram เป็น
ลองเล่น

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

Alluvial diagram แสดงการย้ายหมวดของสมาชิกระหว่างขั้นที่มีชุดหมวดเดียวกัน เช่น ลูกค้าที่อยู่กลุ่มพรีเมียมปีนี้ไปอยู่กลุ่มไหนในปีหน้า ต่างจาก sankey ตรงที่ sankey ไหลไปข้างหน้าสู่โหนดใหม่ ส่วน alluvial วนอยู่ในชุดหมวดเดิม

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

เหมือนแผนภาพการย้ายห้องเรียนของนักเรียนทุกปี ห้องมีชุดเดิมทุกปี แต่คนย้ายไปมาระหว่างห้อง

ใช้ที่ไหนบ้าง — การย้ายระดับลูกค้าระหว่างปี การเปลี่ยนพรรคที่เลือกระหว่างการเลือกตั้ง หรือการย้ายกลุ่มความเสี่ยงของผู้ป่วย

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

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

ตัวอย่างคลาสสิก · แผนภาพการย้ายพรรคของผู้มีสิทธิเลือกตั้ง

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

Wikipedia · Alluvial diagram

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

คำถามที่ตารางตอบยากคือ "คนที่เคยอยู่กลุ่ม A ตอนนี้ไปอยู่ไหนกันบ้าง" เพราะต้องดูตารางไขว้แล้วตามทีละช่อง

Alluvial diagram ตอบด้วยภาพ แต่ละขั้นมีแถบของทุกหมวดเรียงกัน และริบบิ้นที่เชื่อมระหว่างขั้นบอกว่ามีกี่คนย้ายจากหมวดไหนไปหมวดไหน

ความต่างจาก sankey ที่ต้องเข้าใจคือ ใน sankey โหนดแต่ละขั้นเป็นคนละอย่างกัน เช่น เข้าชมเว็บแล้วไปดูสินค้า แต่ใน alluvial ทุกขั้นใช้ชุดหมวดเดียวกัน เช่น ระดับลูกค้าในปีที่ 1 2 และ 3

สิ่งที่อ่านได้ทันทีคือความมั่นคง ริบบิ้นที่วิ่งตรงจากหมวดเดิมไปหมวดเดิมคือคนที่ไม่เปลี่ยน ส่วนริบบิ้นที่ไขว้ไปมาคือการย้าย ยิ่งไขว้มากแปลว่าระบบยิ่งไม่นิ่ง

ข้อควรระวังคือเมื่อมีหลายขั้นและหลายหมวด ริบบิ้นจะไขว้กันจนตามเส้นทางของกลุ่มเดียวไม่ได้ ในทางปฏิบัติจึงจำกัดที่ประมาณ 3-4 ขั้นและ 4-5 หมวด

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

รูปทรงของข้อมูลรายการเส้นเชื่อม source–target–value
จำนวนมิติที่เข้ารหัสได้3 มิติ
จำนวนแถวที่เหมาะ3–4 ขั้น × 3–5 หมวดขั้นต่ำ 4 แถว
เส้นฐานศูนย์ไม่เกี่ยวข้องไม่มีแกนค่า ความหมายอยู่ที่ความหนาของริบบิ้น

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

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
sourceหมวดในขั้นก่อนโหนดpath2–6 หมวดชุดหมวดควรเหมือนกันทุกขั้น
targetหมวดในขั้นถัดไปโหนดpath2–6 หมวดชุดเดียวกับ source
valueจำนวนที่ย้ายตัวเลขต่อเนื่องsizeบวกเท่านั้นความหนาของริบบิ้นแปรตามจำนวน

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

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

ค่าที่หายไป — สมาชิกที่หายไประหว่างขั้นต้องมีหมวด "ออกจากระบบ" ของตัวเอง ห้ามปล่อยให้หายเงียบ ๆ เพราะผลรวมจะไม่ตรง

สเกลของแกน — ความหนาแปรตรงกับจำนวน เหมือน sankey

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

เกิน 5 ขั้นหรือ 6 หมวด ริบบิ้นจะไขว้กันจนตามไม่ได้

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

source,target,value
เข้าชมเว็บ,ดูสินค้า,7975
เข้าชมเว็บ,ออกทันที,4078

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

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

  • สัดส่วนที่อยู่หมวดเดิมจากริบบิ้นที่วิ่งตรง
  • หมวดที่คนไหลเข้ามากที่สุด
  • หมวดที่คนไหลออกมากที่สุด
  • เส้นทางการย้ายที่พบบ่อยที่สุด

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

  • ไม่บอกว่าทำไมถึงย้าย
  • ตามเส้นทางของกลุ่มเดียวข้ามหลายขั้นได้ยากเมื่อริบบิ้นไขว้กันมาก

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

  1. ดูแถบของแต่ละหมวดในขั้นแรกว่าใหญ่แค่ไหน
  2. ตามริบบิ้นที่ออกจากหมวดที่สนใจ
  3. ดูว่าริบบิ้นส่วนใหญ่วิ่งตรงหรือไขว้

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

  • คนที่เคยอยู่กลุ่มนี้ไปไหนกันบ้าง
  • กลุ่มไหนที่คนอยู่ทนที่สุด
  • มีการย้ายข้ามระดับแบบกระโดดไหม

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

  • ผลรวมของริบบิ้นที่ออกจากหมวดไม่เท่ากับขนาดของหมวดนั้น
  • ไม่มีหมวดสำหรับคนที่ออกจากระบบ

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

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

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

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

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

<เปอร์เซ็นต์> ของกลุ่ม <หมวด> ยังอยู่หมวดเดิม ขณะที่ <เปอร์เซ็นต์> ย้ายไป <หมวด>

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

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

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

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

df = pd.read_csv("alluvial-diagram-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
NOTE = "straight"   # ← ค่าจาก Playground

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

# matplotlib ไม่มี alluvial ในตัว — แสดงเป็นตารางการย้ายหมวดแทน
pivot = df.pivot_table(index="source", columns="target", values="value", aggfunc="sum").fillna(0)
share = pivot.div(pivot.sum(axis=1), axis=0)          # สัดส่วนการย้ายจากแต่ละหมวด
im = ax.imshow(share, cmap="Blues", vmin=0, vmax=1, aspect="auto")
ax.set_xticks(range(len(pivot.columns))); ax.set_xticklabels(pivot.columns, rotation=30, ha="right", fontsize=8)
ax.set_yticks(range(len(pivot.index))); ax.set_yticklabels(pivot.index, fontsize=8)
for i in range(len(pivot.index)):
    for j in range(len(pivot.columns)):
        if share.iloc[i, j] > 0:
            ax.text(j, i, f"{share.iloc[i, j]:.0%}", ha="center", va="center", fontsize=8)
ax.set_ylabel("หมวดเดิม"); ax.set_xlabel("หมวดใหม่")

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

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

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

ข้อมูลตัวอย่าง · 8 แถว · seed 239● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
ริบบิ้นที่วิ่งตรงคือคนที่ไม่เปลี่ยนหมวด
ขั้นที่ 1ขั้นที่ 2ขั้นที่ 3ขั้นที่ 4ขั้นที่ 5เข้าชมเว็บเข้าชมเว็บ · 12,053ดูสินค้าดูสินค้า · 8,195ออกทันทีออกทันที · 4,078ใส่ตะกร้าใส่ตะกร้า · 3,118ออกกลางทางออกกลางทาง · 5,112กรอกที่อยู่กรอกที่อยู่ · 1,952ทิ้งตะกร้าทิ้งตะกร้า · 1,166ชำระเงินสำเร็จชำระเงินสำเร็จ · 1,418ชำระไม่สำเร็จชำระไม่สำเร็จ · 457
จำนวนขั้น5
เส้นทางทั้งหมด8
ปริมาณตั้งต้น12,053
ดูข้อมูลเป็นตาราง (8 แถว)
alluvial diagram 5 ขั้น
จากไปจำนวน
เข้าชมเว็บดูสินค้า7,975
เข้าชมเว็บออกทันที4,078
ดูสินค้าใส่ตะกร้า3,083
ดูสินค้าออกกลางทาง5,112
ใส่ตะกร้ากรอกที่อยู่1,952
ใส่ตะกร้าทิ้งตะกร้า1,166
กรอกที่อยู่ชำระเงินสำเร็จ1,418
กรอกที่อยู่ชำระไม่สำเร็จ457

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

  • สังเกตอะไร: เทียบความหนาของริบบิ้นที่วิ่งตรงกับที่ไขว้ จะเห็นว่าระบบนี้มั่นคงแค่ไหน ซึ่งเป็นข้อมูลที่ตารางไขว้บอกได้แต่ต้องคำนวณเอง

ข้อควรระวัง

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

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

  • แต่ละขั้นเป็นคนละสิ่งกันใช้แทน: sankey-diagram
  • สนใจแค่ตารางไขว้ของสองขั้นใช้แทน: heatmap-matrix
  • สนใจว่าคนอยู่ทนแค่ไหนตามเวลาใช้แทน: cohort-heatmap

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

เทคนิคถัดไป · แผนภาพการไหล