רגרסיה קווית באמצעות TensorFlow 2

מחבר:
בתאריך:

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

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

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

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

לחץ להורדת קובץ Jupyter Notebook שאותו נפתח במדריך

ספריית TensorFlow 2 ללמידת מכונה by google

 

תזכורת לגבי מודל קווי (לינארי)

מודל קווי (לינארי) הוא קו ישר בתוך מערכת צירים. למודל קווי יש שני מאפיינים, שיפוע ונקודת חיתוך עם ציר ה-Y.

זו משוואת הקו הישר:

Y = m*X + B
  • m - שיפוע הקו הישר
  • B - נקודת החיתוך עם ציר ה - Y

משוואת הקו הישר

משוואת הקו הישר מתאימה ערך של Y לכל ערך של X.

על ציר ה-Y נמצאים המשתנים אותם אנו מנסים לחזות. אילו המשתנים התלויים.

על ציר ה-X נמצאים המשתנים הבלתי תלויים המכונים גם פיצ'רים (features).

במדריך זה, ננסה לחזות את שווי הדירה (ציר Y) על פי שטח הדירה (ציר X).

המשוואה :

Y = m*X + B

מוצאת ערך Y לכל ערך של X. לדוגמה, מחיר על פי שטח הדירה.

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

Y = m1*X + m2*Z + B

כל פיצ'ר מתייחס לציר אחד ומצויד בשיפוע משלו.

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

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

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

 

ייבוא הספריות שישמשו במדריך

נתחיל בייבוא 3 הספריות השימושיות ביותר ללמידת מכונה:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
  • Numpy לעבודה עם מערכים רב-ממדיים.
  • Pandas לסידור ולסינון מידע בדומה לאקסל.
  • Matplotlib להצגת מידע באמצעות גרפים ותרשימים.

TensorFlow 2 היא הספרייה בה נשתמש ללמידת מכונה. אני משתמש בגרסה 2.2 מכיוון שהיא העדכנית ביותר בזמן כתיבת המדריך.

נתקין את הגרסה שמעניינת אותנו:

!pip install tensorflow==2.2.0

את המדריך פתחתי בסביבת Colab ומשמעות סימן הקריאה (!) בתחילת השורה הוא שימוש בטרמינל המובנה של סביבת הפיתוח.

נייבא:

import tensorflow as tf

נוודא שייבאנו את הגרסה שבה אנו מעוניינים:

print(tf.__version__)
2.2.0

 

ייבוא מסד הנתונים

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

df = pd.read_csv('../data/sacramentorealestatetransactions.csv',usecols=['sq__ft', 'price'])

במדריך נשתמש בעמודות שטח הבית (sq__ft) והמחיר מפני שאנחנו רוצים לחזות את מחירי הבתים על סמך השטח שלהם.

 

סקירת הנתונים וניקוי דוגמאות חריגות

נסקור את הנתונים לפני שנכנס לתהליך הלמידה כדי להימנע מהפתעות בהמשך:

# See the database before doing anything
df.set_index('sq__ft')
df.shape
(985, 2)

מסד הנתונים כולל שני טורים באורך 985 שורות.

נדפיס את המידע על עמודות מסד הנתונים באמצעות:

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 985 entries, 0 to 984
Data columns (total 2 columns):
sq__ft    985 non-null int64
price     985 non-null int64
dtypes: int64(2)
memory usage: 15.5 KB

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

נוודא שלא חסרים נתונים:

df.isnull().sum().sum()
0

התוצאה היא 0, ולפיכך לא חסרים נתונים.

נתאר את מדדי מרכז באמצעות:

df.describe()

ספריית tensorflow ללמידת מכונה

ועכשיו נמצא את מידת הקורלציה בין שטח הבית והמחיר:

# Find the correlation
df.corr()['sq__ft'].sort_values()
price     0.333897
sq__ft    1.000000
Name: sq__ft, dtype: float64

קורלציה נמוכה של 33% בלבד בניגוד לציפייה שלנו שיהיה קשר חזק יותר בין גודל הבית ומחירו. למה?

נציג את הנתונים בגרף וננסה להבין מה מקור השיבוש:

