Percentile Capping (Winsorize)
winsorize · outlier · number, text
2026-09-24
กำลังประมวลผล…
winsorize · outlier · number, text
2026-09-24
เมื่อค่าสุดขั้วไม่กี่ค่าดึงค่าเฉลี่ยจนรายงานเพี้ยน ทางเลือกหนึ่งคือลบแถวทิ้ง แต่นั่นทำให้จำนวนแถวไม่ตรงกับความจริง Winsorize เลือกอีกทาง คือ เก็บทุกแถวไว้แต่จำกัดค่าสุดขั้ว ให้เท่ากับค่าที่เปอร์เซ็นไทล์ที่กำหนด ค่าเฉลี่ยจึงเสถียรขึ้นโดยจำนวนแถวไม่เปลี่ยน
lower และ upper ด้วยการประมาณค่าเชิงเส้นlower ต้องน้อยกว่า upper ไม่อย่างนั้นระบบจะหยุดพร้อมข้อความบอกเหตุผลต่างจาก
clamp_valueตรงที่ขอบมาจาก การกระจายตัวของข้อมูลเอง ไม่ใช่ตัวเลขที่คุณกำหนด จึงใช้ได้แม้ยังไม่รู้ช่วงที่ถูกต้อง แต่ก็แปลว่าขอบจะเปลี่ยนไปตามไฟล์แต่ละรอบ
import json
def quantile(sorted_values, q):
position = (len(sorted_values) - 1) * q
base = int(position)
rest = position - base
lower = sorted_values[base]
upper = sorted_values[base + 1] if base + 1 < len(sorted_values) else lower
return lower + rest * (upper - lower)
def winsorize(values, lower=0.01, upper=0.99, decimals=6):
if lower >= upper:
raise ValueError('lower ต้องน้อยกว่า upper')
numbers = sorted(v for v in values if isinstance(v, (int, float)) and not isinstance(v, bool))
if not numbers:
return list(values)
low, high = quantile(numbers, lower), quantile(numbers, upper)
result = []
for value in values:
if not isinstance(value, (int, float)) or isinstance(value, bool):
result.append(value)
continue
result.append(round(min(high, max(low, value)), decimals))
return result
values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 100]
print(json.dumps(winsorize(values, 0.1, 0.9), ensure_ascii=False))
คอลัมน์ order_amount มีคำสั่งซื้อองค์กรไม่กี่รายการที่ยอดสูงกว่าค่าทั่วไปห้าสิบเท่า ทำให้ยอดเฉลี่ยต่อออเดอร์ที่รายงานทุกเดือนแกว่งตามว่าเดือนนั้นมีออเดอร์ใหญ่กี่รายการ ใช้ winsorize ที่ 1% และ 99% สร้างเป็นคอลัมน์แยกสำหรับรายงานค่าเฉลี่ย แต่ ยอดรวมต้องใช้คอลัมน์ดิบเสมอ และระบุในรายงานว่าค่าเฉลี่ยคำนวณจากข้อมูลที่จำกัดค่าสุดขั้วแล้ว
ใช้ outlier_iqr เพื่อดูก่อนว่ามีค่าสุดขั้วกี่ค่า ใช้ clamp_value เมื่อรู้ช่วงที่ถูกต้องตามกฎธุรกิจ และใช้ scale_values หลังจำกัดค่าสุดขั้วแล้วเพื่อให้สเกลไม่ถูกบีบ