[Blog] มีโอกาสได้พูดคุย
ลองหาอะไรใหม่ ๆ ให้ตัวเอง
ไม่ว่าจะด้วยอะไรก็ตาม ทำให้มีโอกาสได้สร้างบทสนทนาที่มีคุณภาพกว่า 1 ชั่วโมง มีเรื่องมาเล่าที่สกัดออกมาจาก 10 นาทีจากทั้งหมด 1 ชั่วโมง รู้สึกว่ามันเติมไฟในภาวะที่ Burnout แบบนี้ได้ดี
ด้วยสายงานที่ทำอยู่ (Risk model) ทำให้ต้องเจอเรื่องที่ค่อนข้างเหมือนเดิม คำถามที่โดนถามก็เป็นคำถามเดิม ๆ คงเป็นเพราะมีรูปแบบในการพูดคุยที่ค่อนข้างชัดเจน แต่บทสนทนาที่เพิ่งเจอมา มันต่างออกไป…
แปลงเนื้อหาโจทย์ทั้งหมดแล้ว แต่ยังคง Concept เดิมไว้
ได้รับโจทย์ปัญหามา มีการอธิบายจากโจทย์ที่ให้มา และบอกสิ่งที่ต้องการเป็นผลลัพธ์สุดท้าย จากนั้นมีเวลาให้ 2 นาที สำหรับการเตรียมตัว และมีเวลา 3 นาที ในอธิบายวิธีการแก้โจทย์ การอธิบายเริ่มจากการบอกภาษาที่จะใช้ สามารถใช้ได้ไม่จำกัด! ซึ่งใช้ได้ทั้ง SAS, Python หรือ R ซึ่งเป็นสิ่งที่ดีมาก
เมื่อเลือกภาษาได้แล้ว สิ่งต่อไปที่ต้องบอกคือ คำสั่ง หรือฟังก์ชั่น ที่วางแผนว่าจะใช้งาน ซึ่งจำเป็นต้องบอกให้ครบทุกฟังก์ชั่น ในทุก ๆ ขั้นตอน ขาดไม่ได้ แต่เกินไม่เป็นไร แต่อาจยังไม่ต้องลงรายละเอียดถึง Syntax ในแต่ละขั้นตอน แต่การผ่าน Parameters อะไรบ้างต้องมี
จากนั้นมีเวลาอีก 5 นาที ทำทุกอย่างที่อธิบายไปแล้วเมื่อ 5 นาทีก่อน ออกมาเป็น Code พร้อมกับผลลัพธ์สุดท้าย ในระหว่างที่อธิบาย อาจมีการถามเป็นระยะเพื่อให้เกิดความเข้าใจ
ฟัง ๆ ดูก็เหมือนการ Leetcode ของ Programmer เหมือนกันนะ…
Question
ย้ำอีกครั้งว่ามีการแปลงโจทย์แล้ว…
โจทย์ที่ได้มาคือรูปภาพตาราง Excel ตามด้านรูปล่าง
แสดงข้อมูลกระแสเงินในบัญชีของ 2 Accounts คือ Mr.A และ Mr.B ที่อยู่ใน Column
Name
โดยที่ ColumnDate
เป็นวันที่ที่ทำรายการ Transaction ส่วน ColumnAmount
จำนวนเงินที่ฝากเข้า หรือถอนออกไป
ส่วนผลลัพธ์สุดท้ายที่ต้องการคือ ตารางในแบบรูปด้านล่าง แสดงแบบข้อมูลตั้งแต่เดือน September 2017 ถึง May 2018 โดยสิ่งที่ต้องมีในช่องว่างให้ครบทุกช่องคือ ชื่อของเจ้าของบัญชีนั้น ๆ (A และ B) และยอด Outstanding ที่เกิดขึ้นทั้งหมดในเดือนนั้น ๆ (Net amount) โดยที่เดือนที่ไม่มีการทำรายการ ให้ยกยอดมาจากเดือนก่อนหน้า ส่วนเดือนที่มีก่อน Transaction แรกให้มีค่าเป็น 0
หลังจากนี้มีเวลาทั้งหมด 10 นาทีในการอธิบาย และทำให้ Logic ให้ออกมาเป็น Code ซึ่งการ Code ต้อง Share screen ด้วย ถ้าเป็นเมื่อก่อนคงเลือกใช้ SAS เป็นภาษาหลักในการทำ แต่ตอนนี้ต้องเป็น Python เท่านั้น!
Answer
อย่างที่บอกไปว่าโจทย์ที่ให้มาเป็นรูปภาพ ใช่แล้ว… ต้องทำการสร้าง Table ด้วยการ Code มือ โดยที่ต้องระวังไม่ให้ Format ผิดไปจากรูปที่โจทย์ให้มา ตรงนี้เวลาก็หายไปแล้ว 1 นาที
เลือกใช้เป็น Dictionary ให้การเก็บ Raw data เพราะ Dictionary วิ่งเข้ามาในหัวก่อนใครเพื่อน หลังจากที่ได้ Dictionary แล้วก็เปลี่ยนเป็น Dataframe เพื่อเก็บเป็น Data input
เนื่องจาก Output สุดท้ายมี Date column ที่มี Frequency เป็น Monthly basis ดังนั้นจึงเป็นต้องมีการสร้างอีก Table ไว้สำหรับเก็บผลลัพธ์ ถ้าพิมพ์ไปทีละเดือนก็เหมือนกัน (ทำได้นะ ไม่ใช่ว่าทำไม่ได้) แต่คงเสียเวลาไปอีก 1 นาที ดังนั้นจึงเลือกใช้เป็น pandas.date_range()
ที่สามารถกำหนดจุดเริ่มต้น จุดสุดท้าย และความถี่ได้ทันที
โดยกำหนดเป็นวันสุดท้ายของเดือนแรกใน Output เป็นจุดเริ่มต้น และกำหนดเป็นวันสุดท้ายของเดือนสุดท้ายใน Output เป็นจุดสุดท้าย และให้ความถี่เป็น M
ย่อมาจาก Month เมื่อได้เป็น DatetimeIndex มาแล้ว สามารถทำเป็น Dataframe และตั้งชื่อตามที่ Output ต้องการได้เลย
ต่อมาขอจัดการเรื่อง Datetime format ก่อน เพราะใช้เป็น Key mapping และ Key grouping ได้ เนื่องจากใน Table input date ทั้งหมดถูกส่งค่ามาเป็น String ที่มีวันที่อยู่ด้วย แต่สิ่งสุดท้ายที่ต้องการคือ Date ที่มีเฉพาะเดือนและปีเท่านั้น
ดังนั้นสิ่งแรกคือต้องเปลี่ยน String ให้เป็น Datetime format ก่อน สามารถใช้ pandas.to_datetime()
ได้ และจัด Datetime format ให้ด้วย dt.strftime()
สำหรับเดือนและปี แบบ Nov-17
คือเดือนเป็นภาษาอังกฤษตัวย่อ และปีแสดงเฉพาะ 2 ตัวหลัง คั่นกลางด้วยเครื่องหมาย En Dash (-) Syntax คือ ‘%b-%y’
ทำการเปลี่ยนทั้ง 2 Tables
เริ่มทำการ Aggregate table input ด้วยการ Sum Amount ให้อยู่ในระดับ Contract level และ Monthly basis ฟังก์ชั่น .groupby()
ให้ผ่าน Parameter as_index = False
เพราะอยากให้ Return กลับมาเป็น Dataframe เหมือนเดิม จากนั้นทำการ .rename()
columns ให้เป็นชื่อเดียวกับ Output เพื่อทำการ Mapping
การ Mapping รวมทั้งสอง Tables เข้าด้วยกัน อาจทำได้ด้วย Cross join แต่ใน Pandas อาจต้อง Implement ฟังก์ชั่นขึ้นมาเอง ดังนั้นจึงขอใช้เป็นท่าปกติคือ Left join ที่อยู่ใน Iteration statement แทน
สร้างตัวแปรไว้เก็บ Output ไว้เป็น List จากนั้นเริ่มต้น Iteration statement ด้วยการหา Unique value จาก Column contractID
ทำการเลือกเอาเฉพาะ Contract นั้น ๆ มาทำ Operation ในแต่ละ Loop มีการทำ Left join กับ Date table output สิ่งที่เกิดขึ้นหลังจากรวม Tables คือค่า Missing values ที่เกิดจากการที่ไม่มีข้อมูลจาก Table ด้านขวา
ดังนั้นจึงต้องทำการ .fillna()
ทั้งหมด 2 ครั้ง โดยที่ครั้งแรกเป็นการ Repeat contractID
ด้วย Parameter ที่รับมาในแต่ละ Loop ส่วนครั้งที่สองเป็นการ Replace ช่องว่างด้วย 0
จากนั้นสามารถคำนวณ Outstanding ของเดือนนั้น ๆ จากยอดเดือนก่อนหน้าด้วย .cumsum()
ทำการ .append()
ผลเก็บไว้ในแต่ละ Loop
เมื่อก่อน List ที่เก็บ Dataframe แล้ว สามารถใช้ pandas.concat()
เพื่อแปลง List ให้ออกมาเป็น Table ตามที่โจทย์ต้องการ
Conclusion
สรุปสุดท้ายก็ทำได้ทันเวลาใน 10 นาที ทำได้ตามที่คิดและอธิบายเอาไว้ทั้งหมด ถือว่าเป็นโจทย์ที่เจอได้ทั่วไปสำหรับการ Cleansing ข้อมูล ส่วนตัวคิดว่าถ้าไม่ต้องเขียน Code สร้าง Input data เอง เวลาคงเหลือเยอะกว่านี้ สนุกดีเหมือนกัน ได้ลองอะไรใหม่ ๆ
อัพเดต
ทำเป็น Full code ที่เขียนไว้ตอนสัมภาษณ์ เก็บไว้ใน GitHub