# Побудова регресійної моделі з використанням Scikit-learn: регресія чотирма способами ## Примітка для початківців Лінійна регресія використовується, коли ми хочемо передбачити **числове значення** (наприклад, ціну будинку, температуру або продажі). Вона працює, знаходячи пряму, яка найкраще відображає зв’язок між вхідними ознаками й виходом. У цьому уроці ми зосереджуємося на розумінні концепції перед тим, як вивчати більш просунуті методи регресії. ![Linear vs polynomial regression infographic](../../../../translated_images/uk/linear-polynomial.5523c7cb6576ccab.webp) > Інфографіка від [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. Тепер ви готові заглибитися в регресію для машинного навчання (ML). Візуалізація допомагає зрозуміти дані, але справжня сила машинного навчання полягає у _навчанні моделей_. Моделі тренуються на історичних даних, щоб автоматично вловлювати залежності в даних і дозволяють робити прогнози для нових даних, які модель раніше не бачила. У цьому уроці ви дізнаєтесь більше про два типи регресії: _базова лінійна регресія_ та _поліноміальна регресія_, а також про математику, що лежить в основі цих методів. Ці моделі дозволять нам передбачати ціни на гарбузи залежно від різних вхідних даних. [![ML for beginners - Understanding Linear Regression](https://img.youtube.com/vi/CRxFT8oTDMg/0.jpg)](https://youtu.be/CRxFT8oTDMg "ML for beginners - Understanding Linear Regression") > 🎥 Натисніть на зображення вище, щоб переглянути коротке відеоогляд лінійної регресії. > Протягом цього курсу ми припускаємо мінімальні знання математики і прагнемо зробити матеріал доступним для студентів з різних галузей, тому звертайте увагу на примітки, 🧮 позначки, діаграми та інші інструменти навчання, які допоможуть зрозуміти матеріал. ### Вимоги Ви вже знайомі зі структурою даних про гарбузи, які ми досліджуємо. Ви можете знайти їх завантаженими та попередньо очищеними у файлі цього уроку _notebook.ipynb_. У файлі ціна гарбуза відображається за бушель у новому фреймі даних. Переконайтеся, що ви можете запускати ці ноутбуки у Visual Studio Code. ### Підготовка Нагадаємо, ви завантажуєте ці дані, щоб ставити питання. - Коли найкращий час купувати гарбузи? - Яку ціну можна очікувати за коробку мініатюрних гарбузів? - Чи варто купувати їх у кошиках на півбушеля, чи в коробках на 1 1/9 бушеля? Продовжимо копатися в цих даних. У попередньому уроці ви створили Pandas DataFrame і заповнили його частиною оригінального набору даних, стандартизуючи ціни за бушель. Проте таким чином вдалося зібрати лише близько 400 точок даних і тільки за осінні місяці. Ознайомтеся з даними, які ми завантажили у супровідному ноутбуці цього уроку. Дані завантажені, і початковий розсіювальний графік відображає дані за місяцями. Можливо, ми зможемо дізнатися більше про природу даних, очистивши їх більш ретельно. ## Лінійна регресійна лінія Як ви дізналися в уроці 1, мета лінійної регресійної вправи — побудувати лінію, щоб: - **Показати залежності змінних.** Відобразити зв’язок між змінними - **Зробити прогнози.** Робити точні прогнози про те, де нова точка даних розміститься відносно цієї лінії Зазвичай для цього використовується **регресія найменших квадратів (Least-Squares Regression)**. Термін «найменших квадратів» означає процес мінімізації загальної похибки в нашій моделі. Для кожної точки даних ми вимірюємо вертикальну відстань (результат, який називається залишком) між фактичною точкою та нашою регресійною лінією. Ми підносимо ці відстані у квадрат з двох основних причин: 1. **Величина важливіша за напрямок:** Хочемо, щоб похибка -5 розглядалася так само, як і +5. Квадрат робить всі значення позитивними. 2. **Штрафування викидів:** Квадрат надає більшу вагу великим похибкам, що змушує лінію ближче підходити до точок, які розташовані далеко. Потім ми складаємо всі ці квадрати. Наша мета — знайти лінію, де ця сума квадратичних відхилень буде найменшою (мінімальною) — звідси й назва «найменших квадратів». > **🧮 Покажіть мені математику** > Цю лінію, яку називають _лінією найкращого прилягання_, можна подати за допомогою [рівняння](https://en.wikipedia.org/wiki/Simple_linear_regression): > > ``` > Y = a + bX > ``` > > `X` — 'пояснювальна змінна', `Y` — 'залежна змінна'. Кут нахилу лінії — `b`, а `a` — це перетин з віссю Y, тобто значення `Y`, коли `X = 0`. > >![calculate the slope](../../../../translated_images/uk/slope.f3c9d5910ddbfcf9.webp) > > Спершу обчислюємо нахил `b`. Інфографіка від [Jen Looper](https://twitter.com/jenlooper) > > Іншими словами, у нашому прикладі з гарбузами, де треба "передбачити ціну гарбуза за бушель залежно від місяця", `X` — це ціна, а `Y` — місяць продажу. > >![complete the equation](../../../../translated_images/uk/calculation.a209813050a1ddb1.webp) > > Обчисліть значення 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. За допомогою розсіювального графіку ви можете швидко побачити цей коефіцієнт. Якщо точки показані впорядковано уздовж лінії, кореляція висока, якщо розкидані хаотично — кореляція низька. Добрий лінійний регресійний модель — це та, у якої коефіцієнт кореляції високо (ближче до 1, ніж до 0) і з використанням методу найменших квадратів із регресійною лінією. ✅ Запустіть ноутбук, що супроводжує цей урок, та подивіться на розсіювальний графік "Місяць - Ціна". Чи виглядає, що дані, що зв’язують місяць і ціну продажу гарбузів, мають високу чи низьку кореляцію згідно з вашим візуальним аналізом графіка? Чи зміниться це, якщо використати більш детальний показник замість `Month`, наприклад, *день року* (число днів від початку року)? У наведеному нижче коді ми припускаємо, що дані були очищені і отримано DataFrame з назвою `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`](notebook.ipynb). Ми виконали ті самі кроки очищення, що й у попередньому уроці, і обчислили стовпець `DayOfYear` за допомогою такого виразу: ```python day_of_year = pd.to_datetime(pumpkins['Date']).apply(lambda dt: (dt-datetime(dt.year,1,1)).days) ``` Тепер, коли ви маєте уявлення про математику лінійної регресії, давайте створимо регресійну модель, щоб побачити, чи можемо ми передбачити, яка упаковка гарбузів матиме найкращі ціни. Хтось, хто купує гарбузи для осіннього ярмарку, може хотіти цю інформацію, щоб оптимізувати свої покупки. ## Пошук кореляції [![ML for beginners - Looking for Correlation: The Key to Linear Regression](https://img.youtube.com/vi/uoRq-lW2eQo/0.jpg)](https://youtu.be/uoRq-lW2eQo "ML for beginners - Looking for Correlation: The Key to Linear Regression") > 🎥 Натисніть на зображення вище, щоб переглянути коротке відео про кореляцію. Із попереднього уроку ви, мабуть, бачили, що середня ціна по місяцях виглядає так: Average price by month Це підказує, що повинна бути певна кореляція, і ми можемо спробувати навчити модель лінійної регресії для прогнозу зв’язку між `Month` і `Price`, або між `DayOfYear` і `Price`. Ось розсіювальний графік для останнього зв’язку: Scatter plot of Price vs. Day of Year Поглянемо, чи є кореляція, використовуючи функцію `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` в функцію `scatter`, ми можемо відобразити всі точки на одному графіку: ```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) ``` Scatter plot of Price vs. Day of Year Наше дослідження свідчить про те, що сорт має більший вплив на загальну ціну, ніж фактична дата продажу. Це можна бачити на стовпчиковій діаграмі: ```python new_pumpkins.groupby('Variety')['Price'].mean().plot(kind='bar') ``` Bar graph of price vs variety Зараз зосередимося лише на одному сорті гарбуза, 'pie type', і подивимось, який вплив має дата на ціну: ```python pie_pumpkins = new_pumpkins[new_pumpkins['Variety']=='PIE TYPE'] pie_pumpkins.plot.scatter('DayOfYear','Price') ``` Scatter plot of Price vs. Day of Year Якщо тепер порахувати кореляцію між `Price` і `DayOfYear` за допомогою функції `corr`, отримаємо приблизно `-0.27` — це означає, що навчання прогнозної моделі має сенс. > Перед тим, як навчати лінійну регресійну модель, важливо переконатися, що дані чисті. Лінійна регресія погано працює з пропущеними значеннями, тому має сенс позбутися порожніх клітинок: ```python pie_pumpkins.dropna(inplace=True) pie_pumpkins.info() ``` Іншим підходом може бути заповнення порожніх значень середніми значеннями стовпця. ## Проста лінійна регресія [![ML for beginners - Linear and Polynomial Regression using Scikit-learn](https://img.youtube.com/vi/e4c_UP2fSjg/0.jpg)](https://youtu.be/e4c_UP2fSjg "ML for beginners - Linear and Polynomial Regression using 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` до вхідних даних, щоб пакет лінійної регресії правильно їх сприйняв. Лінійна регресія очікує 2D-масив на вході, де кожен рядок — це вектор вхідних ознак. В нашому випадку, оскільки вхідна ознака лише одна, потрібен масив розміру N×1, де N — розмір набору даних. Далі потрібно розділити дані на навчальний (train) та тестовий (test) набори, щоб можна було перевірити модель після навчання: ```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`, що вказує на ціну на початку року. Щоб побачити, наскільки точна наша модель, ми можемо передбачити ціни на тестовому наборі даних, а потім виміряти, наскільки близькі наші прогнози до очікуваних значень. Це можна зробити за допомогою метрики кореня середньоквадратичної помилки (RMSE), яка є коренем середнього значення всіх квадратів різниці між очікуваним і передбаченим значеннями. ```python pred = lin_reg.predict(X_test) rmse = np.sqrt(mean_squared_error(y_test,pred)) print(f'RMSE: {rmse:3.3} ({rmse/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) ``` Linear regression ## Поліноміальна регресія Інший тип лінійної регресії — це поліноміальна регресія. Хоча іноді між змінними існує лінійний зв’язок — чим більша гарбуз за обсягом, тим вища ціна — іноді такі зв’язки не можна відобразити у вигляді площини чи прямої лінії. ✅ Ось [декілька інших прикладів](https://online.stat.psu.edu/stat501/lesson/9/9.8) даних, які можуть потребувати поліноміальної регресії. Подивіться ще раз на зв’язок між датою та ціною. Чи цього розсіювання досить, щоб його обов’язково слід аналізувати прямою лінією? А чи не можуть ціни коливатися? У такому разі можна спробувати поліноміальну регресію. ✅ Поліноми — це математичні вирази, які можуть складатися з однієї чи кількох змінних і коефіцієнтів. Поліноміальна регресія створює криву лінію, щоб краще підходити нелінійним даним. У нашому випадку, якщо включити змінну `DayOfYear` у квадраті в вхідні дані, ми зможемо апроксимувати наші дані параболою, що має мінімум у певній точці року. Scikit-learn має корисний [pipeline API](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.make_pipeline.html?highlight=pipeline#sklearn.pipeline.make_pipeline) для об’єднання різних кроків обробки даних. **Pipeline** — це ланцюжок **оцінювачів**. У нашому випадку ми створимо 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`2, але якщо є дві вхідні змінні X і Y, додадуться X2, XY і Y2. Ми також можемо використати поліноми вищого ступеня, якщо хочемо. Pipeline можна використовувати так само, як і оригінальний об'єкт `LinearRegression`, тобто ми можемо `fit` pipeline, а потім викликати `predict` для отримання прогнозів. Ось графік, що показує тестові дані та криву апроксимації: Polynomial regression За допомогою поліноміальної регресії ми можемо отримати дещо нижче MSE та вищий коефіцієнт детермінації, але не суттєво. Потрібно враховувати інші ознаки! > Ви бачите, що мінімальні ціни на гарбузи спостерігаються десь біля Геловіну. Як це можна пояснити? 🎃 Вітаємо, ви щойно створили модель, яка може допомогти передбачити ціну гарбузів для пирогів. Ймовірно, ви можете повторити цю процедуру для всіх типів гарбузів, але це було б нудно. Давайте навчимося враховувати сорт гарбуза в нашій моделі! ## Категоріальні ознаки В ідеальному світі ми хочемо передбачати ціни для різних сортів гарбузів за допомогою однієї моделі. Однак стовпець `Variety` дещо відрізняється від стовпців на кшталт `Month`, тому що містить нечислові значення. Такі стовпці називаються **категоріальними**. [![ML для початківців - передбачення з категоріальними ознаками за допомогою лінійної регресії](https://img.youtube.com/vi/DYGliioIAE0/0.jpg)](https://youtu.be/DYGliioIAE0 "ML для початківців - передбачення з категоріальними ознаками за допомогою лінійної регресії") > 🎥 Натисніть на зображення вище для короткого відеоогляду використання категоріальних ознак. Тут ви бачите, як середня ціна залежить від сорту: Average price by variety Щоб врахувати сорт, спочатку потрібно перетворити його у числову форму, або **закодувати**. Є кілька способів це зробити: * Просте **числове кодування** створює таблицю різних сортів, а потім замінює назву сорту індексом у цій таблиці. Це не найкраща ідея для лінійної регресії, оскільки регресія бере фактичне числове значення індексу і додає його до результату, множачи на коефіцієнт. У нашому випадку залежність між номером індексу і ціною очевидно нелінійна, навіть якщо впорядкувати індекси певним чином. * **One-hot кодування** замінить стовпець `Variety` на 4 різні стовпці — по одному для кожного сорту. Кожен стовпець міститиме `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'] ``` Решта коду така сама, як і вище для навчання лінійної регресії. Якщо спробувати, побачите, що середньоквадратична помилка приблизно така ж, але коефіцієнт детермінації значно вищий (~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` і тип упаковки `Package`, що дає нам MSE = 2.84 (10%) і коефіцієнт детермінації 0.94! ## Підсумовуємо Щоб створити найкращу модель, ми можемо використовувати комбіновані (one-hot закодовані категоріальні + числові) дані з вищенаведеного прикладу разом з поліноміальною регресією. Ось повний код для вашої зручності: ```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'] # зробити розподіл на навчальну та тестову вибірки X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0) # налаштувати та навчити конвеєр pipeline = make_pipeline(PolynomialFeatures(2), LinearRegression()) pipeline.fit(X_train,y_train) # передбачити результати для тестових даних pred = pipeline.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}%)') 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/) ## Огляд та самостійне вивчення В цьому уроці ми вивчили лінійну регресію. Існують також інші важливі типи регресії. Прочитайте про крокову, Ridge, Lasso та Elasticnet техніки. Хорошим курсом для поглибленого вивчення є [Stanford Statistical Learning course](https://online.stanford.edu/courses/sohs-ystatslearning-statistical-learning) ## Завдання [Побудуйте модель](assignment.md) --- **Відмова від відповідальності**: Цей документ було перекладено за допомогою сервісу автоматичного перекладу [Co-op Translator](https://github.com/Azure/co-op-translator). Хоча ми прагнемо до точності, будь ласка, майте на увазі, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ рідною мовою слід вважати авторитетним джерелом. Для критичної інформації рекомендується професійний людський переклад. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникли внаслідок використання цього перекладу.