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

กราฟแกนขนานParallel Coordinates

อ่านค่าของทุกตัวแปรได้ ต่างจากการลดมิติ

4
ขั้นสูงควรรู้ก่อน · คุ้นกับข้อมูลหลายตัวแปร
ลองเล่น

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

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

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

เหมือนตารางที่แต่ละคอลัมน์ตั้งขึ้นเป็นแกน แล้วลากเส้นเชื่อมค่าของคนเดียวกันข้ามคอลัมน์

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

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

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

ตัวอย่างคลาสสิก · Alfred Inselberg พัฒนาระบบพิกัดขนานในทศวรรษ 1980

Inselberg ศึกษาคุณสมบัติทางเรขาคณิตของการแทนจุดในปริภูมิหลายมิติด้วยเส้นบนแกนขนาน และพบว่ารูปแบบบางอย่างมีความหมายทางคณิตศาสตร์ เช่น จุดที่อยู่บนเส้นตรงในปริภูมิหลายมิติจะให้เส้นที่ตัดกันที่จุดเดียวกัน ซึ่งทำให้วิธีนี้ไม่ใช่แค่การจัดวางที่สวยงามแต่มีฐานทางทฤษฎี

Wikipedia · Parallel coordinates

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

ข้อมูลที่มี 5-6 ตัวแปรวาดบนระนาบสองมิติตรง ๆ ไม่ได้ วิธีหนึ่งคือลดมิติด้วย PCA แต่นั่นทำให้อ่านค่าของตัวแปรเดิมไม่ได้อีกเลย

Parallel coordinates ใช้วิธีตรงกว่า คือตั้งแกนของแต่ละตัวแปรขนานกัน แล้วลากเส้นเชื่อมค่าของแถวเดียวกันข้ามทุกแกน หนึ่งเส้นคือหนึ่งแถว

ข้อดีที่ชัดคือยังอ่านค่าจริงได้ ถ้าอยากรู้ว่าสินค้ารุ่นนี้ราคาเท่าไร ก็ดูว่าเส้นของมันตัดแกนราคาที่ตำแหน่งไหน

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

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

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

รูปทรงของข้อมูลตารางแบบกว้าง (หนึ่งแถวหนึ่ง entity)
จำนวนมิติที่เข้ารหัสได้4 มิติ
จำนวนแถวที่เหมาะ20–200 แถว × 3–8 แกนขั้นต่ำ 10 แถว
เส้นฐานศูนย์ไม่เกี่ยวข้องแต่ละแกนมีสเกลของตัวเองที่ปรับให้เต็มความสูง จึงไม่มีเส้นฐานร่วม

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

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
ราคาตัวแปรที่ 1ตัวเลขต่อเนื่องyต่อเนื่องแต่ละคอลัมน์ตัวเลขกลายเป็นหนึ่งแกน
ความเร็วตัวแปรที่ 2ตัวเลขต่อเนื่องyต่อเนื่องควรมี 3–8 แกน
group
ไม่บังคับ
กลุ่มหมวดหมู่color<= 8 กลุ่มใช้ระบายสีเพื่อดูว่ากลุ่มแยกกันไหม

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

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

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

สเกลของแกน — แต่ละแกนใช้สเกลของตัวเองเต็มความสูง และต้องเขียนค่าต่ำสุดกับสูงสุดกำกับที่ปลายแกน

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

เกิน 300 เส้น ภาพจะกลายเป็นก้อนทึบ — ใช้ความโปร่งใสหรือกรองข้อมูลก่อน

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

item,group,ราคา,ความเร็ว,ความจุ,น้ำหนัก,คะแนนรีวิว
รุ่น A,รุ่นประหยัด,167,48.5,17.6,30.9,3.17
รุ่น B,รุ่นมาตรฐาน,301,55.7,30.4,20,4.09

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

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

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

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

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

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

  1. เลือกเส้นหนึ่งเส้นแล้วตามจากแกนซ้ายไปขวา
  2. ดูว่าเส้นระหว่างสองแกนขนานกันหรือไขว้กัน
  3. หากลุ่มของเส้นที่เดินทางคล้ายกัน

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

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

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

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

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

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

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

  1. เขียนค่าต่ำสุดและสูงสุดที่ปลายแกนทุกแกน
  2. ใช้ความโปร่งใสเมื่อเส้นเยอะ
  3. เน้นเส้นที่เป็นประเด็นและทำเส้นอื่นเป็นสีเทา

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

รายการที่ <คุณสมบัติ> สูง มักมี <คุณสมบัติ> ต่ำด้วย

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

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

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

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

df = pd.read_csv("parallel-coordinates-sample.csv")
df["ราคา"] = pd.to_numeric(df["ราคา"], errors="coerce")
df["ความเร็ว"] = pd.to_numeric(df["ความเร็ว"], errors="coerce")
df["ความจุ"] = pd.to_numeric(df["ความจุ"], errors="coerce")
df["น้ำหนัก"] = pd.to_numeric(df["น้ำหนัก"], errors="coerce")
df["คะแนนรีวิว"] = pd.to_numeric(df["คะแนนรีวิว"], errors="coerce")
NOTE = "adjacent"   # ← ค่าจาก Playground

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

cols = ["ราคา", "ความเร็ว", "ความจุ", "น้ำหนัก", "คะแนนรีวิว"]
scaled = df.copy()
for c in cols:                                        # ★ ปรับสเกลแต่ละแกนให้เต็มความสูง
    scaled[c] = (df[c] - df[c].min()) / (df[c].max() - df[c].min())
parallel_coordinates(scaled[cols + ["group"]], "group", ax=ax,
                     color=[C1, C2, C3], alpha=0.55, linewidth=1.6)
