שני עמודי דשבורד שכל מספר בהם מגיע ממדד שאתם כותבים מאפס, עם חיווי צבע אוטומטי
למצב התוכניות. עובדים על Education_PowerBI_Star.xlsx — סכמת כוכב טהורה: טבלת עובדות אחת,
שבעה מימדים, 28,640 שורות ושבעה קשרים. 29 תרגילים, כל אחד בדף נפרד ועם פתרון מלא. שימו לב: ההורדה
והתרגול הם במחשב בלבד — Power BI Desktop אינו קיים בטלפון.
הנתונים סינתטיים. שמות הערים והמדינות אמיתיים, אבל כל סטודנט, קורס, מרצה,
תוכנית ומספר בקובץ נוצרו באופן מלאכותי עם זרע אקראי קבוע. אין להסיק מהם דבר על מוסד לימודים אמיתי.
לפני שמתחילים — בניית המודל. טענו את שמונה טבלאות המודל
(Relationships הוא גיליון תיעוד — אל תטענו אותו). כבו Autodetect,
בנו את שבעת הקשרים ידנית, וודאו שכולם One to Many בכיוון Single מהמימד אל
Fact_Enrollments. סמנו את Dim_Date כטבלת תאריכים
(Mark as date table על Full_Date).
המלכודת הגדולה של הקובץ הזה — שורות מבוטלות שנושאות הכנסה שלא מומשה.
בטבלת העובדות שתי עמודות כסף שנראות תאומות: Tuition_Billed_USD ו-Tuition_Collected_USD.
לכל שורה שהסטטוס שלה שייך ל-Status_Group = "Lost" — כלומר Withdrawn ו-Cancelled —
יש חיוב חיובי אבל גבייה אפס. מי שיסכם את עמודת החיוב יקבל
61,236,519.19 במקום 50,294,056.87 — ניפוח של
10,942,462.32 דולר, 17.9% מסך החיוב, שמעולם לא נכנס לקופה.
בכל המטלה מסכמים Tuition_Collected_USD. חיוב הוא כוונה, גבייה היא הכנסה.
מילון סוגריים.Table[Column] = עמודה · [מדד] =
סוגריים מרובעים בלי שם טבלה. לכל מדד: קליק ימני על Fact_Enrollments בחלונית
Data ← New measure ← הנוסחה ← Enter. השם חייב להיות בדיוק כפי שמופיע בתרגיל.
מבנה המטלה
חלק 1
14 מדדי DAX
אחד-עשר מדדי בסיס — שני SUM, שני DISTINCTCOUNT, DIVIDE, שני CALCULATE, ALL, IF ושני SWITCH — ושלוש פונקציות חלון: RANK, INDEX ו-WINDOW.
חלק 2
שני עמודי דשבורד
ארבעה קארדים על מגש, גרף עמודות, גרף קו מוחלק, סלייסר, טבלת תוכניות, Top N, Matrix וגרף משולב.
חלק 3
עיצוב מותנה וחשיבה
אותה חלוקה לשלוש שכבות בשתי טכניקות, ואז שני תרגילי חשיבה: פירוק המלכודת ותובנת רווחיות הערוצים.
כל המספרים אומתו ב-pandas מול הקובץ
1.1 · Total Tuition Collected — מדד הבסיס
צרו מדד בשם Total Tuition Collected שמסכם את Fact_Enrollments[Tuition_Collected_USD]. עצבו עם מפריד אלפים ושתי ספרות אחרי הנקודה.
Total Tuition Collected =
SUM (
Fact_Enrollments[Tuition_Collected_USD]
)
יצירהקליק ימני על Fact_Enrollments ← New measure
עיצובMeasure tools ← Format: Currency ← 2 ספרות
בדיקהגררו לקארד ריק כדי לוודא שהמספר מופיע
למה דווקא העמודה הזאת: בטבלה יושבת גם Tuition_Billed_USD, והיא מחזירה 61,236,519.19. ההפרש של 10,942,462.32 דולר הוא בדיוק החיוב של השורות שבוטלו — כסף שנרשם כחוב ומעולם לא נגבה. תרגיל 4.1 מפרק את זה לגמרי.
תוצאה: 50,294,056.87 דולר — מספר העוגן של כל המטלה.
1.2 · Students Enrolled — כמה סטודנטים באמת
צרו מדד בשם Students Enrolled שסופר סטודנטים ייחודיים על בסיס Fact_Enrollments[Student_ID].
Students Enrolled =
DISTINCTCOUNT (
Fact_Enrollments[Student_ID]
)
למה לא COUNT:COUNT(Student_ID) היה מחזיר 28,640 — הוא סופר שורות שיש בהן ערך, לא ערכים ייחודיים. כל סטודנט נרשם ל-6.8 קורסים בממוצע, ולכן 28,640 ÷ 4,198 ≈ 6.82.
תוצאה: 4,198 סטודנטים.
1.3 · Tuition per Student — עקרון הלגו
צרו מדד בשם Tuition per Student — אך ורק משני המדדים הקיימים, בלי סימן החלוקה / ובלי AVERAGE. עצבו לשתי ספרות.
ממוצע של מה:AVERAGE(Tuition_Collected_USD) היה מחזיר את הממוצע לשורת רישום (1,756.08), לא לסטודנט. כשהמדד בנוי משני מדדים קיימים המכנה מוגדר במפורש ואתם יודעים בדיוק מה חילקתם. DIVIDE עדיף על / כי הוא מחזיר ריק במקום שגיאה כשהמכנה אפס.
המדד מתגלגל אוטומטית לכל הקשר: גררו אותו לטבלת התוכניות והוא יחזיר את שכר הלימוד לסטודנט בכל תוכנית בנפרד — בלי לכתוב שורה נוספת.
תוצאה: 11,980.48 דולר לסטודנט.
1.4 · Total Credit Hours — SUM על עמודה אחרת
צרו מדד בשם Total Credit Hours שמסכם את Fact_Enrollments[Credit_Hours]. המדד משרת את הגרף המשולב בתרגיל 2.10.
Total Credit Hours =
SUM ( Fact_Enrollments[Credit_Hours] )
העמודה הזאת נגזרת באמת:Credit_Hours בטבלת העובדות שווה תמיד ל-Credit_Value של הקורס ב-Dim_Course. אפשר היה לוותר עליה ולסכם דרך הקשר — היא יושבת בעובדות כדי שתוכלו לסכם בלי לגעת במימד.
תוצאה: 481,915 שעות זכות.
1.5 · Courses Delivered — DISTINCTCOUNT שני
צרו מדד בשם Courses Delivered שסופר קורסים ייחודיים על בסיס Fact_Enrollments[Course_ID].
שימו לב להבדל מ-1.2: אותה פונקציה, עמודה אחרת, ותוצאה בסדר גודל אחר לגמרי. DISTINCTCOUNT תמיד סופר את הערכים הייחודיים בהקשר הנוכחי — גררו את המדד לטבלה לפי Dim_Campus[Campus_Name] והוא יראה כמה קורסים שונים רצו בכל קמפוס, לא 180 בכל שורה.
תוצאה: 180 קורסים — כל הקטלוג פעיל.
1.6 · Online Tuition — CALCULATE ראשון
צרו מדד בשם Online Tuition שמחזיר את שכר הלימוד שנגבה מקורסים מקוונים בלבד. השתמשו ב-CALCULATE עם [Total Tuition Collected] כביטוי ותנאי על Dim_Course[Delivery_Mode].
מה קורה כאן: CALCULATE מוסיפה את התנאי לבועת הסינון ורק אז מריצה את [Total Tuition Collected]. הפילטר יושב על עמודת טקסט בטבלת המימד, זורם דרך הקשר אל 28,640 שורות העובדה — בלי שום JOIN.
מה KEEPFILTERS משנה: תנאי רגיל בתוך CALCULATE דורס כל פילטר קיים על אותה עמודה. KEEPFILTERS מחליף את הדריסה בהצטלבות. הבדיקה: שימו סלייסר על Status_Group ובחרו Open בלבד. בלי KEEPFILTERS המדד ימשיך להחזיר 35,487,304.63 ויתעלם מהסלייסר; עם KEEPFILTERS הוא יחזיר ריק — כי החיתוך של Open עם Realized הוא קבוצה ריקה. זו התשובה הנכונה.
למה זה חשוב כאן במיוחד: הקבוצה השלישית, Lost, מחזיקה גבייה אפס אבל חיוב של 10,410,534.43 דולר. הפילוח לפי סטטוס הוא בדיוק המקום שבו המלכודת של הקובץ נחשפת בעין.
תוצאה: 35,487,304.63 דולר. לפי קבוצת סטטוס: Realized 35,487,304.63 · Open 14,806,752.24 · Lost 0.00
1.8 · % of All Programs — ALL משחררת את הפילטר
צרו מדד בשם % of All Programs שמחזיר את חלקה של כל תוכנית מתוך כל שורות Dim_Program — גם כשהוויזואל מסונן לתוכנית אחת. עצבו כאחוז בשתי ספרות.
% of All Programs =
DIVIDE (
[Total Tuition Collected],
CALCULATE (
[Total Tuition Collected],
ALL ( Dim_Program )
)
)
איפה ALL עובדת: המונה מחושב בהקשר השורה — שכר הלימוד של התוכנית הנוכחית. המכנה עטוף ב-CALCULATE עם ALL ( Dim_Program ), שמוחק את הפילטר על כל העמודות של המימד ומחזיר תמיד את סך 24 התוכניות. אילו כתבתם ALL ( Dim_Program[Program_Name] ) הייתם משחררים רק עמודה אחת — פילטר על Faculty_Name היה ממשיך לחתוך את המכנה.
מבחן השפיות: גררו את המדד לטבלת התוכניות. עמודת האחוזים חייבת להסתכם בדיוק ל-100.00%. אם היא לא — סימן שהמכנה שלכם מסונן.
תוצאה: Public Health = 5.20% (2,613,332.23) · Digital Marketing = 2.88% (1,449,455.63) · סך העמודה = 100.00%
1.9 · Program Status — IF מול יעד קבוע
צרו מדד בשם Program Status שמחזיר "Above Target" כששכר הלימוד של התוכנית מגיע ליעד השנתי של 2,100,000 דולר, ו-"Below Target" אחרת.
Program Status =
IF (
[Total Tuition Collected] >= 2100000,
"Above Target",
"Below Target"
)
יעד קבוע, לא ממוצע: היעד כאן הוא מספר מוסכם מראש שנקבע בתקציב, לא ערך שמחושב מהנתונים. היתרון: התוצאה יציבה ולא זזה כשמסננים את הוויזואל. החיסרון: אם תשנו את היעד תצטרכו לערוך את הנוסחה — בתרגיל 2.6 תראו איך פרמטר What-if פותר את זה.
מדד טקסט אינו מדד מספרי: אי אפשר לדרג אותו, לסכם אותו או להזין ממנו גרף. מקומו בטבלה ובקארד בלבד.
תוצאה: 14 תוכניות מעל היעד · 10 מתחתיו. התוכנית הראשונה מתחת ליעד: Social Work (1,995,665).
1.10 · Program Tier — SWITCH לשלוש שכבות
צרו מדד בשם Program Tier שמחלק את התוכניות לשלוש שכבות: "Top" מ-2,400,000 ומעלה, "Mid" מ-1,900,000 ומעלה, והשאר "Low". השתמשו ב-SWITCH(TRUE()).
למה SWITCH(TRUE()) ולא IF מקונן:TRUE() כארגומנט ראשון הופך את SWITCH לרשימת תנאים שנבדקים מלמעלה למטה, והראשון שמתקיים מנצח. הסדר קריטי: אילו שורת ה-Mid הייתה ראשונה, כל התוכניות מעל 2.4 מיליון היו מקבלות Mid כי הן עוברות גם את הסף הנמוך.
הארגומנט האחרון בלי תנאי הוא ברירת המחדל. בלעדיו תוכנית שלא עונה לאף תנאי תחזיר ריק, והוויזואל יראה שורה ריקה במקום תווית.
תוצאה: 6 תוכניות Top · 13 Mid · 5 Low. סך הכל 24 — כל תוכנית קיבלה בדיוק תווית אחת.
1.11 · Tier Color — SWITCH שמחזיר צבע
צרו מדד בשם Tier Color שמתרגם את [Program Tier] לקוד הקסה: Top → #132449, Mid → #F5C518, וברירת מחדל #A9B4CC. זה SWITCH על ערך, לא על TRUE().
שתי צורות של אותה פונקציה: בתרגיל הקודם SWITCH קיבלה TRUE() והשוותה תנאים. כאן היא מקבלת ביטוי ומשווה אותו לערכים. הצורה הזאת קצרה יותר וקריאה יותר כשיש רשימת ערכים סגורה.
המדד הזה לא מיועד לעין. הוא מזין את חלונית העיצוב המותנה בתרגיל 3.2. אם תגררו אותו לטבלה תראו מחרוזות הקסה — זה תקין.
שלושת החלקים:DENSE קובע שאחרי תיקו הדירוג הבא הוא הבא בתור ולא קופץ · ALLSELECTED מגדיר את החלון — כל התוכניות שהסלייסר משאיר גלויות · ORDERBY קובע לפי מה ממיינים. בלי ORDERBY, RANK תמיין לפי סדר העמודה ותחזיר דירוג אלפביתי.
למה ALLSELECTED ולא ALL: עם ALL הדירוג היה מתעלם מהסלייסרים ותמיד נע בין 1 ל-24. עם ALLSELECTED סינון לפקולטה אחת מדרג מחדש בתוך הפקולטה — מספר 1 יהיה המוביל בבחירה הנוכחית.
תוצאה: Public Health = 1 · Digital Marketing = 24. 24 תוכניות, 24 דירוגים — אין תיקו בקובץ הזה, ולכן DENSE ו-SKIP מחזירים כאן אותו דבר. ההבדל יתגלה ברגע שתסננו לפקולטה עם ערכים זהים.
1.13 · Leader Tuition — INDEX מחזיר את המוביל
צרו מדד בשם Leader Tuition שמחזיר בכל שורה את שכר הלימוד של התוכנית המובילה — אותו מספר בכל שורות הטבלה. השתמשו ב-INDEX עם ORDERBY.
INDEX מחזירה שורה, לא מספר. היא בוררת את השורה במיקום שביקשתם בתוך החלון — 1 = הראשונה אחרי המיון. כדי להפוך שורה למספר עוטפים ב-CALCULATE, שמשתמש בשורה שנבחרה כפילטר ומריץ עליה את המדד. INDEX ( -1, ... ) היה מחזיר את האחרונה.
מה עושים עם זה: מדד עזר טבעי הוא DIVIDE ( [Total Tuition Collected], [Leader Tuition] ) — אחוז מהמוביל. אצל Public Health הוא יחזיר 100%, ואצל Digital Marketing 55.46%.
תוצאה: 2,613,332.23 — אותו מספר בכל 24 השורות. אם הוא משתנה משורה לשורה, החלון שלכם לא ALLSELECTED.
1.14 · Tuition Moving Avg 3M — WINDOW
צרו מדד בשם Tuition Moving Avg 3M שמחזיר ממוצע נע של שלושה חודשים — החודש הנוכחי ושני החודשים שלפניו. השתמשו ב-WINDOW עם REL.
ארבעת המספרים הראשונים:-2, REL = גבול תחתון, שתי שורות אחורה יחסית לשורה הנוכחית · 0, REL = גבול עליון, השורה הנוכחית עצמה. REL = יחסי לשורה הנוכחית; ABS היה סופר מתחילת החלון.
למה AVERAGEX ולא AVERAGE:WINDOW מחזירה טבלה של עד שלוש שורות. AVERAGEX רצה עליה שורה-שורה, מחשבת את המדד בכל אחת, ורק אז ממצעת. החלפה ל-SUMX תיתן סכום נגרר במקום ממוצע נע.
שתי השורות הראשונות שונות: בינואר 2023 יש שורה אחת בחלון ובפברואר שתיים, ולכן הממוצע שם הוא של פחות משלושה חודשים. זו התנהגות נכונה, לא באג — מי שרוצה ריק בשורות האלה חייב לספור אותן במפורש.
הציגו לפי Dim_Date[Year_Month] (36 חודשים). תוצאה: 2023-03 = 2,059,545.77 · 2025-12 = 1,593,617.98 (החודש עצמו: 817,666.91 — הממוצע הנע מרכך את צניחת הסמסטר).
2.1 · רקע, כותרת ומגש KPI — הפריסה
בנו את עמוד 1 של הדשבורד: רקע כהה, כותרת, ומגש שיארח את ארבעת הקארדים. עדיין בלי ויזואלים — רק השלד.
כלל אצבע: תמונה בדשבורד היא רקע, לא תוכן. אם היא מושכת את העין לפני המספרים — הורידו את השקיפות שלה עוד. יחס ניגודיות של 4.5:1 בין טקסט לרקע הוא המינימום.
גודל הקובץ נכנס ל-PBIX: תמונה של 4MB מנפחת את הקובץ ומאיטה את הפתיחה. כווצו ל-200KB לפני ההוספה.
בסוף התרגיל יש לוגו קטן בפינה ותמונת רקע מעומעמת מאחורי הכותרת, והכותרת עדיין נקראת בבירור.
2.3 · ארבעת הקארדים — רק מדדים
הניחו על המגש ארבעה קארדים: [Total Tuition Collected], [Students Enrolled], [Courses Delivered] ו-[Tuition per Student]. אסור לגרור עמודה גולמית לאף אחד מהם.
הוספהVisualizations ← Card ← גררו את המדד ל-Fields
כותרתFormat ← Callout value ← 32pt · לבן
תוויתCategory label ← 12pt · #A9B4CC
יישורבחרו את ארבעתם ← Format ← Align top ← Distribute horizontally
רקעכבו את הרקע של כל קארד — המגש מתרגיל 2.1 הוא הרקע
למה לא עמודה גולמית: קארד שמקבל עמודה מציג First או Count לפי הסוג, וברגע שמישהו מסנן הוא עלול להחזיר מספר שאין לו משמעות. מדד מוגדר במפורש ומתגלגל נכון בכל הקשר.
ארבעת הקארדים מציגים: 50,294,056.87 · 4,198 · 180 · 11,980.48.
2.4 · גרף עמודות — שכר לימוד לפי תוכנית
בנו Clustered bar chart עם Dim_Program[Program_Name] על הציר ו-[Total Tuition Collected] בערכים, ממוין מהגבוה לנמוך.
ויזואלClustered bar chart
ציר YDim_Program[Program_Name]
ערכים[Total Tuition Collected]
מיוןשלוש נקודות ← Sort axis ← Total Tuition Collected ← Descending
תוויותFormat ← Data labels ← On ← Display units: Millions
צירכבו את כותרת הציר — שם הוויזואל כבר אומר מה זה
גררו את השם מהמימד, לא מהעובדות. ב-Fact_Enrollments יש רק Program_ID. ויזואל שבנוי על המפתח יראה קודים במקום שמות, ולא יגיב לסלייסר על Faculty_Name.
Bar ולא Column: 24 שמות תוכניות ארוכים על ציר אופקי נחתכים או מסתובבים באלכסון. עמודות אופקיות נותנות לשם שורה מלאה.
התוכנית העליונה: Public Health — 2,613,332.23. התחתונה: Digital Marketing — 1,449,455.63.
2.5 · גרף קו מוחלק — המגמה החודשית
בנו Line chart עם Dim_Date[Year_Month] על הציר, [Total Tuition Collected] ו-[Tuition Moving Avg 3M] כשני קווים. הפעילו החלקה על הקו הראשי.
ויזואלLine chart
ציר XDim_Date[Year_Month] — ודאו שהוא Categorical ולא Date hierarchy
צבעיםהקו הראשי #F5C518 ברוחב 3 · הממוצע הנע #A9B4CC ברוחב 2 מקווקו
מיוןSort axis ← Year_Month ← Ascending
עונתיות שתראו מיד: ספטמבר-אוקטובר וינואר-פברואר מזנקים, יולי-אוגוסט צונחים. זה לוח השנה האקדמי, לא רעש. סך הכל: Spring 24,763,017 · Fall 21,537,164 · Summer 3,993,875.
ההחלקה משקרת קצת. Smooth line מצייר עקומה בין נקודות ולכן ממציא ערכי ביניים שלא קיימים. הוא יפה למגמה ומסוכן לקריאה מדויקת — לכן הממוצע הנע נשאר קו ישר.
הקו המוחלק מתחיל ב-2,568,361.43 (2023-01) ומסתיים ב-817,666.91 (2025-12). הממוצע הנע בנקודה האחרונה: 1,593,617.98.
2.6 · עמוד 2 וסלייסר שנת הלימודים
צרו עמוד שני בשם Detail, העתיקו אליו את המגש והכותרת, והוסיפו סלייסר על Dim_Date[Academic_Year] שמסנכרן את שני העמודים.
סנכרוןView ← Sync slicers ← סמנו Sync ו-Visible בשני העמודים
ברירת מחדלהשאירו את הסלייסר ריק — ריק פירושו הכול
What-ifModeling ← New parameter ← Numeric range ← Target · 1,000,000 עד 3,000,000 · צעד 100,000
הפרמטר משחרר את היעד מ-1.9: החליפו בנוסחת Program Status את המספר 2100000 ב-[Target Value], והמשתמש יזיז את הסליידר ויראה כמה תוכניות עוברות את היעד בזמן אמת.
שימו לב לסנכרון:Sync בלי Visible מסנן את העמוד השני בלי להראות שם את הסלייסר — מצב מבלבל שגורם למשתמשים לדווח על "מספרים שגויים".
בחירת AY2024 מורידה את הקארד הראשון ל-16,814,633.91. שלוש השנים: AY2023 16,802,711.36 · AY2024 16,814,633.91 · AY2025 16,676,711.60 — סכומן הוא בדיוק מספר העוגן.
2.7 · טבלת התוכניות — כאן חיים IF ו-SWITCH
בעמוד Detail בנו Table עם Dim_Program[Program_Name], Dim_Program[Faculty_Name] וחמשת המדדים: [Total Tuition Collected], [% of All Programs], [Program Rank], [Program Status] ו-[Program Tier].
ויזואלTable — לא Matrix, אין כאן היררכיה
עמודותשתי עמודות מימד ואז חמשת המדדים לפי הסדר
מיוןלחצו על כותרת Program Rank ← עולה
סכוםFormat ← Totals ← On — ודאו ש-% מסתכם ל-100.00%
רוחבגררו את גבולות העמודות ידנית; אל תסמכו על ההתאמה האוטומטית
מבחן האדיטיביות: שורת הסיכום של [Total Tuition Collected] חייבת להראות 50,294,056.87 ושל [% of All Programs] בדיוק 100.00%. [Program Rank] בשורת הסיכום יראה 1 — זה תקין, כי בהקשר הסיכום אין תוכנית לדרג.
מה לא לשים כאן: את Revenue_Per_Credit_Hour מטבלת העובדות. הוא יחס ברמת שורה, ו-Power BI יסכם אותו בברירת מחדל ויציג מספר חסר משמעות לגמרי. יחס מחשבים תמיד כמדד DIVIDE ברמת הסיכום.
השורה הראשונה: Public Health · Faculty of Health · 2,613,332.23 · 5.20% · 1 · Above Target · Top.
2.8 · Top 10 קורסים — Bar עם פילטר Top N
בנו גרף עמודות של עשרת הקורסים המובילים לפי [Total Tuition Collected], באמצעות פילטר Top N ולא מיון ידני.
ויזואלClustered bar chart ← ציר: Dim_Course[Course_Name]
ערכים[Total Tuition Collected]
פילטרFilters ← Course_Name ← Filter type: Top N
הגדרהShow items: Top ← 10 ← By value: [Total Tuition Collected]
החלהApply filter — בלי הלחיצה הזאת שום דבר לא קורה
Top N הוא פילטר דינמי. ברגע שיבחרו AY2024 בסלייסר, הרשימה תחושב מחדש ועשרת המובילים עשויים להתחלף. מיון ידני עם "הצג 10 ראשונים" לא היה עושה את זה.
שימו לב לאשליית הריכוזיות: עשרת הקורסים המובילים מחזיקים יחד רק 11.47% מהגבייה. בקטלוג של 180 קורסים אין זנב ארוך אמיתי — התפלגות שטוחה למדי, וזו תובנה בפני עצמה.
הקורס המוביל: Finance Practice — 634,376.62. סך עשרת המובילים: 11.47% מ-50,294,056.87.
2.9 · Matrix — פקולטה × אופן הוראה
בנו Matrix עם Dim_Program[Faculty_Name] בשורות, Dim_Course[Delivery_Mode] בעמודות ו-[Total Tuition Collected] בערכים.
ויזואלMatrix
שורותDim_Program[Faculty_Name]
עמודותDim_Course[Delivery_Mode]
ערכים[Total Tuition Collected]
סכומיםFormat ← Row subtotals ו-Column subtotals ← On
יחידותFormat ← Display units: Millions ← ספרה אחת
שני מימדים שונים בצלעות אחת מטריצה. זה בדיוק מה שסכמת כוכב נותנת: Dim_Program ו-Dim_Course לא מכירות זו את זו, אבל שתיהן מסננות את אותה טבלת עובדות, ולכן החיתוך ביניהן מחושב לבד.
מבחן הפינה הימנית התחתונה: הסכום הכולל של המטריצה חייב להיות 50,294,056.87. אם הוא גדול יותר — יש לכם קשר דו-כיווני או נתיב סינון כפול במודל.
סכומי העמודות: Campus 24,521,003.34 · Online 14,331,147.98 · Hybrid 11,441,905.55 · סך הכל 50,294,056.87.
2.10 · גרף משולב — כסף מול שעות זכות
בנו Line and clustered column chart: עמודות = [Total Tuition Collected], קו = [Total Credit Hours], ציר = Dim_Course[Subject_Area].
ויזואלLine and clustered column chart
צירDim_Course[Subject_Area]
עמודות[Total Tuition Collected]
קו[Total Credit Hours] ← באזור Line y-axis
ציר שניFormat ← Y-axis (secondary) ← On — בלעדיו הקו יימעך
מיוןלפי [Total Tuition Collected] יורד
שני צירים = שתי יחידות מידה. דולרים ושעות זכות אינם אותו סדר גודל. בלי ציר משני הקו ייצמד לקרקע ולא תראו בו כלום.
מה לחפש: תחום שבו העמודה גבוהה והקו נמוך גובה הרבה כסף על מעט שעות — כלומר תעריף לשעת זכות גבוה. תחום הפוך הוא תחום עתיר הוראה. זה מקדים את תובנת הסיום בתרגיל 4.2.
סך הקו על כל התחומים: 481,915 שעות זכות. סך העמודות: 50,294,056.87 דולר.
2.11 · ניווט ופוליש — סגירת הדשבורד
חברו את שני העמודים בכפתורי ניווט, ועברו על רשימת הפוליש הסופית.
סגנוןצבע לא-פעיל #1B3060 · פעיל #F5C518 · טקסט לבן
כותרותכל ויזואל מקבל כותרת בעברית ברורה ב-Format ← Title
TooltipFormat ← Tooltips ← On לכל גרף
סדר טאבView ← Selection ← Tab order — כותרת, קארדים, גרפים
Alt textתיאור קצר לכל ויזואל ב-General ← Alt text
רשימת הפוליש הסופית: אין ויזואל עם כותרת ברירת מחדל (Total Tuition Collected by Program_Name) · אין פס גלילה בתוך ויזואל בגודל הסטנדרטי · כל המספרים באותו מספר ספרות · אין שני גוונים של אותו כחול · אין ויזואל שנחתך בקצה הקנבס.
בדיקת סגירה: לחצו על עמודה בגרף התוכניות וודאו שכל שאר הוויזואלים מגיבים. אם אחד מהם לא זז — הוא בנוי על עמודה מטבלת העובדות במקום מהמימד.
בסוף התרגיל: שני עמודים מקושרים, כל ויזואל עם כותרת, וכל מספר בדשבורד מגיע ממדד שכתבתם.
3.1 · Rules — עיצוב מותנה בתוך ויזואל אחד
צבעו את גרף העמודות מתרגיל 2.4 בשלוש שכבות באמצעות Rules — בלי להיעזר במדד הצבע.
פתיחהבחרו את הגרף ← Format ← Bars ← Colors ← fx
סוגFormat style: Rules
שדהBased on field: [Total Tuition Collected] ← Summarization: Sum
כלל 1If value >= 2400000 and < 999999999 ← #132449
כלל 2If value >= 1900000 and < 2400000 ← #F5C518
כלל 3If value >= 0 and < 1900000 ← #A9B4CC
הסדר בחלונית הוא הסדר שנבדק. Power BI עוצר בכלל הראשון שמתקיים, בדיוק כמו SWITCH(TRUE()). כלל שמכסה טווח רחב מדי בראש הרשימה יבלע את כל השאר.
המגבלה של Rules: הן חיות בתוך הוויזואל הזה בלבד. אם תרצו את אותה חלוקה בטבלה, ב-Matrix ובקארד — תצטרכו להגדיר אותה שלוש פעמים ולשמור על סנכרון ידני. זו בדיוק הבעיה שתרגיל 3.2 פותר.
שש עמודות כחולות כהות · שלוש-עשרה צהובות · חמש אפורות. אותה חלוקה בדיוק כמו [Program Tier] בתרגיל 1.10.
3.2 · Field value — המדד SWITCH מזין את הצבע
צבעו את טבלת התוכניות מתרגיל 2.7 באותה חלוקה, הפעם באמצעות Field value והמדד [Tier Color] מתרגיל 1.11.
פתיחהבחרו את הטבלה ← Format ← Cell elements
שדהApply to: [Total Tuition Collected]
סוגBackground color ← On ← fx
מצבFormat style: Field value
מדדWhat field should we base this on: [Tier Color]
חזרהחזרו על אותו הליך על גרף העמודות — אותו מדד, אפס הגדרות חדשות
זה ההבדל המהותי: ב-Rules הלוגיקה גרה בוויזואל; ב-Field value היא גרה במודל. שינוי סף אחד במדד Program Tier מעדכן בבת אחת את כל הוויזואלים שמשתמשים ב-Tier Color. זו הסיבה שכתבנו שני מדדי SWITCH נפרדים — אחד ללוגיקה ואחד לתרגום שלה לצבע.
מה חייב לחזור מהמדד: מחרוזת הקסה תקינה בת שבעה תווים או שם צבע מוכר. מדד שמחזיר ריק ייתן תא בלי צבע — לא שגיאה, פשוט חוסר.
הטבלה וגרף העמודות מציגים כעת בדיוק את אותה חלוקה, משני מקורות שונים לחלוטין — וזו הבדיקה שהמדד נכון.
4.1 · המלכודת — הסבירו למה התשובה הנאיבית שגויה
בתרגיל הזה לא כותבים מדד. עמית בקורס בנה מדד Total Revenue = SUM ( Fact_Enrollments[Tuition_Billed_USD] ), קיבל 61,236,519.19 דולר, ומציג את המספר להנהלה כ"הכנסות המוסד". כתבו בשלוש-ארבע שורות מה בדיוק שגוי כאן, כמה הפער, ואיזו בדיקה במודל הייתה חושפת אותו בתוך דקה.
התשובה המלאה — מה שגוי: העמודה Tuition_Billed_USD מתעדת חיוב, לא גבייה. שתי קבוצות סטטוס מתוך שלוש — Withdrawn ו-Cancelled, שיחד הן Status_Group = "Lost" — נושאות חיוב חיובי וגבייה אפס. הרישום בוטל, הכסף מעולם לא נכנס, אבל שורת החיוב נשארה בטבלת העובדות. מדד שמסכם חיוב סופר את הכסף הזה כאילו התקבל.
כמה הפער:61,236,519.19 פחות 50,294,056.87 = 10,942,462.32 דולר — 17.9% מסך החיוב, וכולו מיוחס לקבוצה אחת. הפירוק לפי קבוצת סטטוס: Realized 35,487,304.63 חויב ונגבה במלואו · Open 15,338,680.13 חויב מול 14,806,752.24 שנגבה · Lost 10,410,534.43 חויב מול 0.00 שנגבה.
הבדיקה שחושפת את זה בדקה: בנו Matrix עם Dim_Status[Status_Group] בשורות ושני מדדים בערכים — סכום החיוב מול סכום הגבייה. שורה שבה עמודה אחת גדולה מאפס והשנייה אפס היא דגל אדום ואי אפשר לפספס אותה. הכלל הכללי: כל אימת ששתי עמודות כסף בטבלת עובדות נראות תאומות, פלחו את שתיהן לפי מימד הסטטוס לפני שאתם בוחרים אחת.
מה כן היה לגיטימי: להציג את שני המספרים זה לצד זה ולקרוא להם בשמם — "חויב" ו"נגבה" — ולהוסיף מדד שלישי לפער. זה הופך את המלכודת לתובנה תפעולית על אחוז הנשירה.
הפער: 10,942,462.32 דולר · 17.9% מהחיוב · כולו מקבוצת Lost.
4.2 · תובנת הסיום — איזה ערוץ הוראה באמת רווחי
בנו טבלה עם Dim_Course[Delivery_Mode] בשורות, ושלושה מדדים: [Total Tuition Collected], Net Margin = SUM ( Fact_Enrollments[Net_Margin_USD] ) ו-Margin % = DIVIDE ( [Net Margin], [Total Tuition Collected] ). ואז ענו: איזה ערוץ הוראה המוסד צריך להרחיב, ולמה זה לא הערוץ הגדול ביותר?
הטבלה שתקבלו:
רווחיות לפי אופן הוראה
Delivery Mode
שכר לימוד שנגבה
רווח נקי
שיעור רווח
Campus
24,521,003.34
2,150,521.44
8.77%
Online
14,331,147.98
4,509,735.15
31.47%
Hybrid
11,441,905.55
2,392,673.81
20.91%
סך הכל
50,294,056.87
9,052,930.40
18.00%
התובנה: Campus הוא הערוץ הגדול — 48.8% מהגבייה — אבל הוא מייצר רק 23.8% מהרווח, בשיעור של 8.77%. Online גובה 41% פחות ממנו ומייצר יותר רווח בערכים מוחלטים: 4,509,735 מול 2,150,521. הערוץ שנראה הכי חשוב בגרף העמודות הוא הפחות רווחי בפועל.
למה זה קורה — הסבר מהנתונים, לא מהניחוש: שני כוחות פועלים באותו כיוון. ראשית, Contact_Minutes לשעת זכות בקורס מקוון עומד על 72% מזה של קורס בקמפוס. שנית, עלות דקת הוראה בקמפוס גבוהה ב-12% מזו של דקה מקוונת — כיתות, טכנאים, נסיעות. פחות דקות שכל אחת מהן זולה יותר. מנגד, קורס מקוון גובה תעריף נמוך ב-14% לשעת זכות — וזה עדיין לא מספיק כדי לסגור את הפער.
מה זה אומר להנהלה: החלטה על הרחבת Online אינה החלטה על גודל אלא על תמהיל. אבל לפני שממליצים — שימו לב למה שהנתונים לא אומרים: אין כאן מדידה של איכות למידה, שביעות רצון או שיעור השלמה לפי ערוץ. ניתוח רווחיות הוא צד אחד של ההחלטה בלבד, וכדאי לומר את זה במפורש בשקף.
הרחבה למי שרוצה עוד: הוסיפו לטבלה עמודת Dim_Program[Program_Level] וראו אם הפער בין הערוצים נשמר בכל רמת תוכנית או שהוא מתרכז ברמה אחת. זו הבדיקה שמפרידה בין תובנה אמיתית לבין פרדוקס סימפסון.
Online — 31.47% שיעור רווח, ורווח מוחלט גבוה ב-110% מזה של Campus, למרות שהוא גובה 41% פחות.
מטלת סיכום · מוסד לימודים
סיכום — כל התוצאות במקום אחד
טבלת אימות מרוכזת לכל 14 המדדים ולכל מספר עוגן במטלה. פתחו אותה רק אחרי שסיימתם — היא נותנת את כל התשובות.
כל התוצאות המאומתות במקום אחד
מדד / רכיב
תוצאה מאומתת
1.1 Total Tuition Collected
50,294,056.87
1.2 Students Enrolled
4,198 (COUNT היה מחזיר 28,640)
1.3 Tuition per Student
11,980.48
1.4 Total Credit Hours
481,915
1.5 Courses Delivered
180
1.6 Online Tuition
14,331,147.98 (28.49%)
1.7 Realized Tuition
35,487,304.63 · Open 14,806,752.24 · Lost 0.00
1.8 % of All Programs
מוביל 5.20% · סך העמודה 100.00%
1.9 Program Status
14 מעל היעד · 10 מתחת · יעד 2,100,000
1.10 Program Tier
6 Top · 13 Mid · 5 Low
1.11 Tier Color
6 × #132449 · 13 × #F5C518 · 5 × #A9B4CC
1.12 Program Rank
Public Health = 1 · Digital Marketing = 24
1.13 Leader Tuition
2,613,332.23 בכל 24 השורות
1.14 Tuition Moving Avg 3M
2023-03 = 2,059,545.77 · 2025-12 = 1,593,617.98
סך החיוב (המלכודת)
61,236,519.19 — פער של 10,942,462.32
Net Margin
9,052,930.40 (18.00%)
התוכנית המובילה
Public Health — 2,613,332.23
הקורס המוביל
Finance Practice — 634,376.62
הקמפוס המוביל
Distance Learning Hub — 5,832,708.10
שנת השיא
AY2024 — 16,814,633.91
הערוץ הרווחי ביותר
Online — 31.47% שיעור רווח
כל התוצאות אומתו ב-pandas מול Education_PowerBI_Star.xlsx (28,640 שורות עובדה), וכל שבעת הקשרים נבדקו תכנותית — 0 מפתחות יתומים, 0 מפתחות ריקים, 0 תלויות מעגליות ו-0 נתיבי סינון כפולים. שתי העמודות הנגזרות בטבלת העובדות אומתו מול הנוסחה שלהן שורה-שורה.
אפשר לנווט גם בכפתורים שבראש המסך, בחצי המקלדת, ובטלפון בהחלקת אצבע