[Power BI] หาค่า Tatget ที่แท้จริงจากข้อมูลซ้ำ
โจทย์ดัดแปลงจาก Power BI Thailand Facebook
อ่านบทความก่อนหน้า [DA Series] ทำไมต้องทำความเข้าใจข้อมูลก่อนวิเคราะห์
โจทย์ระบุว่า
นายกาเหว่า เป็น Data Analyst คนใหม่ในบริษัทขายส่งอาหารแห่งหนึ่ง ในวันที่ 5 ของการทำงาน กาเหว่าได้รับไฟล์ยอดขายอาหารจากหัวหน้างาน พร้อมกับข้อความว่า “ช่วยสรุปข้อมูลตัวนี้ส่งผู้บริหารประกอบการประชุมในอีก 30 นาที”
- ยอดขายรวมรายสินค้า
- เป้าหมายรายสินค้า
- รวมยอดขายและเป้าหมายทุกสินค้านายกาเหว่าครุ่นคิดพิจารณาถึงตัวข้อมูล ก่อนที่จะเห็นจุดผิดสังเกต จึงนำไปสอบถามกับพี่ในแผนก พบคำตอบว่า
“อ๋อ ตัวเลขยอดขายเรารวมกันได้เลย เพราะ 1 Row แทนยอดขาย 1 Transaction แต่ตัวเลข Target ที่นี่จะเก็บแบบประหลาดหน่อย คือจริง ๆ แล้ว 1 Product จะมีเลข Target ค่าเดียว อย่างนม (Milk) จริง ๆ Target มันอยู่ที่ 10 หน่วยหน่ะ”
โจทย์นี้ Core หลักของปัญหาคือ
ตัวเลข Target ซ้ำซ้อน
หลักการแก้ปัญหาจึงอยู่ที่การทำให้ตัวเลข Sales / Target ของแต่ละ Product เป็นค่า ๆ เดียวที่ถูกต้อง สำหรับค่า Sales แล้วเราสามารถใช้ Sum เพื่อหาผลรวมได้ทั้งภาพรวมและราย Category แต่กับ Target ที่เป็นค่า Duplicate (ซ้ำกัน) ต้องใช้ Aggregate function แบบอื่น ๆ แต่ทั้งนี้ ถ้าจัดการไม่ถูกต้องอาจมีปัญหา ไม่ในภาพรวม ก็แบบราย Category ได้เช่นกัน
ซึ่งถ้าจะแก้ปัญหานี้ในแต่ละโปรแกรม อาจจะมี Detail ที่แตกต่างกันไป ขอยกตัวอย่างในมุมการแก้ปัญหาด้วย Power BI ซึ่งเป็นที่มาของโจทย์ปัญหานี้
การจัดการข้อมูลใน Power BI จะไม่สามารถ Customize สุดโต่งได่แบบ Excel แต่จะต้องมี Logic ในการแปลงข้อมูลทีละ Step เพื่อให้ได้ผลลัพธ์ตามต้องการ
ทั้งนี้วิธีแก้ปัญหามีหลากหลายมาก ๆ แต่จะขอลองยกตัวอย่าง 3 วิธี
วิธีแรก แก้ปัญหาโดยการแยก Target มาเก็บให้ถูกต้อง
หลักการคือ target ของสินค้าไม่ควรเก็บรวมกับ Transaction ควรแยกให้เป็นระเบียบเรียบร้อยแล้วค่อยนำมาเชื่อมความสัมพันธ์กับภายหลัง จะทำให้ง่ายต่อการใช้งานมากขึ้น
ในกรณีของ Power BI หากจะนำข้อมูลไปใช้ได้ถูกต้องผ่านวิธีนี้แล้ว หากไม่แก้ที่ต้นทาง สามารถทำได้ผ่าน Power Query
ส่วนตัวแล้วนี่เป็นวิธีที่แก้ปัญหาได้ดีที่สุดและแก้ปัญหาในระยะยาวได้หลายอย่าง ซึ่งบอกไม่ได้ว่าเป็นวิธีที่ง่ายหรือยาก เพราะบางที่ก็อาจจะทำได้เลย (ทำนองว่าจริง ๆ แล้วคนทำข้อมูลดันหวังดีจะ Join ข้อมูลให้ ….) หรืออาจจะทำยากมาก (System ถูกออกแบบมาแบบนี้ ไม่มีใครกล้าแก้ไข) ก็เป็นไปได้เหมือนกัน
วิธีที่สอง คำนวน Target แยกตาม Product แต่ละชนิด
แนวคิดตรง ๆ ของวิธีนี้คือ หา Target ของ Product แต่ละตัวก่อน จากนั้นถ้าต้องการยอดรวมค่อยเอามาบวกกันทีหลัง (คิดแยกทีละตัว แล้วค่อยเอามารวมกัน)
target_milk =
CALCULATE(MAX('Main Table'[Target]),'Main Table'[Product] = "Milk")
sum_target =
'Main Table'[target_milk] + 'Main Table'[target_sausage]
วิธีนี้ส่วนตัวคิดว่าค่อนข้างคิดได้ง่าย ไม่ใช้เวลาคิดเยอะ และเหมาะกับข้อมูลจำนวนไม่มาก ก็แค่ใช้ Aggregate Function บางตัวที่ทำให้ข้อมูลหลายบรรทัดกลายเป็นข้อมูลตัวเดียว และได้ค่าที่ต้องการแน่ ๆ (กรณีนี้อาจใช้ Average / Median / Max / Min ก็ได้) ซึ่งถ้า Product มีไม่เยอะมากก็ไม่น่ากังวลเท่าไร แต่ก็นึกสภาพว่าถ้ามี Product ซัก 1000 ตัวแล้วมานั่งบวกเอง ก็คงไม่ต้องทำอะไรแล้วแหละ
Note: Aggregate Function ที่ใช้ เนื่องจากในกรณีนี้ Target เกิดการ Duplicate ขึ้น จึงเลือกใช้ Max / Min / Average / Median ก็ได้
วิธีที่สาม สร้าง Temp Table มาเพื่อเก็บข้อมูล Target แต่ละ Product
วิธีนี้จะคล้ายกับกรณีแรก แต่สามารถเลือกได้ว่าจะสร้างตารางขึ้นมา หรือจะซ่อนไว้ใน Measure ก็ได้ จะเหมาะในกรณีที่จำเป็นต้องใช้ Dax จริง ๆ ด้วยเหตุผลใดๆ
- สร้าง Table ใหม่จากการเขียน DAX ใช้สูตร Summarize เพื่อหาค่าของ Target
Temp Table =
SUMMARIZE('Main Table','Main Table'[Product],
"Target",MAX('Main Table'[Target]))
2. นำ Result จากข้อ 1 ไปใช้ต่อผ่านการ SUM
วิธีนี้จะมีความพิเศษอยู่คือ เราสามารถรวมสูตรทั้งหมดทั้ง 2 ขั้นตอน ให้อยู่ใน DAX เดียว (ผ่านการสร้าง Measure ได้)
target_measure =## ประกาศตัวแปรเพื่อเก็บ Table เอาไว้
VAR agg_table = SUMMARIZE('Main Table','Main Table'[Product],"Target",MAX('Main Table'[Target]))## ใช้สูตร CALCULATE + SUMX ช่วยในการคำนวนผลลัพธ์สุดท้าย
RETURN CALCULATE(SUMX(agg_table,[Target]),ALLEXCEPT('Main Table','Main Table'[Product]))
นอกจากสามวิธีนี้ก็จะมีวิธีอื่น ๆ ที่ใช้ในการจัดการได้อีก แต่ Main Idea ของการแก้ปัญหานี้คือ การพยายามทำให้แต่ละ Product ได้ค่า Target ที่แท้จริงก่อนนำมาใช้คำนวณต่อ
ซึ่งแต่ละวิธีไม่ได้มีผิดหรือมีถูก ขึ้นกับว่า ณ สถานการณ์นั้นควรตัดสินใจใช้วิธีไหน (บางวิธีอาจทำได้ไว แต่ Performance ต่ำ / บางวิธีอาจได้เรื่อง Performance แต่แลกกับการที่ต้องใช้เวลาทำเยอะ / บางวิธีอาจได้ทั้งสอง แต่ติดที่สกิลในการเข้าใจตัวโปรแกรม)
ลองฝึกกันดูนะ :D