|
|
<!--
|
|
|
CO_OP_TRANSLATOR_METADATA:
|
|
|
{
|
|
|
"original_hash": "40e64f004f3cb50aa1d8661672d3cd92",
|
|
|
"translation_date": "2025-09-05T18:39:01+00:00",
|
|
|
"source_file": "2-Regression/3-Linear/README.md",
|
|
|
"language_code": "he"
|
|
|
}
|
|
|
-->
|
|
|
# בניית מודל רגרסיה באמצעות Scikit-learn: רגרסיה בארבע דרכים
|
|
|
|
|
|

|
|
|
> אינפוגרפיקה מאת [Dasani Madipalli](https://twitter.com/dasani_decoded)
|
|
|
## [מבחן מקדים להרצאה](https://ff-quizzes.netlify.app/en/ml/)
|
|
|
|
|
|
> ### [השיעור הזה זמין גם ב-R!](../../../../2-Regression/3-Linear/solution/R/lesson_3.html)
|
|
|
### הקדמה
|
|
|
|
|
|
עד כה חקרתם מהי רגרסיה עם נתוני דוגמה שנאספו ממאגר נתוני מחירי דלעת, אותו נשתמש לאורך השיעור הזה. כמו כן, ביצעתם ויזואליזציה של הנתונים באמצעות Matplotlib.
|
|
|
|
|
|
עכשיו אתם מוכנים לצלול לעומק הרגרסיה עבור למידת מכונה. בעוד שויזואליזציה מאפשרת להבין את הנתונים, הכוח האמיתי של למידת מכונה מגיע מ_אימון מודלים_. מודלים מאומנים על נתונים היסטוריים כדי ללכוד באופן אוטומטי תלות בין נתונים, ומאפשרים לכם לחזות תוצאות עבור נתונים חדשים שהמודל לא ראה קודם.
|
|
|
|
|
|
בשיעור הזה תלמדו יותר על שני סוגי רגרסיה: _רגרסיה לינארית בסיסית_ ו_רגרסיה פולינומית_, יחד עם מעט מתמטיקה שמאחורי הטכניקות הללו. מודלים אלו יאפשרו לנו לחזות מחירי דלעת בהתאם לנתוני קלט שונים.
|
|
|
|
|
|
[](https://youtu.be/CRxFT8oTDMg "למידת מכונה למתחילים - הבנת רגרסיה לינארית")
|
|
|
|
|
|
> 🎥 לחצו על התמונה למעלה לצפייה בסרטון קצר על רגרסיה לינארית.
|
|
|
|
|
|
> לאורך הקורס הזה, אנו מניחים ידע מתמטי מינימלי, ושואפים להפוך אותו לנגיש לסטודנטים שמגיעים מתחומים אחרים. שימו לב להערות, 🧮 קריאות, דיאגרמות וכלים אחרים שיעזרו בהבנה.
|
|
|
|
|
|
### דרישות מקדימות
|
|
|
|
|
|
כעת אתם אמורים להיות מוכנים עם מבנה נתוני הדלעת שאנו בוחנים. תוכלו למצוא אותו טעון מראש ומנוקה בקובץ _notebook.ipynb_ של השיעור הזה. בקובץ, מחיר הדלעת מוצג לפי יחידת bushel במסגרת נתונים חדשה. ודאו שאתם יכולים להריץ את המחברות הללו ב-kernels ב-Visual Studio Code.
|
|
|
|
|
|
### הכנה
|
|
|
|
|
|
כתזכורת, אתם טוענים את הנתונים הללו כדי לשאול שאלות לגביהם.
|
|
|
|
|
|
- מתי הזמן הטוב ביותר לקנות דלעות?
|
|
|
- איזה מחיר אני יכול לצפות עבור מארז של דלעות מיניאטוריות?
|
|
|
- האם כדאי לי לקנות אותן בסלים של חצי bushel או בקופסאות של 1 1/9 bushel?
|
|
|
בואו נמשיך לחקור את הנתונים הללו.
|
|
|
|
|
|
בשיעור הקודם יצרתם מסגרת נתונים של Pandas ומילאתם אותה עם חלק ממאגר הנתונים המקורי, תוך סטנדרטיזציה של המחירים לפי bushel. עם זאת, על ידי כך הצלחתם לאסוף רק כ-400 נקודות נתונים ורק עבור חודשי הסתיו.
|
|
|
|
|
|
הסתכלו על הנתונים שטעונים מראש במחברת המצורפת לשיעור הזה. הנתונים טעונים מראש וגרף פיזור ראשוני מוצג כדי להראות נתוני חודשים. אולי נוכל לקבל מעט יותר פרטים על טיב הנתונים על ידי ניקוי נוסף שלהם.
|
|
|
|
|
|
## קו רגרסיה לינארית
|
|
|
|
|
|
כפי שלמדתם בשיעור הראשון, המטרה של תרגיל רגרסיה לינארית היא להיות מסוגלים לשרטט קו כדי:
|
|
|
|
|
|
- **להראות קשרים בין משתנים**. להראות את הקשר בין משתנים
|
|
|
- **לבצע תחזיות**. לבצע תחזיות מדויקות על מיקום נקודת נתונים חדשה ביחס לקו הזה.
|
|
|
|
|
|
זה אופייני ל**רגרסיית ריבועים קטנים** לשרטט סוג כזה של קו. המונח 'ריבועים קטנים' מתייחס לכך שכל נקודות הנתונים שמסביב לקו הרגרסיה מרובעות ואז מסוכמות. באופן אידיאלי, הסכום הסופי הזה הוא קטן ככל האפשר, מכיוון שאנו רוצים מספר נמוך של שגיאות, או `ריבועים קטנים`.
|
|
|
|
|
|
אנו עושים זאת מכיוון שאנו רוצים לדגם קו שיש לו את המרחק המצטבר הקטן ביותר מכל נקודות הנתונים שלנו. אנו גם מרבעים את המונחים לפני הסכימה מכיוון שאנו מתמקדים בגודל שלהם ולא בכיוונם.
|
|
|
|
|
|
> **🧮 תראו לי את המתמטיקה**
|
|
|
>
|
|
|
> הקו הזה, שנקרא _קו ההתאמה הטוב ביותר_, יכול להיות מבוטא על ידי [משוואה](https://en.wikipedia.org/wiki/Simple_linear_regression):
|
|
|
>
|
|
|
> ```
|
|
|
> Y = a + bX
|
|
|
> ```
|
|
|
>
|
|
|
> `X` הוא המשתנה המסביר. `Y` הוא המשתנה התלוי. השיפוע של הקו הוא `b` ו-`a` הוא נקודת החיתוך עם ציר ה-Y, שמתייחסת לערך של `Y` כאשר `X = 0`.
|
|
|
>
|
|
|
>
|
|
|
>
|
|
|
> ראשית, חשבו את השיפוע `b`. אינפוגרפיקה מאת [Jen Looper](https://twitter.com/jenlooper)
|
|
|
>
|
|
|
> במילים אחרות, בהתייחס לשאלת הנתונים המקורית שלנו על דלעות: "חיזוי מחיר דלעת לפי bushel לפי חודש", `X` יתייחס למחיר ו-`Y` יתייחס לחודש המכירה.
|
|
|
>
|
|
|
>
|
|
|
>
|
|
|
> חשבו את הערך של Y. אם אתם משלמים בסביבות $4, זה חייב להיות אפריל! אינפוגרפיקה מאת [Jen Looper](https://twitter.com/jenlooper)
|
|
|
>
|
|
|
> המתמטיקה שמחשבת את הקו חייבת להראות את השיפוע של הקו, שתלוי גם בנקודת החיתוך, או היכן ש-`Y` ממוקם כאשר `X = 0`.
|
|
|
>
|
|
|
> תוכלו לצפות בשיטת החישוב לערכים הללו באתר [Math is Fun](https://www.mathsisfun.com/data/least-squares-regression.html). כמו כן, בקרו ב[מחשבון ריבועים קטנים](https://www.mathsisfun.com/data/least-squares-calculator.html) כדי לראות כיצד ערכי המספרים משפיעים על הקו.
|
|
|
|
|
|
## מתאם
|
|
|
|
|
|
מונח נוסף שחשוב להבין הוא **מקדם המתאם** בין משתני X ו-Y נתונים. באמצעות גרף פיזור, תוכלו לראות במהירות את מקדם המתאם. גרף עם נקודות נתונים מפוזרות בקו מסודר יש לו מתאם גבוה, אבל גרף עם נקודות נתונים מפוזרות בכל מקום בין X ל-Y יש לו מתאם נמוך.
|
|
|
|
|
|
מודל רגרסיה לינארית טוב יהיה כזה שיש לו מקדם מתאם גבוה (קרוב יותר ל-1 מאשר ל-0) באמצעות שיטת רגרסיית ריבועים קטנים עם קו רגרסיה.
|
|
|
|
|
|
✅ הריצו את המחברת המצורפת לשיעור הזה והסתכלו על גרף הפיזור של חודש מול מחיר. האם הנתונים שמקשרים בין חודש למחיר עבור מכירות דלעת נראים בעלי מתאם גבוה או נמוך, לפי הפרשנות הוויזואלית שלכם לגרף הפיזור? האם זה משתנה אם אתם משתמשים במדד מדויק יותר במקום `חודש`, למשל *יום בשנה* (כלומר מספר הימים מתחילת השנה)?
|
|
|
|
|
|
בקוד למטה, נניח שניקינו את הנתונים וקיבלנו מסגרת נתונים בשם `new_pumpkins`, דומה לזו הבאה:
|
|
|
|
|
|
ID | Month | DayOfYear | Variety | City | Package | Low Price | High Price | Price
|
|
|
---|-------|-----------|---------|------|---------|-----------|------------|-------
|
|
|
70 | 9 | 267 | PIE TYPE | BALTIMORE | 1 1/9 bushel cartons | 15.0 | 15.0 | 13.636364
|
|
|
71 | 9 | 267 | PIE TYPE | BALTIMORE | 1 1/9 bushel cartons | 18.0 | 18.0 | 16.363636
|
|
|
72 | 10 | 274 | PIE TYPE | BALTIMORE | 1 1/9 bushel cartons | 18.0 | 18.0 | 16.363636
|
|
|
73 | 10 | 274 | PIE TYPE | BALTIMORE | 1 1/9 bushel cartons | 17.0 | 17.0 | 15.454545
|
|
|
74 | 10 | 281 | PIE TYPE | BALTIMORE | 1 1/9 bushel cartons | 15.0 | 15.0 | 13.636364
|
|
|
|
|
|
> הקוד לניקוי הנתונים זמין ב-[`notebook.ipynb`](../../../../2-Regression/3-Linear/notebook.ipynb). ביצענו את אותם שלבי ניקוי כמו בשיעור הקודם, וחישבנו את עמודת `DayOfYear` באמצעות הביטוי הבא:
|
|
|
|
|
|
```python
|
|
|
day_of_year = pd.to_datetime(pumpkins['Date']).apply(lambda dt: (dt-datetime(dt.year,1,1)).days)
|
|
|
```
|
|
|
|
|
|
עכשיו כשיש לכם הבנה של המתמטיקה שמאחורי רגרסיה לינארית, בואו ניצור מודל רגרסיה כדי לראות אם נוכל לחזות איזה מארז דלעות יציע את המחירים הטובים ביותר. מישהו שקונה דלעות עבור חוות דלעות לחג עשוי לרצות את המידע הזה כדי לייעל את רכישותיו של מארזי דלעות לחווה.
|
|
|
|
|
|
## חיפוש מתאם
|
|
|
|
|
|
[](https://youtu.be/uoRq-lW2eQo "למידת מכונה למתחילים - חיפוש מתאם: המפתח לרגרסיה לינארית")
|
|
|
|
|
|
> 🎥 לחצו על התמונה למעלה לצפייה בסרטון קצר על מתאם.
|
|
|
|
|
|
מהשיעור הקודם כנראה ראיתם שהמחיר הממוצע עבור חודשים שונים נראה כך:
|
|
|
|
|
|
<img alt="מחיר ממוצע לפי חודש" src="../2-Data/images/barchart.png" width="50%"/>
|
|
|
|
|
|
זה מציע שיכול להיות מתאם, ואנו יכולים לנסות לאמן מודל רגרסיה לינארית כדי לחזות את הקשר בין `Month` ל-`Price`, או בין `DayOfYear` ל-`Price`. הנה גרף הפיזור שמראה את הקשר האחרון:
|
|
|
|
|
|
<img alt="גרף פיזור של מחיר מול יום בשנה" src="images/scatter-dayofyear.png" width="50%" />
|
|
|
|
|
|
בואו נראה אם יש מתאם באמצעות פונקציית `corr`:
|
|
|
|
|
|
```python
|
|
|
print(new_pumpkins['Month'].corr(new_pumpkins['Price']))
|
|
|
print(new_pumpkins['DayOfYear'].corr(new_pumpkins['Price']))
|
|
|
```
|
|
|
|
|
|
נראה שהמתאם די קטן, -0.15 לפי `Month` ו- -0.17 לפי `DayOfMonth`, אבל יכול להיות קשר חשוב אחר. נראה שיש קבוצות שונות של מחירים שמקבילות לזני דלעות שונים. כדי לאשר את ההשערה הזו, בואו נשרטט כל קטגוריית דלעות בצבע שונה. על ידי העברת פרמטר `ax` לפונקציית גרף הפיזור, נוכל לשרטט את כל הנקודות על אותו גרף:
|
|
|
|
|
|
```python
|
|
|
ax=None
|
|
|
colors = ['red','blue','green','yellow']
|
|
|
for i,var in enumerate(new_pumpkins['Variety'].unique()):
|
|
|
df = new_pumpkins[new_pumpkins['Variety']==var]
|
|
|
ax = df.plot.scatter('DayOfYear','Price',ax=ax,c=colors[i],label=var)
|
|
|
```
|
|
|
|
|
|
<img alt="גרף פיזור של מחיר מול יום בשנה" src="images/scatter-dayofyear-color.png" width="50%" />
|
|
|
|
|
|
החקירה שלנו מציעה שלזן יש השפעה גדולה יותר על המחיר הכולל מאשר תאריך המכירה בפועל. אנו יכולים לראות זאת עם גרף עמודות:
|
|
|
|
|
|
```python
|
|
|
new_pumpkins.groupby('Variety')['Price'].mean().plot(kind='bar')
|
|
|
```
|
|
|
|
|
|
<img alt="גרף עמודות של מחיר מול זן" src="images/price-by-variety.png" width="50%" />
|
|
|
|
|
|
בואו נתמקד לרגע רק בזן אחד של דלעות, 'סוג פאי', ונראה מה ההשפעה של התאריך על המחיר:
|
|
|
|
|
|
```python
|
|
|
pie_pumpkins = new_pumpkins[new_pumpkins['Variety']=='PIE TYPE']
|
|
|
pie_pumpkins.plot.scatter('DayOfYear','Price')
|
|
|
```
|
|
|
<img alt="גרף פיזור של מחיר מול יום בשנה" src="images/pie-pumpkins-scatter.png" width="50%" />
|
|
|
|
|
|
אם עכשיו נחשב את המתאם בין `Price` ל-`DayOfYear` באמצעות פונקציית `corr`, נקבל משהו כמו `-0.27` - מה שאומר שאימון מודל חיזוי הגיוני.
|
|
|
|
|
|
> לפני אימון מודל רגרסיה לינארית, חשוב לוודא שהנתונים שלנו נקיים. רגרסיה לינארית לא עובדת טוב עם ערכים חסרים, ולכן הגיוני להיפטר מכל התאים הריקים:
|
|
|
|
|
|
```python
|
|
|
pie_pumpkins.dropna(inplace=True)
|
|
|
pie_pumpkins.info()
|
|
|
```
|
|
|
|
|
|
גישה נוספת תהיה למלא את הערכים הריקים בערכים ממוצעים מהעמודה המתאימה.
|
|
|
|
|
|
## רגרסיה לינארית פשוטה
|
|
|
|
|
|
[](https://youtu.be/e4c_UP2fSjg "למידת מכונה למתחילים - רגרסיה לינארית ופולינומית באמצעות Scikit-learn")
|
|
|
|
|
|
> 🎥 לחצו על התמונה למעלה לצפייה בסרטון קצר על רגרסיה לינארית ופולינומית.
|
|
|
|
|
|
כדי לאמן את מודל הרגרסיה הלינארית שלנו, נשתמש בספריית **Scikit-learn**.
|
|
|
|
|
|
```python
|
|
|
from sklearn.linear_model import LinearRegression
|
|
|
from sklearn.metrics import mean_squared_error
|
|
|
from sklearn.model_selection import train_test_split
|
|
|
```
|
|
|
|
|
|
נתחיל בהפרדת ערכי הקלט (תכונות) והתוצאה הצפויה (תווית) למערכים נפרדים של numpy:
|
|
|
|
|
|
```python
|
|
|
X = pie_pumpkins['DayOfYear'].to_numpy().reshape(-1,1)
|
|
|
y = pie_pumpkins['Price']
|
|
|
```
|
|
|
|
|
|
> שימו לב שהיינו צריכים לבצע `reshape` על נתוני הקלט כדי שחבילת הרגרסיה הלינארית תבין אותם נכון. רגרסיה לינארית מצפה למערך דו-ממדי כקלט, שבו כל שורה במערך מתאימה לווקטור של תכונות קלט. במקרה שלנו, מכיוון שיש לנו רק קלט אחד - אנו צריכים מערך עם צורה N×1, כאשר N הוא גודל מאגר הנתונים.
|
|
|
|
|
|
לאחר מכן, אנו צריכים לחלק את הנתונים למאגרי אימון ובדיקה, כך שנוכל לאמת את המודל שלנו לאחר האימון:
|
|
|
|
|
|
```python
|
|
|
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
|
|
|
```
|
|
|
|
|
|
לבסוף, אימון מודל הרגרסיה הלינארית עצמו לוקח רק שתי שורות קוד. אנו מגדירים את אובייקט `LinearRegression`, ומתאימים אותו לנתונים שלנו באמצעות שיטת `fit`:
|
|
|
|
|
|
```python
|
|
|
lin_reg = LinearRegression()
|
|
|
lin_reg.fit(X_train,y_train)
|
|
|
```
|
|
|
|
|
|
אובייקט `LinearRegression` לאחר התאמה (`fit`) מכיל את כל המקדמים של הרגרסיה, שניתן לגשת אליהם באמצעות תכונת `.coef_`. במקרה שלנו, יש רק מקדם אחד, שאמור להיות בסביבות `-0.017`. זה אומר שהמחירים נראים כאילו הם יורדים מעט עם הזמן, אבל לא יותר מדי, בסביבות 2 סנט ליום. אנו יכולים גם לגשת לנקודת החיתוך של הרגרסיה עם ציר ה-Y באמצעות `lin_reg.intercept_` - זה יהיה בסביבות `21` במקרה שלנו, מה שמעיד על המחיר בתחילת השנה.
|
|
|
|
|
|
כדי לראות עד כמה המודל שלנו מדויק, אנו יכולים לחזות מחירים על מאגר נתוני הבדיקה, ואז למדוד עד כמה התחזיות שלנו קרובות לערכים הצפויים. ניתן לעשות זאת באמצעות מדד שגיאה ממוצעת ריבועית (MSE), שהוא הממוצע של כל ההבדלים הריבועיים בין הערך הצפוי לערך החזוי.
|
|
|
|
|
|
```python
|
|
|
pred = lin_reg.predict(X_test)
|
|
|
|
|
|
mse = np.sqrt(mean_squared_error(y_test,pred))
|
|
|
print(f'Mean error: {mse:3.3} ({mse/np.mean(pred)*100:3.3}%)')
|
|
|
```
|
|
|
נראה שהשגיאה שלנו מתרכזת סביב 2 נקודות, שזה בערך 17%. לא כל כך טוב. אינדיקטור נוסף לאיכות המודל הוא **מקדם ההחלטיות**, שניתן לחשב כך:
|
|
|
|
|
|
```python
|
|
|
score = lin_reg.score(X_train,y_train)
|
|
|
print('Model determination: ', score)
|
|
|
```
|
|
|
אם הערך הוא 0, זה אומר שהמודל לא מתחשב בנתוני הקלט ופועל כ*מנבא הליניארי הגרוע ביותר*, שהוא פשוט ממוצע של התוצאה. ערך של 1 אומר שאנחנו יכולים לנבא באופן מושלם את כל התוצאות הצפויות. במקרה שלנו, המקדם הוא בערך 0.06, שזה די נמוך.
|
|
|
|
|
|
ניתן גם לשרטט את נתוני הבדיקה יחד עם קו הרגרסיה כדי לראות טוב יותר איך הרגרסיה פועלת במקרה שלנו:
|
|
|
|
|
|
```python
|
|
|
plt.scatter(X_test,y_test)
|
|
|
plt.plot(X_test,pred)
|
|
|
```
|
|
|
|
|
|
<img alt="רגרסיה ליניארית" src="images/linear-results.png" width="50%" />
|
|
|
|
|
|
## רגרסיה פולינומית
|
|
|
|
|
|
סוג נוסף של רגרסיה ליניארית הוא רגרסיה פולינומית. בעוד שלפעמים יש קשר ליניארי בין משתנים - ככל שנפח הדלעת גדול יותר, כך המחיר גבוה יותר - לפעמים קשרים אלו לא יכולים להיות מיוצגים כמישור או כקו ישר.
|
|
|
|
|
|
✅ הנה [כמה דוגמאות נוספות](https://online.stat.psu.edu/stat501/lesson/9/9.8) לנתונים שיכולים להשתמש ברגרסיה פולינומית.
|
|
|
|
|
|
תסתכלו שוב על הקשר בין תאריך למחיר. האם פיזור הנתונים נראה כאילו הוא חייב להיות מנותח באמצעות קו ישר? האם מחירים לא יכולים להשתנות? במקרה כזה, ניתן לנסות רגרסיה פולינומית.
|
|
|
|
|
|
✅ פולינומים הם ביטויים מתמטיים שיכולים לכלול משתנה אחד או יותר ומקדמים.
|
|
|
|
|
|
רגרסיה פולינומית יוצרת קו מעוקל שמתאים טוב יותר לנתונים לא ליניאריים. במקרה שלנו, אם נכלול משתנה `DayOfYear` בריבוע בנתוני הקלט, נוכל להתאים את הנתונים שלנו לעקומה פרבולית, שתהיה לה מינימום בנקודה מסוימת במהלך השנה.
|
|
|
|
|
|
ספריית Scikit-learn כוללת [API של צינור](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.make_pipeline.html?highlight=pipeline#sklearn.pipeline.make_pipeline) שמאפשר לשלב שלבים שונים של עיבוד נתונים יחד. **צינור** הוא שרשרת של **אומדנים**. במקרה שלנו, ניצור צינור שמוסיף תחילה תכונות פולינומיות למודל שלנו, ואז מאמן את הרגרסיה:
|
|
|
|
|
|
```python
|
|
|
from sklearn.preprocessing import PolynomialFeatures
|
|
|
from sklearn.pipeline import make_pipeline
|
|
|
|
|
|
pipeline = make_pipeline(PolynomialFeatures(2), LinearRegression())
|
|
|
|
|
|
pipeline.fit(X_train,y_train)
|
|
|
```
|
|
|
|
|
|
שימוש ב-`PolynomialFeatures(2)` אומר שנכלול את כל הפולינומים מדרגה שנייה מנתוני הקלט. במקרה שלנו זה פשוט אומר `DayOfYear`<sup>2</sup>, אבל אם ישנם שני משתני קלט X ו-Y, זה יוסיף X<sup>2</sup>, XY ו-Y<sup>2</sup>. ניתן גם להשתמש בפולינומים מדרגה גבוהה יותר אם רוצים.
|
|
|
|
|
|
ניתן להשתמש בצינורות באותו אופן כמו באובייקט `LinearRegression` המקורי, כלומר ניתן להשתמש ב-`fit` בצינור ואז ב-`predict` כדי לקבל את תוצאות הניבוי. הנה הגרף שמראה את נתוני הבדיקה ואת עקומת הקירוב:
|
|
|
|
|
|
<img alt="רגרסיה פולינומית" src="images/poly-results.png" width="50%" />
|
|
|
|
|
|
שימוש ברגרסיה פולינומית מאפשר לנו לקבל MSE מעט נמוך יותר ומקדם החלטיות גבוה יותר, אך לא באופן משמעותי. יש לקחת בחשבון תכונות נוספות!
|
|
|
|
|
|
> ניתן לראות שהמחירים המינימליים של דלעות נצפים איפשהו סביב ליל כל הקדושים. איך אפשר להסביר את זה?
|
|
|
|
|
|
🎃 כל הכבוד, יצרתם מודל שיכול לעזור לנבא את מחיר דלעות הפאי. כנראה שתוכלו לחזור על אותו תהליך עבור כל סוגי הדלעות, אבל זה יהיה מייגע. עכשיו נלמד איך לקחת בחשבון את סוג הדלעת במודל שלנו!
|
|
|
|
|
|
## תכונות קטגוריות
|
|
|
|
|
|
בעולם האידיאלי, נרצה להיות מסוגלים לנבא מחירים עבור סוגי דלעות שונים באמצעות אותו מודל. עם זאת, העמודה `Variety` שונה במקצת מעמודות כמו `Month`, מכיוון שהיא מכילה ערכים לא מספריים. עמודות כאלה נקראות **קטגוריות**.
|
|
|
|
|
|
[](https://youtu.be/DYGliioIAE0 "ML למתחילים - ניבוי תכונות קטגוריות עם רגרסיה ליניארית")
|
|
|
|
|
|
> 🎥 לחצו על התמונה למעלה לסרטון קצר על שימוש בתכונות קטגוריות.
|
|
|
|
|
|
כאן ניתן לראות איך המחיר הממוצע תלוי בסוג הדלעת:
|
|
|
|
|
|
<img alt="מחיר ממוצע לפי סוג" src="images/price-by-variety.png" width="50%" />
|
|
|
|
|
|
כדי לקחת את סוג הדלעת בחשבון, תחילה עלינו להמיר אותו לצורה מספרית, או **לקודד** אותו. ישנן מספר דרכים לעשות זאת:
|
|
|
|
|
|
* **קידוד מספרי פשוט** יבנה טבלה של סוגי דלעות שונים, ואז יחליף את שם הסוג במספר אינדקס בטבלה. זו לא הבחירה הטובה ביותר עבור רגרסיה ליניארית, מכיוון שרגרסיה ליניארית מתחשבת בערך המספרי של האינדקס ומוסיפה אותו לתוצאה, תוך הכפלה במקדם מסוים. במקרה שלנו, הקשר בין מספר האינדקס למחיר הוא בבירור לא ליניארי, גם אם נוודא שהאינדקסים מסודרים בצורה מסוימת.
|
|
|
* **קידוד One-hot** יחליף את העמודה `Variety` בארבע עמודות שונות, אחת לכל סוג. כל עמודה תכיל `1` אם השורה המתאימה היא מסוג מסוים, ו-`0` אחרת. זה אומר שיהיו ארבעה מקדמים ברגרסיה ליניארית, אחד לכל סוג דלעת, שאחראי על "מחיר התחלתי" (או ליתר דיוק "מחיר נוסף") עבור אותו סוג מסוים.
|
|
|
|
|
|
הקוד הבא מראה איך ניתן לקודד סוג דלעת בשיטת One-hot:
|
|
|
|
|
|
```python
|
|
|
pd.get_dummies(new_pumpkins['Variety'])
|
|
|
```
|
|
|
|
|
|
ID | FAIRYTALE | MINIATURE | MIXED HEIRLOOM VARIETIES | PIE TYPE
|
|
|
----|-----------|-----------|--------------------------|----------
|
|
|
70 | 0 | 0 | 0 | 1
|
|
|
71 | 0 | 0 | 0 | 1
|
|
|
... | ... | ... | ... | ...
|
|
|
1738 | 0 | 1 | 0 | 0
|
|
|
1739 | 0 | 1 | 0 | 0
|
|
|
1740 | 0 | 1 | 0 | 0
|
|
|
1741 | 0 | 1 | 0 | 0
|
|
|
1742 | 0 | 1 | 0 | 0
|
|
|
|
|
|
כדי לאמן רגרסיה ליניארית באמצעות סוג דלעת מקודד בשיטת One-hot כקלט, פשוט צריך לאתחל את נתוני `X` ו-`y` בצורה נכונה:
|
|
|
|
|
|
```python
|
|
|
X = pd.get_dummies(new_pumpkins['Variety'])
|
|
|
y = new_pumpkins['Price']
|
|
|
```
|
|
|
|
|
|
שאר הקוד זהה למה שהשתמשנו בו קודם כדי לאמן רגרסיה ליניארית. אם תנסו זאת, תראו ש-Mean Squared Error נשאר בערך אותו דבר, אבל מקדם ההחלטיות עולה משמעותית (~77%). כדי לקבל ניבויים מדויקים יותר, ניתן לקחת בחשבון תכונות קטגוריות נוספות, כמו גם תכונות מספריות, כגון `Month` או `DayOfYear`. כדי לקבל מערך גדול של תכונות, ניתן להשתמש ב-`join`:
|
|
|
|
|
|
```python
|
|
|
X = pd.get_dummies(new_pumpkins['Variety']) \
|
|
|
.join(new_pumpkins['Month']) \
|
|
|
.join(pd.get_dummies(new_pumpkins['City'])) \
|
|
|
.join(pd.get_dummies(new_pumpkins['Package']))
|
|
|
y = new_pumpkins['Price']
|
|
|
```
|
|
|
|
|
|
כאן אנו לוקחים בחשבון גם את `City` ואת סוג האריזה, מה שמביא אותנו ל-MSE של 2.84 (10%) ולמקדם החלטיות של 0.94!
|
|
|
|
|
|
## לשלב הכל יחד
|
|
|
|
|
|
כדי ליצור את המודל הטוב ביותר, ניתן להשתמש בנתונים משולבים (קטגוריות מקודדות בשיטת One-hot + נתונים מספריים) מהדוגמה לעיל יחד עם רגרסיה פולינומית. הנה הקוד המלא לנוחיותכם:
|
|
|
|
|
|
```python
|
|
|
# set up training data
|
|
|
X = pd.get_dummies(new_pumpkins['Variety']) \
|
|
|
.join(new_pumpkins['Month']) \
|
|
|
.join(pd.get_dummies(new_pumpkins['City'])) \
|
|
|
.join(pd.get_dummies(new_pumpkins['Package']))
|
|
|
y = new_pumpkins['Price']
|
|
|
|
|
|
# make train-test split
|
|
|
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
|
|
|
|
|
|
# setup and train the pipeline
|
|
|
pipeline = make_pipeline(PolynomialFeatures(2), LinearRegression())
|
|
|
pipeline.fit(X_train,y_train)
|
|
|
|
|
|
# predict results for test data
|
|
|
pred = pipeline.predict(X_test)
|
|
|
|
|
|
# calculate MSE and determination
|
|
|
mse = np.sqrt(mean_squared_error(y_test,pred))
|
|
|
print(f'Mean error: {mse:3.3} ({mse/np.mean(pred)*100:3.3}%)')
|
|
|
|
|
|
score = pipeline.score(X_train,y_train)
|
|
|
print('Model determination: ', score)
|
|
|
```
|
|
|
|
|
|
זה אמור לתת לנו את מקדם ההחלטיות הטוב ביותר של כמעט 97%, ו-MSE=2.23 (~8% שגיאת ניבוי).
|
|
|
|
|
|
| מודל | MSE | מקדם החלטיות |
|
|
|
|-------|-----|---------------|
|
|
|
| `DayOfYear` ליניארי | 2.77 (17.2%) | 0.07 |
|
|
|
| `DayOfYear` פולינומי | 2.73 (17.0%) | 0.08 |
|
|
|
| `Variety` ליניארי | 5.24 (19.7%) | 0.77 |
|
|
|
| כל התכונות ליניארי | 2.84 (10.5%) | 0.94 |
|
|
|
| כל התכונות פולינומי | 2.23 (8.25%) | 0.97 |
|
|
|
|
|
|
🏆 כל הכבוד! יצרתם ארבעה מודלים של רגרסיה בשיעור אחד ושיפרתם את איכות המודל ל-97%. בחלק האחרון על רגרסיה תלמדו על רגרסיה לוגיסטית כדי לקבוע קטגוריות.
|
|
|
|
|
|
---
|
|
|
## 🚀אתגר
|
|
|
|
|
|
בדקו משתנים שונים במחברת זו כדי לראות איך הקורלציה משפיעה על דיוק המודל.
|
|
|
|
|
|
## [מבחן לאחר השיעור](https://ff-quizzes.netlify.app/en/ml/)
|
|
|
|
|
|
## סקירה ולימוד עצמי
|
|
|
|
|
|
בשיעור זה למדנו על רגרסיה ליניארית. ישנם סוגים חשובים נוספים של רגרסיה. קראו על טכניקות Stepwise, Ridge, Lasso ו-Elasticnet. קורס טוב ללמוד כדי להעמיק הוא [קורס הלמידה הסטטיסטית של סטנפורד](https://online.stanford.edu/courses/sohs-ystatslearning-statistical-learning).
|
|
|
|
|
|
## משימה
|
|
|
|
|
|
[בנו מודל](assignment.md)
|
|
|
|
|
|
---
|
|
|
|
|
|
**כתב ויתור**:
|
|
|
מסמך זה תורגם באמצעות שירות תרגום מבוסס בינה מלאכותית [Co-op Translator](https://github.com/Azure/co-op-translator). בעוד שאנו שואפים לדיוק, יש להיות מודעים לכך שתרגומים אוטומטיים עשויים להכיל שגיאות או אי דיוקים. המסמך המקורי בשפתו המקורית צריך להיחשב כמקור סמכותי. עבור מידע קריטי, מומלץ להשתמש בתרגום מקצועי על ידי אדם. איננו נושאים באחריות לאי הבנות או לפרשנויות שגויות הנובעות משימוש בתרגום זה. |