מודל לינארי הכולל משתנים קטגוריים לחיזוי מחירי בתים
זה מדריך ישן בסדרה. נא לקרוא את הגרסה החדשה חיזוי מחירי בתים באמצעות למידת מכונה ומודל מרובה משתנים.
אחרי שבמדריכים הקודמים למדנו לפתח מודל לחיזוי מחירי דירות באמצעות רגרסיה ליניארית עם ספריית Keras בהתבסס על מספר משתנים מספריים (שטח הדירה ומספר החדרים) במדריך הנוכחי נשכלל את המודל ונוסיף לו משתנה קטגורי (סוג הנכס).
לחץ כאן כדי להוריד קובץ ה-csv של מסד הנתונים
לחץ כאן כדי להוריד את קובץ קוד המלא שנפתח במדריך
השלבים המקדימים
את השלבים המקדימים עשיתי במדריך הקודם. לכן אדלג עליהם. להורדת הקוד המלא הכולל את השלבים המקדימים
עיבוד המידע וקידוד משתנים קטגוריים
שימוש במשתנה קטגורי (שמי) מציב בעיה מפני שמחשבים צריכים מספרים כדי לעבוד איתם. גישה אחת לפתרון הבעיה היא למפות כל אחת מהקטגוריות למספר. הבעיה עם הגישה הזו שמודלים של למידת מכונה מניחים שיש למספרים ערך כמותי. לדוגמה, אם אנחנו נקודד את השכונות למספרים. שכונה א תקבל את הערך 1, שכונה ב את הערך 2 ושכונה ג את הערך 3. המודל עלול להסיק ששכונה א + ב שוות לשכונה ג. כדי למנוע את הבעיה משתמשים בקידוד one hot encoding שהופכת את המשתנה השמי למערך של 0 ו-1 שבו כל המשתנים מקבלים 0 לבד מאחד שמקבל 1. כל קטגוריה מקבלת 1 במקום שונה במערך.
בוא נראה איך עושים את זה, ובסוף הדוגמה תוכלו לראות בעצמכם איך נראים משתנים קטגוריים אחרי קידוד בשיטת one hot encoding.
נעזר ב-numpy כדי למצות את סוגי הדירות.
type_names = np.unique(np.array(fd.type))
type_names
array(['Condo', 'Multi-Family', 'Residential'], dtype=object)
3 שמות ל-3 סוגים.
נשתמש ב-pandas כדי לקודד בשיטת one hot encoding, המתאימה לקידוד נתונים קטגוריים.
t_dummies = pd.get_dummies(fd.type)
נציץ במספר דוגמאות אקראיות כדי לראות את הקידוד בפעולה:
t_dummies.sample(5)
Condo | Multi-Family | Residential | |
---|---|---|---|
979 | 0 | 0 | 1 |
297 | 0 | 0 | 1 |
344 | 1 | 0 | 0 |
- דוגמאות 979 ו-297 שייכות לקטגוריה Residential
- דוגמה 344 שייכת לסוג Condo.
נאחד את העמודות שהוספנו כתוצאה מהקידוד עם יתר מסד הנתונים לאורך ציר ה-y:
merged = pd.concat([fd, t_dummies], axis=1)
merged.head()
beds | baths | sq__ft | type | price | Condo | Multi-Family | Residential | |
---|---|---|---|---|---|---|---|---|
0 | 2 | 1 | 836 | Residential | 59222 | 0 | 0 | 1 |
1 | 3 | 1 | 1167 | Residential | 68212 | 0 | 0 | 1 |
2 | 2 | 1 | 796 | Residential | 68880 | 0 | 0 | 1 |
3 | 2 | 1 | 852 | Residential | 69307 | 0 | 0 | 1 |
4 | 2 | 1 | 797 | Residential | 81900 | 0 | 0 | 1 |
collinearity של מודלים לינאריים היא כאשר ניתן להסיק את אחת מעמודות הנתונים מהעמודות האחרות. זו בעיה שנוצרת כשעובדים עם קידוד one hot encoding כי ניתן להסיק תמיד את אחת העמודות משילוב של האחרות. במקרה שלנו, יש לנו שלוש עמודות ואם שתי העמודות הראשונות הם 0 אז נסיק בוודאות שהעמודה השלישית היא 1.
פתרון הבעיה של collinearity הוא באמצעות השמטת אחת העמודות שנוצרו באמצעות one hot encoding. במקרה שלנו נוריד את העמודה Condo:
X = merged.drop(['Condo'],axis=1)
כדי לפתח את המודל אנחנו צריכים להגדיר את ציר ה-x (משתנים בלתי תלויים) ואת ציר ה-y (המשתנה התלוי).
המשתנה התלוי שלנו הוא המחיר:
y = fd['price'].values
המשתנים הבלתי תלויים לא יכולים לכלול את העמודות השמיות וגם לא את עמודת המחיר:
X = merged.drop(['price','type','Condo'],axis=1).values
נשארנו עם העמודות הבאות:
X.columns
Index(['beds', 'baths', 'sq__ft', 'Multi-Family', 'Residential'], dtype='object')
סה"כ 5 סדרות של נתונים שאותם נזין לתוך המודל.
הפרדת הנתונים לסט אימון ומבחן
כפי שראינו במדריכים קודמים, נפצל את הנתונים לקבוצת מבחן ואימון:
# Split the data to test and train groups
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)
אימון המודל
אימון המודל נעשה באמצעות מודל Keras ושכבה אחת של נוירונים:
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
המודל הוא מודל ליניארי פשוט, מפני שניסיתי מספר מודלים מורכבים מרובי שכבות וכולם היו פחות טובים מאשר המודל הלינארי הפשוט אשר שבו אני משתמש במדריך.
model = Sequential()
# The model maps the 5 inputs (according to the number of features) to a single output (price)
# The model receives 1 input and outputs a single value
model.add(Dense(1, input_shape=(5,)))
# We expect the model to be linear
model.add(Activation('linear'))
המבנה של המודל מתבסס 5 קלטים (inputs) כנגד חמישה פיצ'רים בציר ה-x ופלט 1 בודד שהוא המחיר.
נסכם:
model.summary()
Model: "sequential" __________________________________________ Layer (type) Output Shape Param ========================================== dense (Dense) (None, 1) 6 __________________________________________ activation (Activation) (None, 1) 0 ========================================== Total params: 6 Trainable params: 6 Non-trainable params: 0
נקמפל את המודל:
# 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), 'mean_squared_error')
נגדיר את התנאים להפסקת תהליך הלמידה:
# 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')
ניתן למכונה ללמוד:
model.fit(X_train,
y_train,
batch_size=32,
epochs=1000,
validation_data=(X_test,y_test),
callbacks=[es])
הערכת המודל
יש לנו מודל. אבל מה הוא אומר לנו על הנתונים? האם נצליח להפיק ממנו תחזיות סבירות לגבי נתונים שאליהם הוא לא נחשף בעבר?
פיתחנו מודל ליניארי מה שאומר שיהיו לנו שיפועים ונקודת חיתוך אחת עם ציר ה-Y. כמה שיפועים? 5 שיפועים כמספר הפיצ'רים.
נמצה את הקבועים (5 השיפועים ונקודת החיתוך עם ציר ה-y) שמצא המודל:
# extract the coefficients from the model
# 5 slopes for 5 features
# B is the Y-intercept
(W1, W2, W3, W4, W5), B = model.get_weights()
רק כדי לקבל תחושה נחשב ידנית את המחיר הצפוי עבור דירה מסויימת בסט נתוני המבחן. זו רשומה שהאינדקס שלה 237.
# Let's pick a single record
X_test.loc[273]
beds 4 baths 2 sq__ft 2169
המחיר ששולם על הדירה בפועל הוא:
# Actual price
y_test[273]
292000
האם המודל שלנו יצליח לחזות את מחיר הדירה?
נחשב את המחיר הצפוי באמצעות הערכים שמצאנו:
# Predicted price
y_pred273 = 4 * W1 + 2 * W2 + 2169 * W3 + 0 * W4 + 1 * W5 + B
y_pred273[0]
316144
קרוב למדי.
הערכת המודל על כל הדוגמאות בקבוצת המבחן
נמצא את התחזיות עבור כל סט נתוני המבחן.
y_pred = model.predict(X_test)
מה מידת הקשר בין המחירים בקבוצת המבחן לבין התוצאות אותם חזה המודל? הקוד הבא משווה את מחירי הבתים בפועל למחירים אותם חוזה המודל.
from scipy import stats
slope, intercept, r_value, p_value, std_err = stats.linregress(y_test.values.reshape(269), y_pred.reshape(269))
idx = ['slope', 'intercept', 'r_value', 'p_value', 'std_err']
data = np.array([slope, intercept, r_value, p_value, std_err])
print(pd.DataFrame(data = data, index = idx , columns = ['values']))
values slope 5.110700e-01 intercept 1.132419e+05 r_value 6.720274e-01 p_value 1.062323e-36 std_err 3.446500e-02
- ערך r של 0.67 אומר לנו שהמודל מצליח להסביר 67% מהשונות בתוצאות.
- ערך p שואף לאפס, 1.062323e-36 מלמד שהקשר אותו מתאר המודל הוא מובהק ביותר, ואינו מקרי.
נתונים נוספים מעניינים הם השיפוע ונקודת החיתוך עם ציר ה-y של ההשוואה בין המחיר בפועל לבין המחיר הצפוי. נשרטט את שיפוע תחזית המחירים כנגד המחירים בפועל.
הפונקציה הבאה מתארת את משוואת הישר ע"פ הנתונים לעיל:
predict_line = lambda S: 5.110700e-01 * y_test + 1.132419e+05
כל מה שאנחנו צריכים זה רק 2 נקודות כדי לשרטט את הישר המתאר את תחזית המחירים :
# There exists only one straight line passing through two distinct points
two_pts_for_the_line = np.array([y_test.min(), y_test.max()])
predicted_line = predict_line(two_pts_for_the_line)
נשרטט את תחזית המחירים (באדום) כנגד המחירים בפועל (בכחול):
plt.plot(y_test, y_pred, 'b+')
plt.plot(y_test, predicted_line, c='RED')
plt.xlabel("Prices")
plt.ylabel("Predicted prices")
plt.title("Actual Vs. Predicted prices")
plt.tight_layout()
נעריך את מידת הסטייה בין התחזית למחירים בפועל:
from sklearn import metrics
print('MAE: %.2f' % metrics.mean_absolute_error(y_test, y_pred))
print('RMSE: %.2f' % np.sqrt(metrics.mean_squared_error(y_test, y_pred)))
MAE: 56353.71 RMSE: 83444.98
ככל שמדדי השגיאה MAE ו- RMSE נמוכים יותר כך ההתאמה טובה יותר. RMSE מודד את השגיאה באותן יחידות כמו הערכים שהמודל מנפק. במקרה שלנו, המודל נותן תחזיות שנמצאות בטווח של +/- 83,444$.
בקובץ המצורף למדריך ניתן למצוא את כל הקוד וגם השוואה לניתוח באמצעות ספריית sklearn
סיכום
במדריך הזה למדנו לפתח מודל של רגרסיה לינארית שתלוי במספר משתנים בלתי תלויים. מספריים ושמיים-קטגוריים. במדריכים הבאים נלמד על מודלים המשתמשים לסיווג באמצעות רגרסיה לוגיסטית ושיטות נוספות המשמשות לצורך למידת מכונה. עוד נלמד על מודלים "עמוקים" שכוללים מספר שכבות חבויות.
לכל המדריכים בנושא של למידת מכונה
אחרי שלמדנו כיצד לפתח מודלים של בינה מלאכותית תוכלו לאפשר למשתמשים רגילים להשתמש בבינה שאתם מפתחים. הממשק שדרכו אנשים בדרך כלל עובדים עם תוכנות הוא באמצעות האינטרנט. במדריך ייצוא מודל בינה מלאכותית לשימוש בדפדפן תלמדו כיצד לייצא מודלים של בינה מלאכותית מבוססי ספריית Keras לדפדפן באמצעות tensorflowjs. במדריך תוכלו לראות את הקוד בפעולה אם תגללו לתחתית הדף.
אהבתם? לא אהבתם? דרגו!
0 הצבעות, ממוצע 0 מתוך 5 כוכבים
המדריכים באתר עוסקים בנושאי תכנות ופיתוח אישי. הקוד שמוצג משמש להדגמה ולצרכי לימוד. התוכן והקוד המוצגים באתר נבדקו בקפידה ונמצאו תקינים. אבל ייתכן ששימוש במערכות שונות, דוגמת דפדפן או מערכת הפעלה שונה ולאור השינויים הטכנולוגיים התכופים בעולם שבו אנו חיים יגרום לתוצאות שונות מהמצופה. בכל מקרה, אין בעל האתר נושא באחריות לכל שיבוש או שימוש לא אחראי בתכנים הלימודיים באתר.
למרות האמור לעיל, ומתוך רצון טוב, אם נתקלת בקשיים ביישום הקוד באתר מפאת מה שנראה לך כשגיאה או כחוסר עקביות נא להשאיר תגובה עם פירוט הבעיה באזור התגובות בתחתית המדריכים. זה יכול לעזור למשתמשים אחרים שנתקלו באותה בעיה ואם אני רואה שהבעיה עקרונית אני עשוי לערוך התאמה במדריך או להסיר אותו כדי להימנע מהטעיית הציבור.
שימו לב! הסקריפטים במדריכים מיועדים למטרות לימוד בלבד. כשאתם עובדים על הפרויקטים שלכם אתם צריכים להשתמש בספריות וסביבות פיתוח מוכחות, מהירות ובטוחות.
המשתמש באתר צריך להיות מודע לכך שאם וכאשר הוא מפתח קוד בשביל פרויקט הוא חייב לשים לב ולהשתמש בסביבת הפיתוח המתאימה ביותר, הבטוחה ביותר, היעילה ביותר וכמובן שהוא צריך לבדוק את הקוד בהיבטים של יעילות ואבטחה. מי אמר שלהיות מפתח זו עבודה קלה ?
השימוש שלך באתר מהווה ראייה להסכמתך עם הכללים והתקנות שנוסחו בהסכם תנאי השימוש.