plt.plot(df['sq__ft'], df['price'], 'o')
plt.ylabel('Price')
plt.xlabel('Square foot')
plt.title('Price vs square foot')

מחיר לעומת גודל הבית. מה הבעיה?

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

# Remove the outliers
filtered_data = df.loc[(df.sq__ft > 10) & (df.sq__ft < 5000)]

df = filtered_data

מעניין עם כמה נתונים נשארנו.

df.shape
(813, 2)

נשרטט את סט הנתונים לאחר הסינון:

מחיר לעומת גודל הבית, נתונים מסוננים

המגמה נראית מובהקת יותר.

נמצא את הקורלציה בסט הנתונים לאחר הסינון:

df.corr()['sq__ft'].sort_values()
price     0.728642
sq__ft    1.000000
Name: sq__ft, dtype: float64

ואכן המתאם גבוה משמעותית יותר ועומד על 72.8%.

 

למידת מכונה באמצעות TensorFlow 2

נפריד את הנתונים למשתנים תלויים ובלתי תלויים:

X = df[['sq__ft']].values
y = df['price'].values

ועכשיו, נפריד את הנתונים לשתי קבוצות:

  • קבוצת אימון (train group) שעליה יתאמן המודל
  • קבוצת מבחן (test group) באמצעותה נבחן את מידת הדיוק של המודל
# Split the data to test and train group
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)

הפונקציה train_test_split מפרידה את הנתונים לשתי קבוצות אקראיות כאשר קבוצת המבחן מהווה 33% מסך התצפיות.

נייבא את המודולים של TensorFlow 2 שישמשו אותנו ללמידת המכונה:

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping

המודל מבצע למידת מכונה באמצעות שכבות של נוירונים. TensorFlow משתמש במודל מסוג Sequential שעורם שכבות של נוירונים זו על גבי זו כשלכל שכבה יש קלט ופלט - input ו-output.

יש רק שכבה אחת במודל כי זה לא מודל עמוק אלא רדוד.

את האופטימיזציה נעשה בעזרת פונקציית אופטימיזציה מסוג Adam. אופטימיזציה היא התהליך שמעדכן את הפרמטרים W (שיפוע הישר) ו-B (נקודת החיתוך עם ציר ה-y) במטרה לצמצם כמה שניתן את מידת השגיאה.

נגדיר את המודל:

# Build the model
model = Sequential()

# Convert the value from the input (square foot) to the output (price)
# The model receives 1 input and outputs a single value
model.add(Dense(1, input_shape=(1,)))

# We expect the model to be linear
model.add(Activation('linear'))
  • שכבת נאורונים מסוג Dense פולטת output (y) אחד עבור כל ערך input (x) שהיא מקבלת. עבור כל ערך יחיד של שטח דירה השכבה תפלוט מחיר אחד.
  • input_shape=(1,) מכיוון שהמודל יכול לקבל ריבוי של x עבור ערכי y שהוא מיועד לפלוט.
  • שכבת האקטיבציה היא לינארית כיוון שאנחנו מצפים לקשר לינארי. ככל שהבית גדול יותר כך יעלה המחיר.

נציג את סיכום המודל:

model.summary()
Layer (type)  Output Shape  Param #   
==============================================
dense_2 (Dense)              (None, 1)      2         
______________________________________________
activation_2 (Activation)    (None, 1)      0         
==============================================
Total params: 2
Trainable params: 2
Non-trainable params: 0
  • צורת ה-output היא 2 כיוון שהתוצאה של המודל היא שני הפרמטרים שיפוע ונקודת החיתוך עם ציר ה-y.

נקמפל את המודל:

