ซาวข้าวและชิมข้าว: ทำความสะอาดและตรวจสอบข้อมูล
wash-and-taste.Rmd
library(khaosuay)
#> khaosuay: สำหรับกราฟภาษาไทย เรียก setup_thai_font() ก่อนใช้ serve_plate()ทำไมต้องซาวข้าว? (Why wash_rice?)
ข้อมูลจากแปลงทดลองทางการเกษตรมักมีปัญหาหลายอย่าง:
- ชื่อคอลัมน์ไม่สม่ำเสมอ (ภาษาไทย/อังกฤษ ตัวพิมพ์ใหญ่/เล็ก)
- ค่าว่าง (empty string) ที่ไม่ใช่ NA
- ตัวเลขถูกเก็บเป็น character (เช่น มีเครื่องหมาย comma)
- ค่าผิดปกติ (outlier) จากการคีย์ข้อมูลผิด
- แผนการทดลองไม่สมดุล (missing combinations)
wash_rice() จัดการปัญหาเหล่านี้อัตโนมัติ แต่
ไม่ลบหรือแก้ไขข้อมูลดิบ โดยตรง — เพียงแต่ แจ้งเตือนและ
flag ให้คุณพิจารณาก่อนตัดสินใจ
ตัวอย่าง: ข้อมูลที่มีปัญหาหลายจุด
# สร้างข้อมูลที่มี "ปัญหา" หลายจุด
messy_data <- data.frame(
Variety = c("KDML105", "KDML105", "RD41", "RD41", "RD57", "RD57",
"KDML105", "KDML105", "RD41", "RD41", "RD57", "RD57"),
Rep = c(1, 2, 1, 2, 1, 2, 3, 4, 3, 4, 3, 4),
Yield = c(650, 680, 590, 610, 720, 700, 660, 640, 600, 585, 710, 695),
Height = c(120, 125, 110, 115, 130, 128, 122, 118, 112, 108, 132, -5),
stringsAsFactors = FALSE
)
messy_data
#> Variety Rep Yield Height
#> 1 KDML105 1 650 120
#> 2 KDML105 2 680 125
#> 3 RD41 1 590 110
#> 4 RD41 2 610 115
#> 5 RD57 1 720 130
#> 6 RD57 2 700 128
#> 7 KDML105 3 660 122
#> 8 KDML105 4 640 118
#> 9 RD41 3 600 112
#> 10 RD41 4 585 108
#> 11 RD57 3 710 132
#> 12 RD57 4 695 -5การซาวข้าวแบบพื้นฐาน
washed <- wash_rice(messy_data, treatment_col = "Variety", rep_col = "Rep")
#> [INFO] ปรับชื่อคอลัมน์ 4 ตัว
#> [MAP] คอลัมน์กรรมวิธี: 'variety' (ไม่เปลี่ยนชื่อ)
#> [MAP] คอลัมน์ซ้ำ: 'rep' (ไม่เปลี่ยนชื่อ)
#> [INFO] แปลงเป็น Factor: rep
#> Warning in wash_rice(messy_data, treatment_col = "Variety", rep_col = "Rep"):
#> [WARN] พบค่าติดลบในคอลัมน์: height
#> [FLAG] พบค่าผิดปกติ (outlier) รวม 1 จุด ในคอลัมน์: height → ดู $flagged
#>
#> --------------------------------------------------
#> wash_rice v3.1 — สรุปผลการล้างข้าว
#> --------------------------------------------------
#> • แถว: 12 -> 12
#> • คอลัมน์: 4
#> • Factor: rep
#> • Numeric: yield, height
#> • Outliers: 1 จุด
#> • Flagged: 2 แถว -> ดูใน $flagged
#> --------------------------------------------------
#> ล้างข้าวเสร็จเรียบร้อย! ข้อมูลพร้อมหุงแล้ว
#> --------------------------------------------------ดูผลลัพธ์
# ข้อมูลที่สะอาดแล้ว
washed$data
#> variety rep yield height
#> 1 KDML105 1 650 120
#> 2 KDML105 2 680 125
#> 3 RD41 1 590 110
#> 4 RD41 2 610 115
#> 5 RD57 1 720 130
#> 6 RD57 2 700 128
#> 7 KDML105 3 660 122
#> 8 KDML105 4 640 118
#> 9 RD41 3 600 112
#> 10 RD41 4 585 108
#> 11 RD57 3 710 132
#> 12 RD57 4 695 -5
# ดูว่าคอลัมน์ถูก map อย่างไร
washed$column_map
#> original standardized
#> 1 Variety variety
#> 2 Rep rep
#> 3 Yield yield
#> 4 Height height
# ดูแถวที่ถูก flag
washed$flagged
#> variety rep yield height .row_number .flag_reason .flag_column
#> 12 RD57 4 695 -5 12 ค่าติดลบใน 'height' height
#> 121 RD57 4 695 -5 12 outlier (iqr) ใน 'height' height
#> .flag_value
#> 12 -5
#> 121 -5พารามิเตอร์สำคัญของ wash_rice()
กำหนดพิสัยที่ยอมรับ (valid_ranges)
washed2 <- wash_rice(
messy_data,
treatment_col = "Variety",
rep_col = "Rep",
valid_ranges = list(yield = c(0, 1500), height = c(0, 200)),
design_check = TRUE
)
#> [INFO] ปรับชื่อคอลัมน์ 4 ตัว
#> [MAP] คอลัมน์กรรมวิธี: 'variety' (ไม่เปลี่ยนชื่อ)
#> [MAP] คอลัมน์ซ้ำ: 'rep' (ไม่เปลี่ยนชื่อ)
#> [INFO] แปลงเป็น Factor: rep
#> Warning in wash_rice(messy_data, treatment_col = "Variety", rep_col = "Rep", :
#> [WARN] พบค่าติดลบในคอลัมน์: height
#> Warning in wash_rice(messy_data, treatment_col = "Variety", rep_col = "Rep", :
#> [WARN] 'height': พบ 1 ค่านอกพิสัย [0-200]
#> [FLAG] พบค่าผิดปกติ (outlier) รวม 1 จุด ในคอลัมน์: height → ดู $flagged
#> Warning in wash_rice(messy_data, treatment_col = "Variety", rep_col = "Rep", : [WARN] ไม่สามารถเช็คแผนการทดลองได้ — ไม่พบคอลัมน์: treatment
#> ลองระบุผ่าน treatment_col / rep_col
#> หรือเพิ่มใน custom_aliases
#>
#> --------------------------------------------------
#> wash_rice v3.1 — สรุปผลการล้างข้าว
#> --------------------------------------------------
#> • แถว: 12 -> 12
#> • คอลัมน์: 4
#> • Factor: rep
#> • Numeric: yield, height
#> • Outliers: 1 จุด
#> • Flagged: 3 แถว -> ดูใน $flagged
#> --------------------------------------------------
#> ล้างข้าวเสร็จเรียบร้อย! ข้อมูลพร้อมหุงแล้ว
#> --------------------------------------------------เมื่อกำหนด valid_ranges ค่าที่อยู่นอกพิสัยจะถูก flag แต่ไม่ถูกลบออก
ให้คุณกลับไปตรวจสอบข้อมูลดิบเอง
Smart Alias Dictionary
wash_rice() มี dictionary
ที่จับคู่ชื่อคอลัมน์ภาษาไทย/อังกฤษอัตโนมัติ:
| Role | ชื่อที่รองรับ |
|---|---|
| Treatment | treatment, trt, variety, var, genotype, gen, entry, line, cultivar, cv, สายพันธุ์, กรรมวิธี, พันธุ์, สูตร, ทรีทเมนต์ |
| Rep/Block | rep, block, blk, replication, replicate, r, ซ้ำ, บล็อก, กลุ่ม |
สามารถเพิ่มเองผ่าน custom_aliases:
washed5 <- wash_rice(
data = my_data,
custom_aliases = list(
treatment = c("formula", "fungicide"),
rep = c("set", "round")
)
)ทำไมต้องชิมข้าว? (Why taste_rice?)
ก่อนจะ “หุงข้าว” (วิเคราะห์สถิติ) เราต้องรู้ก่อนว่าข้อมูลมีลักษณะเป็นอย่างไร เพื่อเลือกสถิติที่เหมาะสม:
| ลักษณะข้อมูล | ผลการชิม | สถิติที่ควรใช้ |
|---|---|---|
| Normal + Equal Variance | Parametric | ANOVA + Tukey HSD |
| Normal + Unequal Variance | Welch | Welch’s ANOVA + Games-Howell |
| Non-normal | Non-parametric | Kruskal-Wallis + Dunn’s test |
taste_rice() ทดสอบให้อัตโนมัติ และส่งคำตอบนี้ให้
cook_*() เลือกสถิติที่ถูกต้อง
ตัวอย่าง: ชิมข้าวแบบต่าง ๆ
Quick mode: ตรวจจาก raw data
set.seed(42)
trial_data <- data.frame(
variety = rep(c("A", "B", "C", "D"), each = 5),
rep = rep(1:5, times = 4),
yield = c(
rnorm(5, 600, 30), rnorm(5, 550, 25),
rnorm(5, 680, 35), rnorm(5, 590, 20)
)
)
washed <- wash_rice(trial_data, treatment_col = "variety", rep_col = "rep",
verbose = FALSE)
tasted_quick <- taste_rice(washed, response = "yield", treatment = "variety",
mode = "quick", plot = FALSE, verbose = FALSE)
print(tasted_quick)
#> ── tasted_rice v2.0 ──
#> Design: Single Factor
#> Mode: quick
#>
#> response final_class recommendation
#> yield Non-normal 🚨 ใช้ Kruskal-Wallis test → Dunn's test
#>
#> yield [4 กลุ่ม]: 🚨 ใช้ Kruskal-Wallis test → Dunn's testModel mode: ตรวจจาก residuals ของ ANOVA model
tasted_model <- taste_rice(washed, response = "yield", treatment = "variety",
mode = "model", plot = FALSE, verbose = FALSE)
print(tasted_model)
#> ── tasted_rice v2.0 ──
#> Design: Single Factor
#> Mode: model
#>
#> response final_class recommendation
#> yield Normal + Equal Variance ✅ ใช้ Fisher's ANOVA → Tukey HSD
#>
#> yield [4 กลุ่ม]: ✅ ใช้ Fisher's ANOVA → Tukey HSDBoth mode (แนะนำ): ตรวจทั้ง raw data และ residuals
tasted_both <- taste_rice(washed, response = "yield", treatment = "variety",
mode = "both", plot = FALSE, verbose = FALSE)
print(tasted_both)
#> ── tasted_rice v2.0 ──
#> Design: Single Factor
#> Mode: both
#>
#> response final_class recommendation
#> yield Normal + Equal Variance ✅ ใช้ Fisher's ANOVA → Tukey HSD
#>
#> yield [4 กลุ่ม]: ✅ ใช้ Fisher's ANOVA → Tukey HSDหมายเหตุ: เมื่อใช้ mode = "both" ผลจาก
residuals (model) จะถูกใช้เป็นผลสุดท้าย เพราะเป็นวิธีที่ถูกต้องกว่าทางสถิติ
ชิมข้าวหลายตัวแปรพร้อมกัน
trial_data$height <- c(
rnorm(5, 120, 5), rnorm(5, 115, 8),
rnorm(5, 130, 6), rnorm(5, 118, 4)
)
washed <- wash_rice(trial_data, treatment_col = "variety", rep_col = "rep",
verbose = FALSE)
tasted_multi <- taste_rice(
washed,
response = c("yield", "height"),
treatment = "variety",
mode = "both",
plot = FALSE,
verbose = FALSE
)
print(tasted_multi)
#> ── tasted_rice v2.0 ──
#> Design: Single Factor
#> Mode: both
#>
#> response final_class recommendation
#> yield Normal + Equal Variance ✅ ใช้ Fisher's ANOVA → Tukey HSD
#> height Normal + Equal Variance ✅ ใช้ Fisher's ANOVA → Tukey HSD
#>
#> yield [4 กลุ่ม]: ✅ ใช้ Fisher's ANOVA → Tukey HSD
#> height [4 กลุ่ม]: ✅ ใช้ Fisher's ANOVA → Tukey HSDฟังก์ชันจะตรวจทุกตัวแปรที่ระบุ และบอกคำแนะนำแยกรายตัว ผลนี้ส่งต่อไปยัง
cook_*() ได้ทันที เพื่อให้แต่ละตัวแปรถูกวิเคราะห์ด้วยสถิติที่ถูกต้อง
ชิมข้าวสำหรับ RCBD (มี Block)
tasted_rcbd <- taste_rice(
washed,
response = "yield",
treatment = "variety",
block = "rep",
mode = "both",
plot = FALSE,
verbose = FALSE
)
print(tasted_rcbd)
#> ── tasted_rice v2.0 ──
#> Design: Single Factor
#> Mode: both
#>
#> response final_class recommendation
#> yield Normal + Equal Variance ✅ ใช้ Fisher's ANOVA → Tukey HSD
#>
#> yield [4 กลุ่ม]: ✅ ใช้ Fisher's ANOVA → Tukey HSDเมื่อระบุ block ฟังก์ชันจะรวม block เข้าไปใน model สำหรับการตรวจ
residuals
สรุป Workflow ขั้นตอนที่ 1-2
# ขั้นตอนที่ 1: ซาวข้าว
washed <- wash_rice(
data = raw_data,
treatment_col = "variety",
rep_col = "rep",
valid_ranges = list(yield = c(0, 1500)),
design_check = TRUE
)
# ตรวจสอบ flagged rows -> กลับไปแก้ไขข้อมูลดิบถ้าจำเป็น
washed$flagged
# ขั้นตอนที่ 2: ชิมข้าว
tasted <- taste_rice(
data = washed,
response = c("yield", "height"),
treatment = "variety",
mode = "both"
)
# ดูคำแนะนำ
tasted$verdict
# พร้อมส่งต่อไป cook_crd() / cook_rcbd() / cook_split()