ייצוג: הנדסת תכונות

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

מיפוי נתונים גולמיים לתכונות

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

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

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

איור 1. הנדסת התכונות ממפה נתונים גולמיים לתכונות למידת מכונה.

מיפוי ערכים מספריים

לנתונים של מספרים שלמים ומנקודה צפה (floating-point) אין צורך בקידוד מיוחד כי אפשר להכפיל אותם במשקל מספרי. כפי שמתואר באיור 2, המרת הערך של המספר השלם הגולמי 6 לערך התכונה 6.0 היא טריוויאלית:

דוגמה לתכונה שניתן להעתיק ישירות מהנתונים הגולמיים

איור 2. מיפוי ערכים של מספרים שלמים לערכים של נקודות צפות.

מיפוי ערכים קטגוריים

לתכונות קטגוריות יש קבוצה נפרדת של ערכים אפשריים. לדוגמה, יכול להיות שיש תכונה בשם street_name עם אפשרויות שכוללות:

{'Charleston Road', 'North Shoreline Boulevard', 'Shorebird Way', 'Rengstorff Avenue'}

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

ניתן לעשות זאת על ידי הגדרת מיפוי מערכי התכונות, שנקראים אוצר המילים של ערכים אפשריים, למספרים שלמים. מאחר שלא כל רחוב בעולם יופיע במערך הנתונים, אנחנו יכולים לקבץ את כל הרחובות האחרים בקטגוריה "אחרת", שנקראת OOV (מחוץ לאוצר המילים).

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

  • מפה את Charleston Road ל-0
  • מיפוי של שדרות החוף הצפוני ל-1
  • מפה את הדרך של Shorebird
  • למפות את שדרת רנגסטורף ל-3
  • מיפוי של כל השאר (OOV) ל-4

עם זאת, אם נשלב את מספרי האינדקסים האלה ישירות במודל שלנו, הדבר יחיל מספר מגבלות שעלולות להיות בעייתיות:

  • נלמד משקולת אחת שרלוונטית לכל הרחובות. לדוגמה, אם נלמד משקל של 6 בשביל street_name, נכפיל אותו ב-0 עבור כביש צ'רלסטון, ב-1 עבור שדרות החוף הצפוני, 2 עבור כביש Shorebird Way וכן הלאה. ניקח לדוגמה מודל שחוזה את מחירי הדירות באמצעות המאפיין street_name. סביר להניח שלא תהיה התאמה לינארית של המחיר על סמך שם הרחוב. בנוסף, ההנחה היא שהזמנתם את הרחובות לפי מחיר הבית הממוצע שלהם. המודל שלנו צריך את הגמישות שמאפשרת למידת משקלים שונים לכל רחוב שיתווסף למחיר המשוער באמצעות שאר התכונות.

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

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

  • עבור הערכים שחלים על הדוגמה, מגדירים את הרכיבים הווקטוריים התואמים ל-1.
  • מגדירים את כל שאר הרכיבים לערך 0.

אורך הווקטור הזה שווה למספר הרכיבים באוצר המילים. הייצוג הזה נקרא קידוד one-hot כאשר ערך יחיד הוא 1, וקידוד מרובה-חמים כאשר מספר ערכים הם 1.

איור 3 ממחיש קידוד לוהט אחד של רחוב מסוים: דרך Shorebird. לאלמנט בווקטור הבינארי של Shorebird Way יש ערך של 1, ואילו לרכיבים בכל שאר הרחובות יש ערך 0.

מיפוי של ערך מחרוזת (

איור 3. מיפוי כתובת באמצעות קידוד חד-פעמי.

הגישה הזו יוצרת למעשה משתנה בוליאני לכל ערך של תכונה (למשל, שם רחוב). במקרה הזה, אם בית נמצא ברחוב Shorebird, הערך הבינארי הוא 1 רק עבור Shorebird Way. לכן, המודל משתמש רק במשקל של ShorebirdWay.

באופן דומה, אם בית נמצא בפינת שני רחובות, שני ערכים בינאריים מוגדרים ל-1 והמודל משתמש בשתי המשקולות שלהם.

ייצוג Sparse

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