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

กราฟแยกส่วนประกอบอนุกรมเวลาSeasonal Decomposition Plot

ผ่าอนุกรมเวลาออกเป็นสามชั้นที่อ่านแยกกันได้

5
เฉพาะทางควรรู้ก่อน · อ่านกราฟเส้นเป็น และเข้าใจแนวคิดค่าเฉลี่ยเคลื่อนที่
ลองเล่น

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

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

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

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

ใช้ที่ไหนบ้าง — วิเคราะห์ยอดขายก่อนทำพยากรณ์ ตรวจว่าการเปลี่ยนแปลงเป็นเรื่องฤดูกาลหรือเรื่องจริง หรือหาเหตุการณ์ผิดปกติที่ซ่อนอยู่ใต้ฤดูกาล

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

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

ตัวอย่างคลาสสิก · วิธี STL ของ Cleveland และคณะ ปี 1990

STL ย่อมาจาก Seasonal-Trend decomposition using Loess เป็นวิธีที่ยืดหยุ่นกว่าการแยกแบบคลาสสิกเพราะยอมให้รูปร่างของฤดูกาลค่อย ๆ เปลี่ยนไปตามเวลาได้ และทนต่อค่าผิดปกติ จึงกลายเป็นมาตรฐานของการแยกส่วนประกอบอนุกรมเวลาจนถึงวันนี้

Forecasting: Principles and Practice · STL decomposition

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

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

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

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

สิ่งที่ต้องตัดสินใจคือความยาวของรอบ ถ้าข้อมูลรายเดือนก็มักเป็น 12 แต่ถ้าเป็นรายวันอาจเป็น 7 สำหรับรอบสัปดาห์หรือ 365 สำหรับรอบปี การเลือกผิดทำให้ผลการแยกไม่มีความหมาย

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

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

รูปทรงของข้อมูลอนุกรมเวลา
จำนวนมิติที่เข้ารหัสได้2 มิติ
จำนวนแถวที่เหมาะ3–10 รอบเต็มขั้นต่ำ 24 แถว
เส้นฐานศูนย์เลือกได้แผงฤดูกาลและส่วนที่เหลือแกว่งรอบศูนย์อยู่แล้ว ส่วนแผงอื่นอ่านจากรูปร่าง

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

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
dateเวลาเวลาxอย่างน้อย 2 รอบเต็มต้องมีข้อมูลอย่างน้อยสองรอบจึงจะสกัดฤดูกาลได้
valueค่าที่วัดได้ตัวเลขต่อเนื่องyต่อเนื่องช่วงห่างต้องสม่ำเสมอ ข้อมูลที่เก็บไม่สม่ำเสมอต้องรวมเป็นช่วงก่อน

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

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

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

สเกลของแกน — แต่ละแผงใช้สเกลของตัวเองเพราะขนาดของส่วนประกอบต่างกันมาก แต่ต้องใช้แกนเวลาร่วมกันเสมอ

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

น้อยกว่า 2 รอบเต็ม สกัดฤดูกาลไม่ได้เลย

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

date,month,value

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

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

  • ทิศทางระยะยาวที่แท้จริงหลังตัดฤดูกาลออก
  • รูปร่างและความแรงของฤดูกาล
  • จุดผิดปกติที่โผล่ในแผงส่วนที่เหลือ

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

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

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

  1. ดูแผงแนวโน้มเพื่ออ่านทิศทางที่แท้จริง
  2. ดูแผงฤดูกาลเพื่ออ่านรูปแบบที่ซ้ำ
  3. ดูแผงส่วนที่เหลือเพื่อหาเหตุการณ์ผิดปกติ

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

  • ยอดที่โตขึ้นเป็นเรื่องจริงหรือแค่ฤดูกาล
  • ฤดูกาลแรงแค่ไหนเทียบกับแนวโน้ม
  • มีเหตุการณ์ผิดปกติเกิดขึ้นเมื่อไร

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

  • ส่วนที่เหลือมีรูปแบบชัดเจน ซึ่งแปลว่าแบบจำลองยังจับอะไรไม่หมด
  • ขนาดของส่วนที่เหลือใหญ่พอ ๆ กับฤดูกาล

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

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

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

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

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