# Compile the model
# Adam optimizer for the learning rate
# In preliminary trials I found the learning rate of 10 to be the best for 
# the task at hand
model.compile(Adam(lr=10), loss='mean_squared_error')
  • מטרת תהליך הלמידה היא להגדיל את מידת הדיוק של המודל.
  • התקדמות תהליך הלמידה נמדדת באמצעות פונקציה מסוג loss function המודדת את ההבדל בין הערך שחוזה המודל עבור כל דוגמה ודוגמה לבין הערך בפועל במסד הנתונים.
  • ההבדל בין הערך החזוי לערך בפועל נמדד בשיטת טעות ריבועית ממוצעת - mean_squared_error - כיוון שזו הדרך הטובה ביותר כשמנסים למצוא קשר ליניארי.
  • הלמידה נעשית במספר מחזורי למידה (epochs) ובכל מחזור המודל מחשב את מידת השגיאה ומתקן את המודל בהתאם.
  • הגודל של צעדי התיקון בכל מחזור למידה הוא 10 כי זה הערך שנתן לי את התוצאות הטובות ביותר בניסוי מקדים שערכתי.
  • הגודל של צעדי התיקון מכונה קצב למידה learning rate ואותו אנו מעבירים לפונקצית אופטימיזציה מסוג Adam.

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

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

# The EarlyStopping callback stops the learning process if the loss doesn't improve
es = EarlyStopping(monitor='val_loss',
                   min_delta=0,
                   patience=10,
                   verbose=1,
                   mode='auto')

המדד שאחריו אנחנו עוקבים הוא loss ואחרי שני מחזורי לימוד, epochs, שהמדד לא מתקדם תהליך הלמידה יעצור. השם שאנחנו נותנים לערך המנוטר עבור דוגמאות הביקורות הוא val_loss כדי להבחין בין המדד עבור קבוצת האימון (עבורה המדד מכונה loss) לבין דוגמאות הביקורת. בשני המקרים תהליך הלמידה עוקב אחרי המדד loss. רק השם שונה.

אחרי כל ההכנות, הפונקציה הבאה עושה את הלמידה בפועל:

# The actual training 
model.fit(X_train,
          y_train,
          batch_size=32,
          epochs=1000,
          validation_data=(X_test,y_test),
          callbacks=[es])

למידת מכונה עם tensorflow רצה על המחשב שלי

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

בסוף התהליך, נראה את הפרמטרים של משוואת הקו הישר שהמודל מצא:

# Print the parameters for the linear model that tensorflow calculated
W, B = model.get_weights()

print('The slope of the regression line: %.2f' % (W))
print('The intercept for the regression line: %.2f' % (B))
The slope of the regression line: 139.75
The intercept for the regression line: 350.52
  • W הוא שיפוע הקו
  • B היא הנקודה שבה הקו חוצה את ציר ה-y

נשרטט את התחזית שהפיק תהליך הלמידה (y_pred) כנגד הנתונים בפועל (X):

# Predict on the test dataset
y_pred = model.predict(X_test)

plt.plot(df['sq__ft'], df['price'], 'o')
plt.ylabel('Price')
plt.xlabel('Square foot')
plt.title('Price vs square foot')
plt.plot(X_test,y_pred,color='red')

הערכים החזויים לעומת הערכים בפועל

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

 

סיכום

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

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

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

בקובץ המצורף למדריך אני מתאר את הדרך לבחון את מידת המהימנות של המודל לחץ להורדת הקובץ.

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

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

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

כדי לפתור את הבעיות עם משתמשים בערך P כדי לבדוק האם המודל שלנו משמעותי. לצורך חישוב p-value לוקחים בחשבון את השונות (כמו ) ובנוסף את גודל המדגם ואת מספר המשתנים. ככל שכמות הדוגמאות גדולה יותר ומספר המשתנים נמוך יותר כך נקבל ערכי P טובים יותר. ערכי P נעים בין 0 ל-1. ככל שהם שואפים ל-0 כך התוצאות משמעותית יותר. מקובל שערכים נמוכים מ-0.05 נחשבים למשמעותיים כי הם מבטאים סיכוי של 5% שהתוצאה היא אקראית.

בקובץ הבא תוכלו למצוא את כל הקוד של המדריך ותוספות חשובות הכוללות  ו-p-value עבור המודל שמצאנו במדריך כמו גם השוואת ביצועי המודל שלנו למודלים של ספריות ידועות בתחום לחץ להורדת הקובץ.

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

לכל המדריכים בנושא של למידת מכונה

 

אהבתם? לא אהבתם? דרגו!

0 הצבעות, ממוצע 0 מתוך 5 כוכבים

 

 

הוסף תגובה חדשה

 

= 4 + 9