for i, c in enumerate(cols):                          # เขียนค่าจริงที่ปลายแกน
    ax.text(i, 1.04, f"{df[c].max():,.0f}", ha="center", fontsize=8, color="#7a7872")
    ax.text(i, -0.07, f"{df[c].min():,.0f}", ha="center", fontsize=8, color="#7a7872")
ax.set_yticks([]); ax.legend(frameon=False, title="กลุ่ม")

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

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

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

ข้อมูลตัวอย่าง · 60 แถว · seed 197● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
ความสัมพันธ์เห็นได้เฉพาะแกนที่ติดกัน
รุ่นประหยัดรุ่นมาตรฐานรุ่นพรีเมียม
ราคา500100ความเร็ว90.030.0ความจุ50.010.0น้ำหนัก35.010.0คะแนนรีวิว5.002.50รุ่น A · รุ่นประหยัดรุ่น B · รุ่นมาตรฐานรุ่น C · รุ่นพรีเมียมรุ่น D · รุ่นประหยัดรุ่น E · รุ่นมาตรฐานรุ่น F · รุ่นพรีเมียมรุ่น G · รุ่นประหยัดรุ่น H · รุ่นมาตรฐานรุ่น I · รุ่นพรีเมียมรุ่น J · รุ่นประหยัดรุ่น K · รุ่นมาตรฐานรุ่น L · รุ่นพรีเมียมรุ่น M · รุ่นประหยัดรุ่น N · รุ่นมาตรฐานรุ่น O · รุ่นพรีเมียมรุ่น P · รุ่นประหยัดรุ่น Q · รุ่นมาตรฐานรุ่น R · รุ่นพรีเมียมรุ่น S · รุ่นประหยัดรุ่น T · รุ่นมาตรฐานรุ่น U · รุ่นพรีเมียมรุ่น V · รุ่นประหยัดรุ่น W · รุ่นมาตรฐานรุ่น X · รุ่นพรีเมียมรุ่น Y · รุ่นประหยัดรุ่น Z · รุ่นมาตรฐานรุ่น [ · รุ่นพรีเมียมรุ่น \ · รุ่นประหยัดรุ่น ] · รุ่นมาตรฐานรุ่น ^ · รุ่นพรีเมียมรุ่น _ · รุ่นประหยัดรุ่น ` · รุ่นมาตรฐานรุ่น a · รุ่นพรีเมียมรุ่น b · รุ่นประหยัดรุ่น c · รุ่นมาตรฐานรุ่น d · รุ่นพรีเมียมรุ่น e · รุ่นประหยัดรุ่น f · รุ่นมาตรฐานรุ่น g · รุ่นพรีเมียมรุ่น h · รุ่นประหยัดรุ่น i · รุ่นมาตรฐานรุ่น j · รุ่นพรีเมียมรุ่น k · รุ่นประหยัดรุ่น l · รุ่นมาตรฐานรุ่น m · รุ่นพรีเมียมรุ่น n · รุ่นประหยัดรุ่น o · รุ่นมาตรฐานรุ่น p · รุ่นพรีเมียมรุ่น q · รุ่นประหยัดรุ่น r · รุ่นมาตรฐานรุ่น s · รุ่นพรีเมียมรุ่น t · รุ่นประหยัดรุ่น u · รุ่นมาตรฐานรุ่น v · รุ่นพรีเมียมรุ่น w · รุ่นประหยัดรุ่น x · รุ่นมาตรฐานรุ่น y · รุ่นพรีเมียมรุ่น z · รุ่นประหยัดรุ่น { · รุ่นมาตรฐานรุ่น | · รุ่นพรีเมียม

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

จำนวนแกน5
จำนวนเส้น60
จำนวนกลุ่ม3
ดูข้อมูลเป็นตาราง (18 แถว)
parallel coordinates 5 แกน 60 เส้น
รายการกลุ่มราคาความเร็วความจุน้ำหนักคะแนนรีวิว
รุ่น Aรุ่นประหยัด16748.517.630.93.17
รุ่น Bรุ่นมาตรฐาน30155.730.420.04.09
รุ่น Cรุ่นพรีเมียม39376.143.617.24.14
รุ่น Dรุ่นประหยัด19538.221.929.53.20
รุ่น Eรุ่นมาตรฐาน30457.435.123.33.82
รุ่น Fรุ่นพรีเมียม43267.938.515.44.47
รุ่น Gรุ่นประหยัด18642.818.530.03.04
รุ่น Hรุ่นมาตรฐาน30249.324.125.93.67
รุ่น Iรุ่นพรีเมียม39677.544.118.24.41
รุ่น Jรุ่นประหยัด17339.019.727.53.50
รุ่น Kรุ่นมาตรฐาน30860.034.222.13.82
รุ่น Lรุ่นพรีเมียม42079.146.419.74.27
รุ่น Mรุ่นประหยัด17335.919.531.93.11
รุ่น Nรุ่นมาตรฐาน29864.632.623.03.65
รุ่น Oรุ่นพรีเมียม43577.741.117.84.00
รุ่น Pรุ่นประหยัด19643.219.529.63.23
รุ่น Qรุ่นมาตรฐาน29655.834.523.33.81
รุ่น Rรุ่นพรีเมียม42274.445.816.84.17

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

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

ข้อควรระวัง

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

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

  • มีตัวแปรน้อยกว่า 3 ตัวใช้แทน: scatter-plot
  • มีมากกว่า 300 แถวใช้แทน: scatter-matrix หรือกรองข้อมูลก่อน
  • ต้องการดูโครงสร้างกลุ่มโดยไม่สนค่าจริงใช้แทน: embedding-projection หรือ andrews-curves

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

เทคนิคถัดไป · แผนภาพการย้ายหมวด