หลังตัดฤดูกาลออก แนวโน้มที่แท้จริง<เพิ่ม/ลด> <ปริมาณ> และมีเหตุการณ์ผิดปกติที่ <เวลา>

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

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

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

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

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

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

df["date"] = pd.to_datetime(df["date"])
s = df.set_index("date")["value"].asfreq("MS").interpolate()   # ต้องเติมค่าที่หายก่อน
result = seasonal_decompose(s, model="additive", period=12)    # period = ความยาวรอบ
fig.clf(); fig.set_size_inches(7.6, 6)
for i, (name, comp) in enumerate([("ข้อมูลจริง", s), ("แนวโน้ม", result.trend),
                                  ("ฤดูกาล", result.seasonal), ("ส่วนที่เหลือ", result.resid)]):
    a = fig.add_subplot(4, 1, i + 1)
    a.plot(comp.index, comp, color=[INK, C1, C3, C2][i], linewidth=1.6)
    a.set_ylabel(name, fontsize=9); a.grid(alpha=0.2)

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

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

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

ข้อมูลตัวอย่าง · 48 แถว · seed 53● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
แผงล่างสุดคือสิ่งที่อธิบายไม่ได้
ข้อมูลจริงข้อมูลจริงแนวโน้มแนวโน้มฤดูกาลฤดูกาลส่วนที่เหลือส่วนที่เหลือ
ความแรงของฤดูกาล46%
ส่วนที่เหลือมากสุด14.5
แนวโน้มรวมขึ้น 66.1
ดูข้อมูลเป็นตาราง (48 แถว)
กราฟแยกส่วนประกอบอนุกรมเวลา 4 แผง
วันที่จริงแนวโน้มฤดูกาลเหลือ
2023-01-151131138.60-8.60
2023-02-1413312315.8-5.67
2023-03-1613712823.4-13.8
2023-04-1514613225.1-11.2
2023-05-1514013420.6-14.5
2023-06-1413613415.6-14.1
2023-07-141251334.73-12.6
2023-08-13118131-6.09-7.12
2023-09-12113129-13.0-2.70
2023-10-12111127-16.1-0.39
2023-11-11113126-10.2-3.08
2023-12-11122125-3.05-0.79
2024-01-101361278.60-0.26
2024-02-0914312815.8-1.01
2024-03-1015312923.4-0.10
2024-04-0916013125.13.89
2024-05-0915613220.63.26
2024-06-0816013415.610.1
2024-07-081421354.731.83
2024-08-07134137-6.093.67
2024-09-06126138-13.00.90
2024-10-06128139-16.14.56
2024-11-05135141-10.24.25
2024-12-05141143-3.050.91
2025-01-041581448.604.54
2025-02-0317114715.88.02
2025-03-0517514923.42.61
2025-04-0418015025.14.61
2025-05-0418015220.66.72
2025-06-0317115315.62.01
2025-07-031601554.730.48
2025-08-02150156-6.090.37
2025-09-01143157-13.0-1.33
2025-10-01139158-16.1-3.67
2025-10-31149160-10.2-0.35
2025-11-30155161-3.05-2.35
2025-12-301751628.604.33
2026-01-2917716315.8-1.34
2026-02-2820016523.411.3
2026-03-3019416625.12.72
2026-04-2919216720.64.56
2026-05-2918616815.62.01
2026-06-281861714.7310.3
2026-07-28169172-6.093.09
2026-08-27164174-13.03.12
2026-09-26159176-16.1-0.49
2026-10-26166177-10.2-0.82
2026-11-25178179-3.052.23

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

  • สังเกตอะไร: ดูแผงล่างสุดแล้วหาจุดที่พุ่งสูงผิดปกติ นั่นคือเหตุการณ์จริงที่ไม่ใช่ฤดูกาลและไม่ใช่แนวโน้ม ซึ่งกราฟเส้นรวมกลบไว้มิด

ข้อควรระวัง

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

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

  • ข้อมูลมีน้อยกว่า 2 รอบเต็มใช้แทน: line-chart
  • ผู้อ่านไม่ใช่นักวิเคราะห์ใช้แทน: cycle-plot หรือ line-chart พร้อมคำอธิบาย
  • ต้องการเห็นแนวโน้มภายในแต่ละเดือนใช้แทน: cycle-plot

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

เทคนิคถัดไป · แผนภูมิแกนต์