01Overall Concept
ไอเดียหลัก — Elastic Net รวมกติกาของ Ridge และ Lasso ไว้ด้วยกัน จึงทั้งคุมไม่ให้น้ำหนักใหญ่เกินไปและตัดตัวแปรบางตัวออกได้ วิธีนี้เหมาะเมื่อมีตัวแปรจำนวนมากและหลายตัวเล่าเรื่องคล้ายกัน
ลองนึกภาพว่า — เหมือนจัดทีมฟุตบอลภายใต้งบจำกัด เราต้องเลือกผู้เล่นที่จำเป็นเหมือน Lasso และยังต้องแบ่งหน้าที่ไม่ให้คนใดคนหนึ่งแบกทั้งทีมเหมือน Ridge
ตัวอย่างการนำไปใช้ — เลือกคำจากเอกสารจำนวนมาก วิเคราะห์ข้อมูลยีน หรือพยากรณ์จากตารางที่มี feature เป็นกลุ่มและสัมพันธ์กันสูง
02อธิบายภาษาคนเข้าใจง่ายๆ
Elastic Net คือการพยายามเอาข้อดีของ Ridge กับ Lasso มารวมกัน
มันคิดประมาณว่า
“บางตัวไม่สำคัญก็ตัดออก แต่ตัวที่เหลือก็อย่าให้อิทธิพลแรงเกินไป”
สมมติเรามีข้อมูลจากลูกค้า 200 ตัวแปร และหลายตัวมีความสัมพันธ์กัน เช่น จำนวนครั้งที่เข้าเว็บไซต์ จำนวนครั้งที่เปิดแอป จำนวนวันที่ใช้งานต่อเดือน สิ่งเหล่านี้อาจสะท้อนเรื่องเดียวกันคือ “ระดับ Engagement”
ถ้าใช้ Lasso อย่างเดียว บางครั้งมันอาจเลือกมาแค่หนึ่งตัวแล้วตัดที่เหลือหมด แต่ Elastic Net สามารถเก็บกลุ่มของตัวแปรที่เกี่ยวข้องกันไว้บ้าง พร้อมกับลดตัวที่ไม่สำคัญออก
เพราะแบบนี้ Elastic Net มักเหมาะกับข้อมูลยุคปัจจุบันที่มีฟีเจอร์จำนวนมากและฟีเจอร์เหล่านั้นมักเกี่ยวข้องกัน
ภาพจำ: Lasso เป็นฝ่ายคัดคนออก ส่วน Ridge เป็นฝ่ายควบคุมไม่ให้ใครเสียงดังเกินไป Elastic Net มีทั้งสองฝ่ายอยู่ในห้องเดียวกัน
03How it works
ค่อยๆ ทำไปด้วยกัน ตั้งแต่ข้อมูลแถวแรกจนถึงการตรวจคำตอบ
เริ่มจากคอลัมน์ลูกค้าที่พูดเรื่องคล้ายกัน
สมมติ X มีจำนวนเข้าเว็บ จำนวนเปิดแอป จำนวนวันที่ใช้งาน และราคาเฉลี่ยที่ซื้อ ส่วน y เป็นยอดใช้จ่ายเดือนถัดไป ใช้ข้อมูลก่อนเดือนที่ต้องการทำนาย แบ่งชุดฝึกและทดสอบตามเวลา แล้วปรับสเกลตัวเลขด้วย StandardScaler ภายใน Pipeline
มีทั้งฝ่ายคัดออกและฝ่ายคุมเสียง
โมเดลทำนายแบบเส้นตรงเหมือนเดิม แต่ค่าปรับมีทั้งผลรวม |w| แบบ Lasso และผลรวม w² แบบ Ridge ส่วนแรกช่วยให้น้ำหนักบางตัวเป็นศูนย์ ส่วนหลังช่วยคุมน้ำหนักเมื่อหลายคอลัมน์เกี่ยวข้องกัน โมเดลหาน้ำหนักที่ประนีประนอมระหว่างทายให้ใกล้กับไม่ใช้สูตรที่แรงเกินไป
แยกสองปุ่มให้ชัด
alpha คุมความแรงรวมของค่าปรับ ส่วน l1_ratio คุมสัดส่วนฝั่ง Lasso เช่น 0.2 เอนไปทาง Ridge, 0.8 เอนไปทาง Lasso และ 1 คือ Lasso เริ่มด้วย ElasticNet(alpha=0.1, l1_ratio=0.5, max_iter=10000) ค่าทั้งหมดนี้ยังต้องปรับกับข้อมูลจริง ไม่ควรเปลี่ยน l1_ratio แล้วคิดว่าได้ทดสอบทุกระดับความแรงแล้ว
ฝึกแล้วลองปรับเป็นตาราง
ใช้ make_pipeline(StandardScaler(), ElasticNet(...)) แล้ว fit ด้วย X_train, y_train ลอง alpha หลายระดับร่วมกับ l1_ratio เช่น 0.2, 0.5, 0.8 โดย cross-validation ภายในชุดฝึก สำหรับข้อมูลตามเวลาให้แบ่ง fold ตามลำดับเวลา จากนั้นนำคู่ค่าที่เหมาะที่สุดไป predict(X_test)
ดูทั้งยอดขายที่ทายและสูตรที่เหลือ
เปรียบเทียบ RMSE กับ Ridge และ Lasso โดยใช้การแบ่งข้อมูลเดียวกัน พร้อมนับ coef_ ที่ไม่เป็นศูนย์ ถ้าโมเดลเล็กลงมากแต่ error เพิ่มนิดเดียว อาจเหมาะกับงานที่ต้องดูแลระยะยาว แต่ถ้าตัวแปรสำคัญถูกบีบจนทายลูกค้ากลุ่มใหญ่ผิด ลองลด alpha และตรวจข้อมูลแยกตามกลุ่มลูกค้า
ข้อมูล พารามิเตอร์ และภาพรวมการคำนวณ
alphal1_ratiomax_iterข้อมูลที่รับเข้ามา
รับตารางตัวเลข X และค่าเป้าหมาย y เหมาะกับข้อมูลมิติสูงที่ feature หลายตัวมีข้อมูลซ้ำหรือเคลื่อนไปด้วยกัน
X = [เข้าเว็บ, เปิดแอป, วันที่ใช้งาน, …] · y = ยอดใช้จ่ายพารามิเตอร์ที่ใช้
- alpha
- ความแรงรวมของ regularization ทั้งหมด
- l1_ratio
- สัดส่วน Lasso ต่อ Ridge ตั้งแต่ 0 ถึง 1
- max_iter
- จำนวนรอบสูงสุดในการหาน้ำหนักที่ลงตัว
ผลลัพธ์ที่ได้
ได้ค่าทำนายและ coefficients ที่บางตัวเป็นศูนย์ ขณะที่ feature ที่คล้ายกันยังแบ่งน้ำหนักกันได้
alpha คุมแรงรวม · l1_ratio คุมสัดส่วน Lasso/Ridgeคำนวณทีละขั้น
- 01
คำนวณ MSE ของคำทำนายจากสมการเส้นตรง
- 02
เพิ่มค่าปรับ L1 สำหรับการตัด feature และ L2 สำหรับบีบน้ำหนักให้เสถียร
- 03
ผสมค่าปรับตาม l1_ratio แล้วปรับ coefficients จน objective ต่ำที่สุด
ควรรู้อีกนิด — มี hyperparameter มากขึ้นและต้องเลือกด้วย cross-validation โดยเฉพาะเมื่อหน่วยของ feature ต่างกัน
04Make it yours
# ติดตั้ง: pip install numpy scikit-learn matplotlibfrom sklearn.linear_model import ElasticNetfrom sklearn.metrics import mean_squared_error import numpy as npfrom sklearn.model_selection import train_test_split rng = np.random.default_rng(42)X = np.linspace(-1, 1, 60).reshape(-1, 1)y = 0.1 + 0.55*X[:, 0] + 0.55*np.sin(3.4*X[:, 0])y += rng.normal(0, 0.14, len(y))X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42) model = ElasticNet(alpha=0.12, l1_ratio=0.50, max_iter=10000)model.fit(X_train, y_train)pred = model.predict(X_test)print("RMSE:", mean_squared_error(y_test, pred) ** 0.5)โค้ดเปลี่ยนตามค่าที่เลือกใน Playground · แต่ละภาษาใช้ข้อมูลตัวอย่างตามที่ระบุในโค้ด
05Learn by playing
ปรับ l1_ratio แล้วสังเกตรูปแบบคำทำนายและตัวชี้วัดที่คำนวณใหม่ทันที
Playground เป็น implementation เพื่อการเรียนรู้ที่คำนวณในเบราว์เซอร์ ส่วนโค้ด Python ใช้ scikit-learn จึงอาจให้ค่าต่างกันเล็กน้อยจากรายละเอียดการ optimize และค่าเริ่มต้นของไลบรารี ผลนี้ไม่ใช่ benchmark บนข้อมูลจริง