[Power BI] หาค่า Tatget ที่แท้จริงจากข้อมูลซ้ำ

Yothin Kittithorn
STEP 2 Analytics
Published in
3 min readMay 3, 2022

โจทย์ดัดแปลงจาก Power BI Thailand Facebook

อ่านบทความก่อนหน้า [DA Series] ทำไมต้องทำความเข้าใจข้อมูลก่อนวิเคราะห์

โจทย์ระบุว่า

ขอบคุณไอเดียโจทย์จากกลุ่ม Power BI Thailand

นายกาเหว่า เป็น 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

ทำการ Copy Table ด้วยการ Reference ลบ column sales ออกก่อนจะทำการ remove duplicate
ทำการ Copy Table ด้วยการ Reference แล้วลบ column target ออก
เชื่อม Relationship ระหว่างกันก่อนนำไปใช้ต่อ

ส่วนตัวแล้วนี่เป็นวิธีที่แก้ปัญหาได้ดีที่สุดและแก้ปัญหาในระยะยาวได้หลายอย่าง ซึ่งบอกไม่ได้ว่าเป็นวิธีที่ง่ายหรือยาก เพราะบางที่ก็อาจจะทำได้เลย (ทำนองว่าจริง ๆ แล้วคนทำข้อมูลดันหวังดีจะ Join ข้อมูลให้ ….) หรืออาจจะทำยากมาก (System ถูกออกแบบมาแบบนี้ ไม่มีใครกล้าแก้ไข) ก็เป็นไปได้เหมือนกัน

วิธีที่สอง คำนวน Target แยกตาม Product แต่ละชนิด

แนวคิดตรง ๆ ของวิธีนี้คือ หา Target ของ Product แต่ละตัวก่อน จากนั้นถ้าต้องการยอดรวมค่อยเอามาบวกกันทีหลัง (คิดแยกทีละตัว แล้วค่อยเอามารวมกัน)

สร้าง Target แยกตาม Product ลงใน Measure
target_milk = 
CALCULATE(MAX('Main Table'[Target]),'Main Table'[Product] = "Milk")
รวมผลลัพธ์ที่ต้องการลงใน Measure เดียวกัน
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 จริง ๆ ด้วยเหตุผลใดๆ

  1. สร้าง Table ใหม่จากการเขียน DAX ใช้สูตร Summarize เพื่อหาค่าของ Target
สูตร Summarize คล้าย ๆ การทำ Group by ข้อมูล
สร้าง Table ใหม่ด้วยสูตร Dax
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

--

--