DR. IGOR DATA SCIENCEAI, Data & Creativity · From Data to Impact
גרסת מרצה — הפתרונות פתוחים
אלגברה ליניארית למדעי הנתונים

תרגול 1 וקטורים ומכפלה פנימית

תנאי → זמן לחשוב → רמזים מדורגים → פתרון ברור → בדיקת Python → טעות נפוצה → Take-home message.

שאלה
חשיבה
רמז
פתרון
Python
Take-home
01

מה קוראים ומה פותרים

תכנון התרגול לפי פרק 1 של Boyd.

חומר קריאה

סעיפים 1.1–1.5

וקטורים, חיבור, כפל בסקלר, מכפלה פנימית וסיבוכיות חישובי וקטורים.

התרגילים מתחילים בעמוד 25 של הספר.

תרגיל בית

1.4 · 1.6 · 1.9 · 1.16

הפתרונות אינם נפתחים בעמוד זה, כדי להשאיר את העבודה עצמאית.

מבנה מומלץ למרצה: הציגו תנאי בלבד, הפעילו טיימר, אספו שתי הצעות מן הכיתה, פתחו רמז ראשון רק אם נתקעים, ורק בסוף פתחו פתרון ו-Take-home message.
פתיחה1.1 ו-1.2 — סימון וממדים
הבנה מושגית1.5 — משמעות של דלילות
פעולות ויישומים1.7, 1.8, 1.10
בונוס1.13 ו-1.15 אם נשאר זמן
02

תרגילים לפתרון בכיתה

שישה תרגילי ליבה ושני תרגילי הרחבה.

תרגיל ליבה Boyd 1.1 5 דקות

משוואות וקטוריות — אמת, שקר או סימון לא תקין?

לפי מוסכמות הסימון של הספר, קבעו עבור כל משפט אם הוא נכון, לא נכון, או אינו בעל משמעות בגלל סימון לא תקין.

\[ \text{(a)}\quad \begin{bmatrix}1\\2\\1\end{bmatrix}=(1,2,1) \] \[ \text{(b)}\quad \begin{bmatrix}1\\2\\1\end{bmatrix}=[1,2,1] \] \[ \text{(c)}\quad (1,(2,1))=((1,2),1) \]
עצרו וחשבו: אל תתחילו מיד להשוות מספרים. קודם שאלו: האם שני הצדדים הם ביטויים וקטוריים תקינים? רק אחר כך בדקו ממד ואיברים.
רמז 1
וקטור עמודה וכתיבה בסוגריים עגולים יכולים לתאר אותו וקטור.
רמז 2
פתחו את הווקטורים המשורשרים: גם \((1,(2,1))\) וגם \(((1,2),1)\) הופכים ל-\((1,2,1)\).
פתרון מלא, שלב אחר שלב

(a) נכון. שני הצדדים הם 3-וקטורים, ובכל מקום מופיע אותו איבר.

(b) סימון לא תקין לפי הספר. הספר אינו משתמש ב-\([1,2,1]\) ככתיבה של וקטור שורה. חשוב לומר שזה כלל סימון של הקורס; בסביבות תכנות סוגריים מרובעים יכולים לייצג רשימה.

(c) נכון. שתי הכתיבות הן אותו וקטור משורשר:

\[(1,(2,1))=(1,2,1)=((1,2),1)\]
בדיקה או המחשה ב-Python
כאן המוקד הוא סימון מתמטי, לא חישוב. ב-Python הביטוי [1, 2, 1] הוא רשימה תקינה, ולכן אסור לערבב בין מוסכמות הספר לבין תחביר Python.
טעות נפוצה
להכריז ש-(b) נכון רק מפני שב-Python סוגריים מרובעים מייצגים רשימה.
Take-home message
לפני כל חישוב בודקים שלושה דברים: הביטוי מוגדר, הממדים מתאימים, והאיברים המתאימים שווים.
הערת הוראה למרצה
פתח מצוין לשיעור. בקשו מהכיתה להצביע בשלוש אפשרויות: נכון / לא נכון / חסר משמעות. עצרו במיוחד ב-(b) כדי להפריד בין שפה מתמטית לשפת תכנות.
תרגיל ליבה Boyd 1.2 12 דקות

