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

แผนที่ความร้อนKernel Heat Map

เปลี่ยนจุดกระจัดกระจายให้เป็นพื้นผิวที่อ่านออก

3
ผสานหลายแนวคิดควรรู้ก่อน · เข้าใจว่าการเกลี่ยเป็นการประมาณ
ลองเล่น

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

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

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

เหมือนภาพถ่ายความร้อนที่บริเวณอุ่นกลืนเข้าหากันเป็นพื้นผิวเรียบ แทนที่จะเห็นเป็นจุดแยก ๆ

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

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

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

ตัวอย่างคลาสสิก · แผนที่จุดร้อนอาชญากรรมในงานตำรวจเชิงพื้นที่

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

Wikipedia · Crime mapping

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

แผนที่จุดดิบมีปัญหาเมื่อจุดเยอะ เพราะจุดทับกันจนบอกไม่ได้ว่าบริเวณไหนหนาแน่นกว่ากันจริง ๆ

Kernel heat map แก้ด้วยการเกลี่ย แทนที่จะวาดจุดเป็นจุด มันวาดแต่ละจุดเป็นเนินเตี้ย ๆ ที่สูงตรงกลางและค่อย ๆ ลดลงตามระยะ แล้วบวกเนินทั้งหมดเข้าด้วยกัน

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

ราคาที่จ่ายอย่างแรกและสำคัญที่สุดคือรัศมีการเกลี่ยเป็นค่าที่คนตั้ง รัศมีเล็กให้จุดร้อนหลายจุดแยกกัน รัศมีใหญ่ให้จุดร้อนใหญ่จุดเดียว จากข้อมูลชุดเดียวกันทุกประการ

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

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

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

รูปทรงของข้อมูลข้อมูลดิบรายแถว (ยังไม่สรุป)
จำนวนมิติที่เข้ารหัสได้3 มิติ
จำนวนแถวที่เหมาะ200–20,000 จุดขั้นต่ำ 20 แถว
เส้นฐานศูนย์ไม่เกี่ยวข้องค่าเข้ารหัสด้วยสี ไม่มีแกนค่า

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

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
latละติจูดเชิงพื้นที่yต่อเนื่องพิกัดของเหตุการณ์
lonลองจิจูดเชิงพื้นที่xต่อเนื่องระบบพิกัดเดียวกับแผนที่ฐาน
value
ไม่บังคับ
น้ำหนักตัวเลขต่อเนื่องcolorบวกเท่านั้นไม่ใส่ก็ได้ ถือว่าทุกจุดหนักเท่ากัน

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

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

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

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

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

จุดน้อยกว่า 30 จุด พื้นผิวที่ได้เป็นภาพลวงมากกว่าข้อมูล

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

lat,lon,value
13.8013,100.1331,184
18.2209,98.5482,50

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

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

  • ตำแหน่งของจุดร้อนหลัก
  • จำนวนจุดร้อนที่แยกจากกัน
  • ทิศทางการแผ่ของความหนาแน่น

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

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

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

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

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

  • จุดร้อนอยู่บริเวณไหน
  • มีจุดร้อนกี่จุด
  • จุดร้อนกระจุกหรือกระจาย

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

  • ไม่ระบุรัศมีการเกลี่ย
  • จุดร้อนในบริเวณที่แทบไม่มีจุดดิบเลย
  • ใช้กับข้อมูลน้อยกว่า 30 จุด
  • ใช้สเกลสีรุ้ง

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

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

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

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

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

จุดร้อนของ <เหตุการณ์> โดยเกลี่ยด้วยรัศมี <ค่า>

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

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

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

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

df = pd.read_csv("kernel-heat-map-sample.csv")
df["lat"] = pd.to_numeric(df["lat"], errors="coerce")
df["lon"] = pd.to_numeric(df["lon"], errors="coerce")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
RADIUS = "46"   # ← ค่าจาก Playground

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

kde = gaussian_kde(np.vstack([df["lon"], df["lat"]]),
                   weights=df["value"], bw_method=0.3)   # bw_method = รัศมีการเกลี่ย
gx, gy = np.mgrid[df["lon"].min():df["lon"].max():160j,
                  df["lat"].min():df["lat"].max():160j]
z = kde(np.vstack([gx.ravel(), gy.ravel()])).reshape(gx.shape)
im = ax.pcolormesh(gx, gy, z, cmap="Blues", shading="gouraud")
ax.scatter(df["lon"], df["lat"], s=6, color="#22201c", alpha=0.5)   # จุดดิบทับให้ตรวจได้
fig.colorbar(im, ax=ax, label="ความหนาแน่นประมาณ", shrink=0.8)
ax.set_title("bw = 0.3", loc="left")

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

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

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

ข้อมูลตัวอย่าง · 40 แถว · seed 347● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
ค่าที่คนตั้งเอง
เย็นร้อน

รัศมีที่เลือกเปลี่ยนตำแหน่งของจุดร้อนได้ — รัศมีกว้างทำให้จุดร้อนหลายจุดรวมเป็นจุดเดียว

รัศมีเคอร์เนล46 px
จำนวนจุดตั้งต้น40
ช่องที่ร้อนที่สุด1,102
ดูข้อมูลเป็นตาราง (24 แถว)
heat map เชิงพื้นที่จาก 40 จุด
ละติจูดลองจิจูดค่า
13.801100.133184
18.22198.54850.0
7.66399.01180.0
14.373101.583162
18.167100.079178
8.68498.466162
14.958102.031138
19.18098.56171.0
6.85498.738199
13.264100.423182
19.61798.26790.0
7.08598.117141
12.45899.89584.0
18.89598.480148
6.86696.877120
13.118100.55065.0
18.923100.16876.0
7.39898.207150
13.792100.146126
18.54598.655134
7.15398.40696.0
14.90699.64231.0
18.06397.913160
7.67699.10590.0

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

  • รัศมีการเกลี่ย: ลองเลื่อนจากแคบไปกว้างแล้วดูว่าจุดร้อนสามจุดรวมเป็นจุดเดียวได้อย่างไร — ข้อมูลไม่เปลี่ยนเลย แต่ข้อสรุปเปลี่ยนไปคนละเรื่อง

ข้อควรระวัง

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

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

  • ต้องอ่านค่าของแต่ละบริเวณใช้แทน: hexbin-map ที่นับจริงในแต่ละช่อง
  • มีจุดข้อมูลน้อยกว่า 30 จุดใช้แทน: dot-density-map หรือ scatter-plot
  • ข้อมูลผูกกับเขตการปกครองใช้แทน: choropleth-map

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

เทคนิคถัดไป · แผนที่ช่องหกเหลี่ยม