สร้าง Column ใหม่จาก Condition ด้วย Numpy.where และ Numpy.select
การสร้าง Column ใหม่จาก Condition เนี่ย มันโคตรจะเป็นอะไรที่ Basic มากสำหรับการทำโมเดลใด ๆ แล้วก็เป็นเรื่องที่โดนมองข้ามด้วย เพราะมันไม่ค่อยจะเป็นปัญหาเลยด้วยซ้ำ
จากที่เคยแนะนำตัวไปใน Blog ตอนนี้ ว่า ผมเองเป็น SAS User มาก่อน (ซึ่งเขียนจนถึงตอนนี้แล้ว ยังไม่ได้แชร์อะไรเกี่ยวกับ SAS เลย) ช่วงหลังนี้เองเพิ่งจะมาใช้ Python ในการเขียนโมเดล ซึ่งยอมรับว่ามันมีเรื่องดีและเรื่องที่ต้องปรับตัวแตกต่างกันไป
เข้าเรื่องดีกว่า…
การใช้ Condition logic แบบ if… else… นี้มันเป็นพื้นฐานสำหรับ Modeller เลยนะ เอาจริง ๆ มันอาจจะเป็นพื้นฐานสำหรับทุกเรื่องก็ได้ พอเราทำงานบน SAS หรือ Excel มันก็ไม่มีอะไรมาก มันสร้างเขียนคำสั่งได้ง่าย ๆ เช่น
หรือใน Excel ก็เขียนได้ไม่ยากเช่นกัน (คงไม่ต้องเขียนให้ดูมั้ง…) คราวนี้เนี่ย ผมก็อยากใช้ Logic เดียวกัน สร้าง Column ใหม่ใน Pandas dataframe
เลยลองค้นหาดู มันก็มีวิธีทำนะ มันต้องเขียนฟังก์ชั่นใหม่ขึ้นมา ที่ม Condition ที่เราต้องการอยู่ แล้วก็ใช้คำสั่ง apply
เพื่อรันคำสั่งนั้น ๆ ให้สร้างเป็น Column ใหม่ขึ้นมา หน้าตาก็จะประมาณนี้ (อย่าเพิ่งด่าว่าโง่เลยนะ)
ฟังดูเหมือนมันแค่โง่ แต่มันก็ไม่มีปัญหาอะไรใช่ไหม?
พอใช้งานไปสักพัก… มันเริ่มไม่ไหวแหะ มันเริ่มช้า พอเจอข้อมูลแบบหลายสิบล้าน จนไปถึงร้อยล้าน rows นี่ เครื่องรันไม่ได้เลย ตอนแรกก็โทษเครื่องนะว่าช้า แต่พอมาคิดดี ๆ มันต้องมีวิธีสิ
ค้นไปค้นมา ก็เจอวิธีใช้ numpy.where
และ numpy.select
คือจริง ๆ ไม่รู้ว่ามันเกิดมาเพราะอะไรหรอก 2 Packages นี้ แต่ว่ามันช่วยงานผมได้เยอะมาก ๆ วันนี้เลยจะมาลองรัน test ความเร็วกัน
เริ่มต้นด้วยการ Import packages เหมือนเดิม ครั้งนี้แตกต่างออกไป เพราะไม่ได้เอาข้อมูลจริง ๆ มันทำแล้ว อยากสร้างข้อมูลที่มีจำนวนเยอะ ๆ เพื่อที่จะได้เห็นความเร็วตอน run code การสร้างก็ไม่ได้ยาก random number ระหว่าง 0 ถึง 100 มาทั้งหมด 1 column กับอีกล้านกว่า rows
เรามาเริ่มกันที่ Pandas กันก่อน ครั้งนี้ทดสอบทั้งหมด 2 logic ง่าย ๆ คือ
- flag ค่าที่น้อยกว่า 50 กับมากกว่า 50
- flag ค่าที่น้อยกว่า 30 อยู่ระหว่าง 31 ถึง 50 และมากกว่า 50
แล้วก็สั่งให้มัน print เวลาออกมา ผลที่ได้คือ
Apply 1 time = 15.393322229385376
Apply 2 time = 24.506651163101196
ใช้เวลานานมากกกกกกก ไม่รู้ทำไมนานขนาดนี้เหมือนกัน หรือเพราะว่ามันไม่ได้เกิดมาเพื่อทำอะไรแบบนี้ ใครรู้รบกวนแชร์ความเห็นหน่อยนะครับ
ต่อมามาลองใช้ Package numpy.where
กับ numpy.select
กันบ้างนะ โดยจะใช้ Condition เหมือนเดิมเลย ส่วนเรื่อง Syntax ก็ง่ายละสั้นมาก ๆ ตาม Code ข้างล่างได้เลย
numpy.where
ใช้สำหรับ 1 เงื่อนไขตามข้อ 1. คือถ้าไม่อย่างใด ก็ต้องทำอย่างหนึ่ง ส่วน numpy.select
ใช้สำหรับมากกว่า 1 เงื่อนไขตามข้อ 2. จริง ๆ มันสามารถเขียนแบบไม่ต้องใช้ option default ก็ได้นะ มันก็จะเป็นแบบนี้ df[‘select’] = np.select([df[‘test’] < 30, df[‘test’] < 50, df[‘test’] >= 50], [1,2,3])
อันนี้แล้วแต่คนถนัดของแต่ละคนเลย ส่วนผลลัพธ์ที่ออกมาก็คือ
Where time = 0.009963750839233398
Select time = 0.031511783599853516
บอกได้เลยว่ามันแตกต่างมาก ๆ คราวนี้ใครรู้ว่าเพราะอะไรมันถึงต่างกันขนาดนี้ ช่วยบอกผมหน่อยนะครับ