01ภาพรวมของกราฟนี้
Andrews curves แปลงข้อมูลแต่ละแถวที่มีหลายมิติให้กลายเป็นเส้นคลื่นหนึ่งเส้นผ่านอนุกรมฟูริเยร์ คุณสมบัติสำคัญคือแถวที่มีค่าใกล้กันในทุกมิติจะได้เส้นที่ใกล้กันตลอด จึงใช้หากลุ่มในข้อมูลมิติสูงได้โดยไม่ต้องลดมิติ
เปรียบเทียบให้เห็นภาพ
เหมือนแปลงลายนิ้วมือให้เป็นเสียง คนที่ลายนิ้วมือคล้ายกันจะได้เสียงที่คล้ายกัน เราจึงจับกลุ่มด้วยการฟังแทนการดู
ใช้ที่ไหนบ้าง — หากลุ่มในข้อมูลที่มี 5-10 ตัวแปร ตรวจว่าการแบ่งกลุ่มที่มีอยู่แยกกันจริงไหม หรือหาแถวที่ผิดปกติในข้อมูลหลายมิติ
สร้างอย่างไร
- ขั้นที่ 1ปรับมาตรฐานทุกตัวแปรให้อยู่ในสเกลเดียวกัน
- ขั้นที่ 2แปลงแต่ละแถวเป็นฟังก์ชันคลื่น
- ขั้นที่ 3วาดเส้นทุกเส้นบนแกนเดียวกัน
- ขั้นที่ 4ระบายสีตามกลุ่มที่รู้อยู่แล้ว
ตัวอย่างคลาสสิก · David Andrews เสนอวิธีนี้ในปี 1972
Andrews เสนอการแปลงข้อมูลหลายมิติให้เป็นฟังก์ชันคลื่นโดยใช้อนุกรมฟูริเยร์ คุณสมบัติที่ทำให้วิธีนี้มีค่าคือมันรักษาระยะทาง กล่าวคือจุดที่ใกล้กันในปริภูมิหลายมิติจะให้เส้นที่ใกล้กันเสมอ ซึ่งพิสูจน์ได้ทางคณิตศาสตร์ ไม่ใช่แค่สังเกตด้วยตา
02อธิบายภาษาคนเข้าใจง่าย ๆ
ข้อมูลที่มี 6 ตัวแปรวาดบนกระดาษสองมิติตรง ๆ ไม่ได้ วิธีที่ใช้กันคือลดมิติด้วย PCA หรือวาดทุกคู่ด้วย scatter matrix ซึ่งทั้งสองวิธีมีข้อเสีย
Andrews curves ใช้วิธีที่ต่างออกไป คือแปลงแต่ละแถวให้เป็นสูตรคลื่นหนึ่งสูตร โดยเอาค่าของแต่ละตัวแปรมาเป็นสัมประสิทธิ์ของไซน์และโคไซน์
คุณสมบัติทางคณิตศาสตร์ที่ทำให้วิธีนี้ใช้ได้คือ ถ้าสองแถวมีค่าใกล้กันในทุกมิติ เส้นคลื่นของทั้งสองจะใกล้กันตลอดช่วง ดังนั้นกลุ่มที่เกาะกันในข้อมูลจะปรากฏเป็นมัดเส้นที่เกาะกัน
ประโยชน์จริงคือการตรวจว่ากลุ่มที่เราตั้งไว้แยกกันจริงไหม ถ้าระบายสีตามกลุ่มแล้วเส้นแต่ละสีเกาะกันเป็นมัดแยกจากกัน แปลว่าการแบ่งกลุ่มนั้นมีฐานในข้อมูลจริง
ข้อจำกัดที่หนักคือลำดับของตัวแปรเปลี่ยนรูปร่างของเส้น เพราะตัวแปรแรกได้สัมประสิทธิ์ที่ต่างจากตัวอื่น สลับคอลัมน์แล้วภาพจะไม่เหมือนเดิม จึงต้องลองหลายลำดับก่อนสรุป
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
ราคา | ตัวแปรตัวเลขตัวที่ 1 | ตัวเลขต่อเนื่อง | path | ต่อเนื่อง | ทุกคอลัมน์ตัวเลขถูกใช้เป็นสัมประสิทธิ์ของคลื่น |
ความเร็ว | ตัวแปรตัวเลขตัวที่ 2 | ตัวเลขต่อเนื่อง | path | ต่อเนื่อง | ควรมี 3–8 คอลัมน์ตัวเลข |
groupไม่บังคับ | กลุ่มที่รู้อยู่แล้ว | หมวดหมู่ | color | <= 3 กลุ่ม | ใช้ระบายสีเพื่อตรวจว่ากลุ่มแยกกันจริงไหม |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- ★ ปรับมาตรฐานทุกตัวแปรให้อยู่ในสเกลเดียวกัน ไม่อย่างนั้นตัวแปรที่มีหน่วยใหญ่จะครองรูปร่างทั้งหมด
- ตัดสินใจลำดับของตัวแปรและลองหลายลำดับ
- ตัดแถวที่ไม่ครบ
ค่าที่หายไป — แถวที่ขาดค่าใดค่าหนึ่งแปลงเป็นคลื่นไม่ได้ ต้องตัดออกและรายงาน
สเกลของแกน — ตัวแปรทุกตัวต้องปรับมาตรฐานก่อน เพราะสัมประสิทธิ์ของคลื่นมาจากค่าดิบโดยตรง
กราฟจะเริ่มพังเมื่อไร
เกิน 200 เส้น ภาพจะกลายเป็นมัดทึบที่แยกอะไรไม่ได้
หน้าตาไฟล์ที่ต้องเตรียม
item,group,ราคา,ความเร็ว,ความจุ,น้ำหนัก,คะแนนรีวิว
รุ่น A,รุ่นประหยัด,167,48.5,17.6,30.9,3.17
รุ่น B,รุ่นมาตรฐาน,301,55.7,30.4,20,4.09
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- มัดเส้นที่เกาะกันซึ่งคือกลุ่มในข้อมูล
- เส้นที่แยกตัวออกไปซึ่งคือแถวผิดปกติ
- ว่ากลุ่มที่ระบายสีไว้แยกกันจริงหรือปนกัน
สิ่งที่กราฟนี้ตอบไม่ได้
- ★ อ่านค่าของตัวแปรใดตัวแปรหนึ่งจากเส้นไม่ได้เลย
- รูปร่างของเส้นเปลี่ยนตามลำดับของตัวแปร จึงไม่ใช่คุณสมบัติของข้อมูลล้วน ๆ
อ่านตามลำดับนี้
- มองหามัดเส้นที่เกาะกัน
- ดูว่าเส้นแต่ละสีเกาะกันเป็นมัดของตัวเองไหม
- หาเส้นที่แยกตัวออกจากทุกมัด
คำถามที่ตอบได้
- ข้อมูลแบ่งเป็นกี่กลุ่มโดยธรรมชาติ
- การแบ่งกลุ่มที่เราตั้งไว้มีฐานในข้อมูลไหม
- มีแถวไหนที่ผิดปกติในหลายมิติพร้อมกัน
สัญญาณว่ามีอะไรผิด
- ไม่ได้ปรับมาตรฐานตัวแปรก่อน ทำให้ตัวแปรหน่วยใหญ่ครองรูปร่างทั้งหมด
- เส้นเยอะจนเป็นมัดทึบ
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- อธิบายว่าแกนตั้งไม่มีหน่วยและเส้นคือตัวแทนของแถว
- ระบุลำดับของตัวแปรที่ใช้
- ระบายสีตามกลุ่มเพื่อให้ตรวจสอบได้
รูปแบบชื่อกราฟที่ควรใช้
กลุ่ม <กลุ่ม> เกาะกันเป็นมัดแยกจากกลุ่มอื่นชัดเจน ซึ่งสนับสนุนว่าการแบ่งกลุ่มมีฐานในข้อมูล
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ andrews-curves-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด andrews-curves-sample.csv จากหน้านี้ แล้ววางไว้ข้างสคริปต์
import matplotlib
matplotlib.use("Agg") # รันแบบไม่มีหน้าจอ ถ้ารันในเครื่องตัวเองลบบรรทัดนี้ได้
import matplotlib.pyplot as plt
import pandas as pd
from pandas.plotting import andrews_curves
from sklearn.preprocessing import StandardScaler # pip install scikit-learn
C1, C2, C3 = "#2a78d6", "#eb6834", "#1baf7a" # palette ของคลัง เปลี่ยนเป็นสีองค์กรได้
INK, SURFACE = "#0b0b0b", "#fcfcfb"
df = pd.read_csv("andrews-curves-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 = "bundles" # ← ค่าจาก Playground
fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)
cols = ["ราคา", "ความเร็ว", "ความจุ", "น้ำหนัก", "คะแนนรีวิว"]
scaled = df.copy()
scaled[cols] = StandardScaler().fit_transform(df[cols]) # ★ ต้องปรับมาตรฐานก่อนเสมอ
andrews_curves(scaled[cols + ["group"]], "group", ax=ax, color=[C1, C2, C3], linewidth=1.4, alpha=0.65)
ax.set_xlabel("t"); ax.set_ylabel("ค่าของฟังก์ชันคลื่น (ไม่มีหน่วย)")
ax.legend(frameon=False, title="กลุ่ม")
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("andrews-curves.png", dpi=160)
print("เขียน andrews-curves.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
ลำดับของตัวแปรเปลี่ยนรูปร่างของเส้น — สลับคอลัมน์แล้วภาพจะไม่เหมือนเดิม
ดูข้อมูลเป็นตาราง (3 แถว)
| กลุ่ม | จำนวนเส้น |
|---|---|
| รุ่นประหยัด | 15 |
| รุ่นมาตรฐาน | 15 |
| รุ่นพรีเมียม | 15 |
ลองแล้วจะเห็นอะไร
- สังเกตอะไร: ดูว่าเส้นแต่ละสีเกาะกันเป็นมัดของตัวเองไหม ถ้าเกาะแปลว่าการแบ่งกลุ่มมีฐานในข้อมูล ถ้าปนกันแปลว่ากลุ่มที่ตั้งไว้อาจไม่ตรงกับโครงสร้างจริง
ข้อควรระวัง
- ★ ไม่ปรับมาตรฐานตัวแปรก่อน ทำให้ตัวแปรที่มีหน่วยใหญ่ครองรูปร่างของเส้นทั้งหมด
- สรุปจากลำดับตัวแปรเดียวโดยไม่ลองสลับ ทั้งที่รูปร่างเปลี่ยนตามลำดับ
- พยายามอ่านค่าของตัวแปรจากเส้น ซึ่งทำไม่ได้เลย
- ใส่เส้นมากเกินไปจนกลายเป็นมัดทึบ
เมื่อไหร่ไม่ควรใช้กราฟนี้
- มีตัวแปรน้อยกว่า 4 ตัว→ใช้แทน: scatter-matrix ที่อ่านค่าได้ตรง
- ต้องการอ่านค่าของแต่ละตัวแปร→ใช้แทน: parallel-coordinates
- ต้องการลดมิติเพื่อดูโครงสร้าง→ใช้แทน: pca-biplot หรือ embedding-projection