מודול 5: יישור פרוקרוסטס — הכנסת צורות לאותו מרחב
שבוע 5 — ערכת הכלים
הבעיה שאנחנו פותרים
בשבוע שעבר ראיתם את ציוני הדרך הגולמיים מפוזרים בכל הגרף. כל תמונת מטבע נסרקה בגודל שונה, עם המטבע במיקום וכיוון שונים. לפני שנוכל להשוות צורות, עלינו להסיר הבדלים לא-רלוונטיים אלה.
יישור פרוקרוסטס הוא הפתרון המתמטי.
מה GPA עושה: שלושה שלבים
ניתוח פרוקרוסטס מוכלל (GPA) מסיר שלושה מקורות שונות שאינם צורה:
שלב 1: הזזה (Translation)
הזזת כל תצורה כך שהצנטרואיד שלה (מרכז גיאומטרי) יהיה בנקודת הראשית \((0, 0)\).
שלב 2: קנה מידה (Scaling)
שינוי גודל כל תצורה כך שהגודל-צנטרואיד שלה יהיה שווה ל-1.
גודל-צנטרואיד = שורש ריבועי של סכום ריבועי המרחקים מכל ציון דרך לצנטרואיד:
\[CS = \sqrt{\sum_{i=1}^{k} d_i^2}\]
כאשר \(d_i\) הוא המרחק מציון הדרך \(i\) לצנטרואיד.
זהו מדד הגודל הסטנדרטי ב-GM כי הוא עצמאי סטטיסטית מהצורה (בניגוד לאורך או רוחב, שמתואמים עם הצורה).
שלב 3: סיבוב (Rotation)
סיבוב כל תצורה כדי למזער את המרחק הכולל בין ציוני הדרך שלה לתצורה הממוצעת (צורת הקונסנסוס).
לאחר שלושת השלבים, כל התצורות מוחלות על אותה מערכת קואורדינטות. מה שנותר הוא צורה.
צורת הקונסנסוס
לאחר GPA, ניתן לחשב את הצורה הממוצעת (קונסנסוס) — המיקום הממוצע של כל ציון דרך בכל הפרטים המיושרים. זוהי צורת הייחוס שלנו לויזואליזציה.
שונות הצורה במאגר הנתונים נמדדת אז כסטיות מקונסנסוס זה.
הרצת GPA ב-Colab
# תא 1: הגדרה
!pip install morphops python-bidi -q
import morphops
import numpy as np
import matplotlib.pyplot as plt
from bidi.algorithm import get_display
rtl = get_display # תיקון כיוון טקסט עברי בגרפים של matplotlib
# טעינת נתונים (שימוש בפונקציה read_tps משבוע 4)
def read_tps(filepath):
specimens = []
current_lms = []
n_lm = 0
with open(filepath, 'r') as f:
for line in f:
line = line.strip().replace(',', '.')
if line.startswith('LM='):
n_lm = int(line.split('=')[1])
current_lms = []
elif line.startswith('IMAGE=') or line.startswith('ID='):
if len(current_lms) == n_lm and n_lm > 0:
specimens.append(current_lms)
elif line and not line.startswith(('SCALE=', 'CURVES=')):
try:
coords = list(map(float, line.split()))
if len(coords) == 2:
current_lms.append(coords)
except:
pass
if len(current_lms) == n_lm and n_lm > 0:
specimens.append(current_lms)
return np.array(specimens)
hadrian = read_tps("data/coins/DEN_Hadrian/Hadrian.TPS")
print(f"נטענו {hadrian.shape[0]} מטבעות, {hadrian.shape[1]} ציוני דרך כל אחד")# תא 2: ניתוח פרוקרוסטס מוכלל
# morphops.gpa() מחזיר מילון עם 'aligned', 'mean', ועוד
result = morphops.gpa(hadrian)
aligned = result['aligned'] # ציוני דרך מיושרים
mean_shape = result['mean'] # צורה ממוצעת
print(f"צורה מיושרת: {aligned.shape}")
print(f"טווח x לאחר GPA: {aligned[:,:,0].min():.3f} עד {aligned[:,:,0].max():.3f}")# תא 3: ציור תצורות מיושרות
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
# לפני יישור
ax1.set_title(rtl("לפני GPA (קואורדינטות גולמיות)"))
for coin in hadrian:
c = coin - coin.mean(axis=0)
ax1.scatter(c[:, 0], c[:, 1], alpha=0.2, s=10, color='gray')
# לאחר יישור
ax2.set_title(rtl("לאחר GPA (קואורדינטות פרוקרוסטס)"))
for coin in aligned:
ax2.scatter(coin[:, 0], coin[:, 1], alpha=0.2, s=10, color='steelblue')
# צורה ממוצעת
ax2.scatter(mean_shape[:, 0], mean_shape[:, 1],
s=100, color='red', zorder=5, label=rtl('צורה ממוצעת'))
ax2.legend()
for ax in (ax1, ax2):
ax.set_aspect('equal')
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()מה גודל-צנטרואיד מספר לנו?
גודל-צנטרואיד הוא תוצר לוואי של GPA. הוא מספר לנו על הגודל היחסי של כל פרט. ניתן לשאול:
- האם הגודל מתואם עם הצורה? (זה נקרא אלומטריה)
- האם חלק מהמטבעות יוצרו מ-flan גדול יותר?
- האם גודל המטבע השתנה עם הזמן?
# תא 4: חישוב גודל-צנטרואיד
centroid_sizes = np.sqrt(np.sum(
(hadrian - hadrian.mean(axis=1, keepdims=True))**2,
axis=(1, 2)
))
plt.figure(figsize=(8, 4))
plt.hist(centroid_sizes, bins=10, edgecolor='black', color='steelblue')
plt.xlabel(rtl("גודל-צנטרואיד"))
plt.ylabel(rtl("מספר מטבעות"))
plt.title(rtl("התפלגות גדלי מטבעות הדריאנוס"))
plt.show()
print(f"ממוצע גודל-צנטרואיד: {centroid_sizes.mean():.4f}")
print(f"סטיית תקן: {centroid_sizes.std():.4f}")
print(f"CV: {centroid_sizes.std()/centroid_sizes.mean()*100:.1f}%")CV נמוך פירושו שהמטבעות יוצרו בגודל עקבי — תקנון חזק. CV גבוה מצביע על פחות שליטת איכות.
אינטואיציה ויזואלית למרחב הצורות
לאחר GPA, כל התצורות קיימות במרחב צורות רב-ממדי (מרחב הצורות של קנדל). כל פרט הוא נקודה יחידה במרחב זה.
ממדי מרחב הצורות = (מספר ציוני הדרך × 2) − 4 לנתונים דו-ממדיים
(מחסירים 4 עבור 2 ממדי הזזה, 1 קנה מידה, ו-1 סיבוב שהוסרו על ידי GPA.)
עבור מאגר מטבעות ה-8 ציוני הדרך שלנו: \((8 \times 2) - 4 = 12\) ממדים.
12 ממדים הם יותר מדי לויזואליזציה ישירה. לשם כך PCA — בשבוע הבא.
בדיקת מושגים מרכזיים
לפני מודול 6, ודאו שאתם מבינים:
- אילו שלושה מקורות שונות מסיר GPA?
- מדוע גודל-צנטרואיד עדיף על מדידות ליניאריות כמשתנה גודל?
- לאחר GPA, כמה ממדים יש למרחב הצורות עבור 8 ציוני דרך בשניים ממדים?
- מהי צורת הקונסנסוס וכיצד היא משמשת?
לשבוע הבא
בשבוע הבא: PCA מצמצם את מרחב הצורות ה-12-ממדי ל-2–3 ממדים שנוכל לראות — ומחבר את הממדים לתכונות צורה גלויות באמצעות רשתות עיוות.