סימון וממדים של וקטורים

נתונים \(a,b\in\mathbb{R}^{10}\) ו-\(c\in\mathbb{R}^{20}\). קבעו אילו ביטויים תקינים, ובמקרה תקין מצאו את האורך.

\[ \text{(a)}\ a+b-c_{3:12} \qquad \text{(b)}\ (a,b,c_{3:13}) \] \[ \text{(c)}\ 2a+c \qquad \text{(d)}\ (a,1)+(c_1,b) \] \[ \text{(e)}\ ((a,b),a) \qquad \text{(f)}\ [\,a\ b\,]+4c \] \[ \text{(g)}\ \begin{bmatrix}a\\b\end{bmatrix}+4c \]
עצרו וחשבו: כתבו ליד כל תת-וקטור את אורכו. זכרו שבסימון הספר הטווח \(r:s\) כולל את שני הקצוות.
רמז 1
האורך של \(c_{3:12}\) הוא \(12-3+1=10\); האורך של \(c_{3:13}\) הוא 11.
רמז 2
יש הבדל בין הצבת \(a,b\) זה לצד זה, שיוצרת מטריצה, לבין stacking אנכי שיוצר וקטור באורך 20.
פתרון מלא, שלב אחר שלב
  • (a) תקין, אורך 10: לכל שלושת הווקטורים אורך 10.
  • (b) תקין, אורך 31: \(10+10+11=31\).
  • (c) לא תקין: \(2a\) באורך 10 ואילו \(c\) באורך 20.
  • (d) תקין, אורך 11: גם \((a,1)\) וגם \((c_1,b)\) באורך 11.
  • (e) תקין, אורך 30: \((a,b)\) באורך 20, ולאחר הוספת \(a\) מקבלים 30.
  • (f) לא תקין: \([\,a\ b\,]\) היא מטריצה \(10\times2\), לא 20-וקטור.
  • (g) תקין, אורך 20: stacking אנכי של \(a,b\) יוצר 20-וקטור.
בדיקה או המחשה ב-Python
NumPyבדיקת shapes
import numpy as np

a = np.zeros(10)
b = np.ones(10)
c = np.arange(20)

print((a + b - c[2:12]).shape)      # (10,)
print(np.concatenate([a, b, c[2:13]]).shape)  # (31,)
print(np.concatenate([a, b]).shape) # (20,)
ב-Python הגבול הימני של slice אינו נכלל, ולכן \(c_{3:12}\) המתמטי מתאים ל-c[2:12].
טעות נפוצה
לספור את \(c_{3:13}\) כאילו אורכו 10, או להתייחס ל-\([a\ b]\) כאל וקטור משורשר.
Take-home message
חיבור דורש ממדים זהים; stacking מחבר אורכים; slicing מתמטי כולל את הקצה הימני.
הערת הוראה למרצה
בנו טבלה על הלוח: ביטוי | סוג העצם | אורך. תנו לסטודנטים לפתור בזוגות. ב-(f) שאלו: מהו ה-shape, לא רק 'למה אי אפשר'.
תרגיל ליבה Boyd 1.5 10 דקות

מה אומרת דלילות בעולם האמיתי?

הווקטור \(x\in\mathbb{R}^n\) דליל: רק מעט מאיבריו שונים מאפס. הסבירו במילים מה פירוש הדבר בכל הקשר:

  1. תזרים מזומנים יומי של עסק.
  2. רכישות שנתיות של לקוח מתוך \(n\) מוצרים.
  3. תיק השקעות ב-\(n\) מניות.
  4. רשימת חומרים לפרויקט.
  5. תמונה מונוכרומטית.
  6. כמות גשם יומית במשך שנה.
