01ภาพรวมของกราฟนี้
Term-document heatmap จัดคำเป็นแถวและเอกสารเป็นคอลัมน์แล้วระบายสีตามความถี่ ทำให้เห็นว่าคำไหนเป็นลักษณะเฉพาะของเอกสารไหน สิ่งที่ต้องทำเสมอคือทำให้ค่าเป็นมาตรฐานก่อน ไม่อย่างนั้นเอกสารที่ยาวกว่าจะเข้มกว่าทุกแถว
เปรียบเทียบให้เห็นภาพ
เหมือนตารางเปรียบเทียบส่วนผสมของอาหารหลายจาน ซึ่งเห็นทันทีว่าจานไหนใส่อะไรเป็นพิเศษ
ใช้ที่ไหนบ้าง — เทียบภาษาที่ใช้ระหว่างกลุ่มลูกค้า เทียบหัวข้อระหว่างช่วงเวลา หรือเทียบคำที่พรรคการเมืองต่าง ๆ ใช้
สร้างอย่างไร
- ขั้นที่ 1★ ทำให้ความถี่เป็นมาตรฐานตามความยาวของเอกสาร
- ขั้นที่ 2เลือกคำที่จะแสดงด้วยเกณฑ์ที่ระบุได้
- ขั้นที่ 3เรียงคำด้วยการจัดกลุ่มเพื่อให้รูปแบบปรากฏ
- ขั้นที่ 4ใช้สเกลสีลำดับเดียวและใส่คำอธิบาย
ตัวอย่างคลาสสิก · TF-IDF กับการหาคำที่เป็นลักษณะเฉพาะ
น้ำหนักแบบ TF-IDF ถูกเสนอขึ้นเพื่อแก้ปัญหาว่าคำที่พบบ่อยที่สุดมักเป็นคำที่ไม่บอกอะไร โดยเพิ่มน้ำหนักให้คำที่ปรากฏในไม่กี่เอกสารและลดน้ำหนักคำที่ปรากฏทุกที่ แนวคิดนี้กลายเป็นพื้นฐานของทั้งระบบค้นหาและการวิเคราะห์ข้อความ
02อธิบายภาษาคนเข้าใจง่าย ๆ
กราฟแท่งความถี่คำตอบได้แค่ว่าคำไหนพบบ่อยในข้อความทั้งชุด แต่คำถามที่มีค่ากว่ามักเป็นว่าคำไหนเป็นลักษณะเฉพาะของกลุ่มไหน
Term-document heatmap ตอบคำถามนั้นด้วยการจัดคำเป็นแถวและเอกสารหรือกลุ่มเป็นคอลัมน์ แล้วระบายสีตามความถี่
สิ่งที่ปรากฏขึ้นคือลายเส้นแนวนอนของคำที่ใช้ทุกกลุ่มเท่ากัน และจุดเข้มเดี่ยว ๆ ของคำที่กลุ่มเดียวเท่านั้นที่ใช้ ซึ่งจุดหลังคือสิ่งที่มีค่าที่สุด
กับดักที่ใหญ่ที่สุดคือความยาวของเอกสาร ถ้าเอกสารหนึ่งยาวกว่าอีกเอกสารสิบเท่า มันก็จะเข้มกว่าทุกแถวโดยอัตโนมัติ ซึ่งไม่ได้บอกอะไรเลย
ทางแก้คือทำให้ค่าเป็นมาตรฐานตามความยาวเสมอ หรือใช้น้ำหนักแบบ TF-IDF ซึ่งเพิ่มน้ำหนักให้คำที่ปรากฏในไม่กี่เอกสารและลดน้ำหนักคำที่ปรากฏทุกที่
อีกเรื่องที่ต้องระบุคือเกณฑ์เลือกคำที่จะแสดง เพราะการเลือกเฉพาะคำที่สนับสนุนข้อสรุปที่ตั้งไว้เป็นเรื่องที่ทำได้ง่ายมากและมองไม่เห็นจากภาพ
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
word | คำ | ข้อความ | row | 10–60 คำ | เรียงด้วยการจัดกลุ่ม |
count | ความถี่ที่ทำเป็นมาตรฐานแล้ว | ตัวเลขต่อเนื่อง | color | ศูนย์ถึงสูงสุด | ★ ต้องหารด้วยความยาวเอกสารก่อน |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- ★ ทำให้ความถี่เป็นมาตรฐานหรือใช้ TF-IDF
- ตัดคำหยุดออก
- ★ ระบุเกณฑ์ที่ใช้เลือกคำที่จะแสดง
ค่าที่หายไป — คำที่ไม่ปรากฏในเอกสารหนึ่งคือค่าศูนย์ซึ่งต่างจากไม่มีข้อมูล ต้องแยกให้ชัด
สเกลของแกน — ใช้สเกลสีลำดับเดียว และเมื่อค่ากระจายแบบหางยาวให้พิจารณาสเกลลอการิทึมพร้อมระบุ
กราฟจะเริ่มพังเมื่อไร
เกิน 60 คำ ชื่อแถวอ่านไม่ออก
หน้าตาไฟล์ที่ต้องเตรียม
word,count
ส่งเร็ว,331
ราคา,179
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- คำที่เป็นลักษณะเฉพาะของเอกสารเดียว
- คำที่ใช้เหมือนกันทุกเอกสาร
- กลุ่มของเอกสารที่ใช้ภาษาคล้ายกัน
สิ่งที่กราฟนี้ตอบไม่ได้
- ★ ถ้าไม่ทำให้เป็นมาตรฐาน ภาพจะบอกแค่ว่าเอกสารไหนยาวกว่า
- บริบทของการใช้คำ
- คำที่ไม่ได้ถูกเลือกมาแสดง
อ่านตามลำดับนี้
- มองหาจุดเข้มเดี่ยว ๆ ซึ่งคือคำเฉพาะของเอกสารนั้น
- มองหาแถวที่เข้มทั้งแถวซึ่งคือคำที่ใช้ทุกที่
- ตรวจว่าทำให้เป็นมาตรฐานแล้วหรือยัง
คำถามที่ตอบได้
- เอกสารนี้ใช้คำอะไรเป็นพิเศษ
- มีคำไหนที่ใช้เหมือนกันหมด
- เอกสารไหนใช้ภาษาคล้ายกัน
สัญญาณว่ามีอะไรผิด
- ไม่ทำให้ค่าเป็นมาตรฐาน
- ไม่ระบุเกณฑ์เลือกคำ
- เรียงคำตามตัวอักษรแทนการจัดกลุ่ม
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- ★ ระบุวิธีทำให้เป็นมาตรฐานและเกณฑ์เลือกคำ
- ตีกรอบคำที่ต้องการชี้ให้เห็น
- ใส่ตัวเลขในช่องเมื่อตารางเล็กพอ
รูปแบบชื่อกราฟที่ควรใช้
คำที่เป็นลักษณะเฉพาะของแต่ละ <กลุ่ม> โดย <กลุ่ม> เด่นด้วยคำว่า <คำ>
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ term-document-heatmap-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด term-document-heatmap-sample.csv จากหน้านี้ แล้ววางไว้ข้างสคริปต์
import matplotlib
matplotlib.use("Agg") # รันแบบไม่มีหน้าจอ ถ้ารันในเครื่องตัวเองลบบรรทัดนี้ได้
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
import seaborn as sns
C1, C2, C3 = "#2a78d6", "#eb6834", "#1baf7a" # palette ของคลัง เปลี่ยนเป็นสีองค์กรได้
INK, SURFACE = "#0b0b0b", "#fcfcfb"
df = pd.read_csv("term-document-heatmap-sample.csv")
df["count"] = pd.to_numeric(df["count"], errors="coerce")
NOTE = "unique" # ← ค่าจาก Playground
fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)
# ★ TF-IDF จัดการเรื่องความยาวเอกสารให้เอง
vec = TfidfVectorizer(max_features=25, stop_words=THAI_STOPWORDS)
X = vec.fit_transform(documents) # documents = list ของข้อความ
mat = pd.DataFrame(X.T.toarray(), index=vec.get_feature_names_out(), columns=doc_names)
mat = mat.loc[mat.var(axis=1).sort_values(ascending=False).index] # เรียงตามความต่าง
sns.heatmap(mat, cmap="Blues", linewidths=2, linecolor="#fcfcfb", ax=ax,
cbar_kws={"label": "น้ำหนัก TF-IDF"})
ax.set_xlabel(""); ax.set_ylabel("")
ax.set_title("น้ำหนัก TF-IDF — ปรับตามความยาวเอกสารแล้ว", loc="left", fontsize=9)
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("term-document-heatmap.png", dpi=160)
print("เขียน term-document-heatmap.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
ถ้าเอกสารยาวไม่เท่ากัน ต้องหารด้วยจำนวนคำทั้งหมดก่อน ไม่อย่างนั้นเอกสารยาวจะเข้มทุกช่อง
ดูข้อมูลเป็นตาราง (10 แถว)
| คำ | รีวิว 1 ดาว | รีวิว 3 ดาว | รีวิว 5 ดาว | แชทซัพพอร์ต |
|---|---|---|---|---|
| ส่งเร็ว | 83 | 83 | 83 | 83 |
| ราคา | 67 | 157 | 90 | 179 |
| คุณภาพ | 110 | 95 | 79 | 63 |
| บริการ | 83 | 71 | 59 | 48 |
| แพ็กเกจ | 22 | 22 | 22 | 22 |
| คุ้มค่า | 16 | 16 | 16 | 16 |
| สวย | 61 | 31 | 53 | 23 |
| ช้า | 54 | 27 | 47 | 20 |
| ใช้ง่าย | 14 | 14 | 14 | 14 |
| พัง | 48 | 24 | 42 | 18 |
ลองแล้วจะเห็นอะไร
- สังเกตอะไร: จุดเข้มเดี่ยว ๆ คือคำที่เอกสารเดียวเท่านั้นที่ใช้ ซึ่งมีค่ากว่าแถวที่เข้มทั้งแถวมาก
ข้อควรระวัง
- ★ ไม่ทำให้ค่าเป็นมาตรฐาน ทำให้ภาพบอกแค่ว่าเอกสารไหนยาวกว่า
- ไม่ระบุเกณฑ์เลือกคำที่แสดง ซึ่งเปิดช่องให้เลือกเฉพาะคำที่สนับสนุนข้อสรุป
- เรียงคำตามตัวอักษรทำให้รูปแบบกระจายจนมองไม่เห็น
- ไม่แยกค่าศูนย์จากช่องที่ไม่มีข้อมูล
เมื่อไหร่ไม่ควรใช้กราฟนี้
- มีเอกสารชุดเดียว→ใช้แทน: word-frequency-bar
- สนใจการเปลี่ยนแปลงตามเวลา→ใช้แทน: topic-stream
- ต้องดูบริบทการใช้คำ→ใช้แทน: kwic-view