עצרו וחשבו: אל תסתפקו במשפט 'יש הרבה אפסים'. תרגמו את האפס למשמעות בתחום: מה פירושו אפס כסף? אפס בהירות? אפס גשם?
רמז 1
בכל סעיף נסחו: 'ברוב הימים / המוצרים / המניות / הפיקסלים ...'.
רמז 2
בתמונה מונוכרומטית בהירות אפס פירושה בדרך כלל פיקסל שחור.
פתרון מלא, שלב אחר שלב
  1. ברוב הימים אין לעסק תקבול או תשלום נטו.
  2. הלקוח רכש רק מספר קטן מתוך כלל המוצרים.
  3. התיק מחזיק פוזיציות, ארוכות או קצרות, רק במספר קטן של מניות.
  4. הפרויקט דורש רק מעט סוגי חומרים.
  5. רוב הפיקסלים שחורים; רק מעט פיקסלים מוארים. דוגמה טבעית היא צילום אסטרונומי.
  6. ברוב ימות השנה לא ירד גשם.
בדיקה או המחשה ב-Python
NumPyNNZ
import numpy as np

x = np.array([0, 0, 4.2, 0, 0, -1.0, 0])
nnz = np.count_nonzero(x)

print(nnz)  # 2
טעות נפוצה
לומר שכל וקטור דליל הוא 'קטן'. דלילות מתארת את מספר האיברים הלא-אפסיים, לא את גודל הערכים.
Take-home message
דלילות היא הנחה על מבנה הנתונים: רוב המצבים אינם פעילים, ורק מעט רכיבים נושאים מידע.
הערת הוראה למרצה
חלקו את הכיתה לשש קבוצות, הקשר אחד לכל קבוצה. בקשו ניסוח של משפט אחד בלי המילה 'אפס'. כך בודקים שהם באמת מבינים את המשמעות.
תרגיל ליבה Boyd 1.7 10 דקות

המרה בין קידוד 0/1 לקידוד ‎−1/+1

הווקטור \(x\) מקודד תנאים באמצעות \(0,1\). אותו מידע מקודד בווקטור \(y\) באמצעות \(-1,+1\).

מצאו נוסחה וקטורית ל-\(y\) באמצעות \(x\), ונוסחה הפוכה ל-\(x\) באמצעות \(y\).

\[(0,1,1,0)\longleftrightarrow(-1,1,1,-1)\]
עצרו וחשבו: חפשו פונקציה אפינית פשוטה שמעבירה את שתי נקודות הקצה: \(0\mapsto-1\), \(1\mapsto1\).
רמז 1
נניח \(y_i=ax_i+b\). הציבו \(x_i=0\) ו-\(x_i=1\).
רמז 2
מן התנאים מתקבלים \(b=-1\) ו-\(a=2\). כדי להפוך, פתרו את המשוואה עבור \(x\).
פתרון מלא, שלב אחר שלב
\[ y=2x-\mathbf{1} \] \[ x=\frac12\left(y+\mathbf{1}\right) \]

בדיקה רכיבית: אם \(x_i=0\), אז \(y_i=-1\); אם \(x_i=1\), אז \(y_i=1\).

בדיקה או המחשה ב-Python
NumPyforward and inverse encoding
import numpy as np

x = np.array([0, 1, 1, 0])
y = 2 * x - 1
x_back = (y + 1) / 2

print(y)       # [-1  1  1 -1]
print(x_back)  # [0. 1. 1. 0.]
טעות נפוצה
לכתוב \(y=x-1\), שממפה \(1\) ל-0 במקום ל-1; או לשכוח ש-\(1\) בנוסחה הוא וקטור אחדים.
Take-home message
המרה בין קידודים היא טרנספורמציה אפינית רכיבית. בודקים אותה על ערכי הקצה.
הערת הוראה למרצה
שאלו קודם על מקרה סקלרי, ורק לאחר שהכיתה מוצאת \(2x-1\), עברו לסימון וקטורי. הדגישו את \(\mathbf1\).
תרגיל ליבה Boyd 1.8 8 דקות

רווח כולל ממוצרים ומכירות

חברה מוכרת \(n\) מוצרים. \(p_i\) הוא הרווח ליחידה ממוצר \(i\), ו-\(s_i\) הוא מספר היחידות שנמכרו בתקופה.

הביעו את הרווח הכולל באמצעות \(p\) ו-\(s\).

עצרו וחשבו: מהן היחידות של \(p_i s_i\)? ומה צריך לעשות לאחר שמחשבים את הרווח מכל מוצר בנפרד?
רמז 1
למוצר \(i\), הרווח הוא \(p_i s_i\).
רמז 2
חיבור על כל המוצרים הוא בדיוק מכפלה פנימית.
פתרון מלא, שלב אחר שלב
\[ P=\sum_{i=1}^{n}p_i s_i=p^Ts \]

הערך \(p_i\) נמדד בדולרים ליחידה, \(s_i\) ביחידות, ולכן המכפלה היא בדולרים. החיבור נותן את הרווח הכולל.

בדיקה או המחשה ב-Python
NumPytotal profit
import numpy as np

p = np.array([4.0, -1.0, 2.5])
s = np.array([100, 10, 40])

total_profit = p @ s
print(total_profit)  # 490.0
טעות נפוצה
לחשב \(\sum p_i+\sum s_i\), או להסתפק ב-\(p\odot s\) בלי לחבר את הרכיבים.
Take-home message
מכפלה פנימית היא סכום משוקלל. כאן הכמויות הן הנתונים והרווח ליחידה הוא המשקל.
הערת הוראה למרצה
בקשו מן הכיתה לבדוק יחידות. זו דרך חזקה להגיע למכפלה הפנימית בלי לזכור נוסחה בעל פה.
תרגיל ליבה Boyd 1.10 16 דקות

בניית וקטור משקלים לציון קורס

וקטור הציונים \(r\in\mathbb{R}^{10}\) בנוי כך:

  • \(r_1,\ldots,r_8\): שמונה עבודות בית, כל אחת בסולם 0–10.
  • \(r_9\): מבחן אמצע בסולם 0–120.
  • \(r_{10}\): מבחן סופי בסולם 0–160.

הציון הסופי בסולם 0–100 מורכב מ-25% עבודות בית, 35% אמצע ו-40% סופי. מצאו \(w\) כך ש-\(s=w^Tr\).

עצרו וחשבו: אי אפשר להשתמש ישירות ב-\(0.25,0.35,0.40\), מפני שהרכיבים אינם באותו סולם. תחילה נרמלו כל חלק לסולם 0–100.
רמז 1
סכום עבודות הבית המקסימלי הוא 80, ולכן כל נקודת עבודת בית שווה \(25/80\) נקודות בציון הסופי.
רמז 2
מקדם האמצע הוא \(35/120\), ומקדם הסופי הוא \(40/160\).
פתרון מלא, שלב אחר שלב

לכל עבודת בית:

\[\frac{25}{80}=0.3125\]

למבחן האמצע:

\[\frac{35}{120}\approx0.2917\]

למבחן הסופי:

\[\frac{40}{160}=0.25\]

לכן:

\[ w=\left(0.3125\,\mathbf1_8,\ 0.2917,\ 0.25\right) \] \[ s=w^Tr \]

בדיקת קצה: סטודנט שקיבל את הציון המקסימלי בכל רכיב יקבל \(25+35+40=100\).

בדיקה או המחשה ב-Python
NumPyweights and verification
import numpy as np

w = np.concatenate([
    np.full(8, 25 / 80),
    np.array([35 / 120, 40 / 160])
])

max_record = np.array([10] * 8 + [120, 160])

print(w)
print(w @ max_record)  # 100.0
טעות נפוצה
להשתמש במשקלים 0.25, 0.35 ו-0.40 ישירות על ציונים בסולמות שונים.
Take-home message
בציון משוקלל יש שני שלבים: המרה לסולם משותף, ואז החלת משקלי החשיבות.
הערת הוראה למרצה
זו משימת הליבה של השיעור. בקשו שלושה פתרונות נפרדים: עבודות בית, אמצע, סופי. אל תציגו את \(w\) לפני שהכיתה בודקת שהמקסימום נותן 100.
אם נשאר זמן Boyd 1.13 12 דקות

התפלגות גילאים באוכלוסייה

הווקטור \(x\in\mathbb{R}^{100}\) מתאר התפלגות גילאים: \(x_i\) הוא מספר האנשים בגיל \(i-1\).

הביעו באמצעות סימון וקטורי:

  1. את גודל האוכלוסייה.
  2. את מספר האנשים בגיל 65 ומעלה.
  3. את הגיל הממוצע.
עצרו וחשבו: בנו שלושה וקטורי משקל: אחדים לכל הגילאים; מסכה לגיל 65 ומעלה; וקטור הגילאים \(0,1,\ldots,99\).
רמז 1
גיל 65 מתאים לאינדקס \(66\), מפני ש-\(x_i\) מתאר גיל \(i-1\).
רמז 2
לממוצע דרושים סכום הגילאים המשוקלל ומספר האנשים הכולל.
פתרון מלא, שלב אחר שלב
\[ N=\mathbf1^Tx \] \[ N_{65+}=a^Tx,\qquad a=(\mathbf0_{65},\mathbf1_{35}) \] \[ \bar{g}= \frac{(0,1,2,\ldots,99)^Tx}{\mathbf1^Tx} \]

המונה בנוסחת הממוצע הוא סכום הגילאים של כל האנשים, והמכנה הוא מספר האנשים.

בדיקה או המחשה ב-Python
NumPypopulation statistics
import numpy as np

x = np.zeros(100, dtype=int)
x[20] = 30   # 30 people aged 20
x[70] = 10   # 10 people aged 70

ages = np.arange(100)

population = x.sum()
over_65 = x[65:].sum()
average_age = ages @ x / population

print(population, over_65, average_age)
טעות נפוצה
לספור \(x_{65}\) כגיל 65. לפי ההגדרה, \(x_{65}\) מתאר גיל 64.
Take-home message
מסכה בינארית בוחרת תת-קבוצה; וקטור ערכים משמש לחישוב סכום משוקלל וממוצע.
הערת הוראה למרצה
משימת בונוס מצוינת לחיבור בין indexing לבין inner product. כתבו על הלוח: index = age + 1.
אם נשאר זמן Boyd 1.15 14 דקות

בחירת ספק זול ופיצול הזמנה

יש לרכוש כמויות \(q\in\mathbb{R}^n\) של \(n\) חומרי גלם. ספק \(k\) מציע וקטור מחירים \(p_k\).

  1. כיצד בוחרים ספק יחיד בעל העלות הנמוכה ביותר?
  2. יועץ מציע להזמין חצי מן הכמות מכל אחד משני ספקים שונים. האם הדבר יכול להוזיל את העלות לעומת הספק הזול ביותר?
עצרו וחשבו: כתבו תחילה את מחיר ההזמנה אצל ספק \(k\). לאחר מכן השוו בין המינימום של המספרים לבין הממוצע של שניים מהם.
רמז 1
עלות אצל ספק \(k\) היא \(C_k=p_k^Tq\).
רמז 2
לכל שני מספרים \(C_i,C_j\), הממוצע שלהם אינו קטן מן הקטן מביניהם.
פתרון מלא, שלב אחר שלב

מחיר ההזמנה המלאה אצל ספק \(k\):

\[C_k=p_k^Tq\]

בוחרים:

\[k^\star=\arg\min_k p_k^Tq\]

אם מפצלים חצי-חצי בין ספקים \(i,j\), העלות היא:

\[ \frac12p_i^Tq+\frac12p_j^Tq = \frac{C_i+C_j}{2} \]

אבל:

\[ \frac{C_i+C_j}{2}\ge\min(C_i,C_j)\ge\min_k C_k \]

לכן הפיצול אינו יכול להיות זול יותר מן הספק הזול ביותר. ייתכנו יתרונות אחרים, למשל גיבוי או סיכון אספקה, אך לא יתרון מחיר במודל הזה.

בדיקה או המחשה ב-Python
NumPysupplier costs
import numpy as np

q = np.array([10, 5, 20])
prices = np.array([
    [3.0, 4.0, 1.5],
    [2.8, 4.5, 1.7],
    [3.2, 3.8, 1.6]
])

costs = prices @ q
best = np.argmin(costs)

print(costs)
print(best, costs[best])
טעות נפוצה
להניח שפיזור בין ספקים בהכרח מוזיל מחיר. ממוצע של עלויות אינו יכול להיות קטן מן העלות המינימלית.
Take-home message
עלות כוללת היא מכפלה פנימית; שילוב קמור של עלויות אינו יורד מתחת למינימום.
הערת הוראה למרצה
לפני האלגברה שאלו אינטואיטיבית: האם ממוצע של 100 ו-120 יכול להיות קטן מ-100? משם המעבר לווקטורים מיידי.
03

תרגיל בית

ארבעה תרגילים מן הספר, ללא פתרונות בעמוד זה.

Boyd 1.4 ללא פתרון בעמוד זה

צריכת אנרגיה מחזורית

וקטור \(w\in\mathbb{R}^{168}\) מתאר צריכת חשמל שעתית במשך שבוע, והדפוס חוזר כל 24 שעות. \(d\in\mathbb{R}^{24}\) מתאר יום אחד. הביעו את \(w\) בעזרת \(d\), ואת \(d\) בעזרת \(w\).

רעיון מרכזי: stacking ו-slicing

Boyd 1.6 ללא פתרון בעמוד זה

וקטור הפרשים

עבור \(x\in\mathbb{R}^n\), הגדירו \(d=(x_2-x_1,\ldots,x_n-x_{n-1})\). הביעו את \(d\) באמצעות תת-וקטורים ופעולות וקטוריות.

רעיון מרכזי: slicing וחיסור

Boyd 1.9 ללא פתרון בעמוד זה

וקטור סימפטומים

וקטור בינארי \(s\in\mathbb{R}^{20}\) מתאר נוכחות של סימפטומים. הביעו את מספר הסימפטומים הכולל, ואת הטענה שלמטופל יש בדיוק חמישה מתוך עשרת הסימפטומים הראשונים.

רעיון מרכזי: וקטור אחדים ומסכה

Boyd 1.16 ללא פתרון בעמוד זה

מכפלה פנימית של וקטורים אי-שליליים

הסבירו מדוע מכפלה פנימית של שני וקטורים אי-שליליים אינה שלילית. אם המכפלה שווה לאפס, מה ניתן להסיק על דפוסי האפסים והאיברים החיוביים?

רעיון מרכזי: אי-שליליות ותמיכות

בדיקה לפני הגשה: בכל תשובה השתמשו בסימון וקטורי, הגדירו כל וקטור עזר, ובדקו ממדים.
04

סיכום התרגול

ארבע שאלות שכדאי לשאול בכל בעיית וקטורים.

1. מה מייצג כל איבר?

ללא משמעות הרכיבים קל לכתוב נוסחה לא נכונה.

2. האם הממדים מתאימים?

בודקים לפני חיבור, חיסור או מכפלה פנימית.

3. האם דרוש סכום משוקלל?

אם כן, חפשו מכפלה פנימית.

4. האם יש מבנה מיוחד?

מסכה בינארית, דלילות, slicing או stacking יכולים לפשט את הפתרון.