Skip to content

Latest commit

 

History

History
386 lines (257 loc) · 36.2 KB

File metadata and controls

386 lines (257 loc) · 36.2 KB

Побудова регресійної моделі за допомогою Scikit-learn: регресія чотирма способами

Примітка для початківців

Лінійна регресія використовується, коли ми хочемо передбачити числове значення (наприклад, ціну будинку, температуру або обсяг продажів). Вона працює, знаходячи пряму лінію, яка найкраще відображає зв’язок між вхідними ознаками та виходом.

У цьому уроці ми зосереджуємося на розумінні концепції перед тим, як дослідити більш просунуті методи регресії. Лінійна vs поліноміальна регресія інфографіка

Інфографіка від Dasani Madipalli

Вступ

До цього моменту ви досліджували, що таке регресія, використовуючи вибіркові дані з набору даних про ціни на гарбузи, який ми використовуватимемо протягом усього цього уроку. Ви також візуалізували ці дані за допомогою Matplotlib.

Тепер ви готові зануритися глибше у регресію в машинному навчанні. Хоча візуалізація допомагає зрозуміти дані, справжня сила машинного навчання полягає в навчанні моделей. Моделі навчаються на історичних даних, щоб автоматично виявляти залежності в даних, і дозволяють прогнозувати результати для нових даних, яких модель раніше не бачила.

У цьому уроці ви детальніше дізнаєтесь про два типи регресії: базова лінійна регресія та поліноміальна регресія, а також про математику, що лежить в основі цих методів. Ці моделі дозволять нам прогнозувати ціни на гарбузи залежно від різних вхідних даних.

ML для початківців - Розуміння лінійної регресії

🎥 Натисніть на зображення вище, щоб переглянути короткий відеоогляд лінійної регресії.

Протягом цього курсу ми передбачаємо мінімальні знання математики і намагаємося зробити її доступною для студентів з інших галузей, тому звертайте увагу на примітки, 🧮 підказки, діаграми та інші інструменти для полегшення розуміння.

Передумови

До цього часу ви вже маєте ознайомлення зі структурою даних про гарбузи, які ми досліджуємо. Ви можете знайти їх завантаженими та попередньо очищеними у файлі notebook.ipynb цього уроку. У файлі ціна на гарбуз подана за бушель у новому датафреймі. Переконайтесь, що ви можете запускати ці ноутбуки в ядрах у Visual Studio Code.

Підготовка

Як нагадування, ви завантажуєте ці дані, щоб ставити до них запитання.

  • Коли найкращий час купувати гарбузи?
  • Яку ціну можна очікувати за коробку мініатюрних гарбузів?
  • Чи варто купувати їх у корзинах на півбушеля або у коробках на 1 1/9 бушеля? Продовжимо досліджувати ці дані.

У попередньому уроці ви створили датафрейм Pandas і наповнили його частиною оригінального набору даних, стандартизувавши ціни за бушель. Проте при цьому ви змогли зібрати лише близько 400 точок даних і лише для осінніх місяців.

Погляньте на дані, які ми заздалегідь завантажили у супровідному ноутбуці цього уроку. Дані завантажено, і побудовано початковий графік розсіювання для показу даних по місяцях. Можливо, ми зможемо отримати трохи більше інформації про природу цих даних, очистивши їх ще більше.

Лінійна регресійна лінія

Як ви дізнались у Уроці 1, мета вправи з лінійної регресії – це можливість побудувати лінію для:

  • Показу взаємозв’язків змінних. Показати зв’язок між змінними
  • Робити прогнози. Робити точні прогнози, де нова точка даних розташується відносно цієї лінії.

Типово для регресії найменших квадратів малюють саме таку лінію. Термін "найменші квадрати" відноситься до процесу мінімізації загальної помилки в нашій моделі. Для кожної точки даних ми вимірюємо вертикальну відстань (яку називають залишком) між фактичною точкою і нашою регресійною лінією.

Ці відстані ми підносимо до квадрату з двох основних причин:

  1. Величина важливіша за напрямок: Ми хочемо поставитись до помилки -5 так само, як до помилки +5. Квадрат робить усі значення додатними.

  2. Покарання за викиди: Квадрат надає більшу вагу великим помилкам, змушуючи лінію триматися ближче до точок, які далеко розташовані.

Потім ми додаємо всі ці квадратні значення разом. Наша мета — знайти таку лінію, де ця сума буде мінімальною (найменшим можливим значенням) — звідси й назва "найменших квадратів".

🧮 Покажи математику

Цю лінію, яка називається лінією найкращого наближення, можна виразити за допомогою рівняння:

Y = a + bX

X – це "пояснювальна змінна". Y – "залежна змінна". Нахил лінії – b, а a – це y-перетин, що відображає значення Y, коли X = 0.

обчислення нахилу

Спочатку обраховуємо нахил b. Інфографіка від Jen Looper

Іншими словами, і звертаючись до нашого початкового питання з даних про гарбузи: "передбачити ціну гарбуза за бушель по місяцях", X вказує на ціну, а Y – на місяць продажу.

завершення рівняння

Обчисліть значення Y. Якщо ви платите близько 4 доларів, то це, мабуть, квітень! Інфографіка від Jen Looper

Математика, що обчислює цю лінію, має показати нахил лінії, який також залежить від перетину, тобто де знаходиться Y, коли X = 0.

Ви можете ознайомитись з методом обчислення цих значень на сайті Math is Fun. Також відвідайте цей калькулятор найменших квадратів, щоб побачити, як значення чисел впливають на лінію.

Кореляція

Ще один термін, який потрібно зрозуміти, – це коефіцієнт кореляції між заданими змінними X та Y. За допомогою графіка розсіювання ви швидко можете візуалізувати цей коефіцієнт. Якщо точки на графіку розташовані акуратно по лінії — кореляція висока, якщо розкидані по всьому графіку — кореляція низька.

Добра модель лінійної регресії матиме високий (ближчий до 1, ніж до 0) коефіцієнт кореляції, визначений методом найменших квадратів із регресійною лінією.

✅ Запустіть ноутбук, який супроводжує цей урок, і подивіться на графік розсіювання місяця продажу до ціни. Чи є у даних про продажі гарбузів за місяцями висока чи низька кореляція згідно з вашим візуальним тлумаченням графіка? Чи зміниться це, якщо використати більш тонкий показник замість Month, наприклад, день року (тобто кількість днів з початку року)?

У коді нижче ми припустимо, що очистили дані й отримали датафрейм під назвою 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. Ми провели такі ж кроки очищення, як і в попередньому уроці, і обчислили стовпець DayOfYear за допомогою такого виразу:

day_of_year = pd.to_datetime(pumpkins['Date']).apply(lambda dt: (dt-datetime(dt.year,1,1)).days)

Тепер, коли ви розумієте математику за лінійною регресією, давайте створимо модель регресії, щоб визначити, який пакет гарбузів має найкращі ціни. Ті, хто купує гарбузи для осінніх святкових майданчиків, можуть захотіти цю інформацію, аби оптимізувати свої закупівлі.

Пошук кореляції

ML для початківців - Пошук кореляції: ключ до лінійної регресії

🎥 Натисніть на зображення вище, щоб переглянути короткий відеоогляд кореляції.

Як ви, мабуть, помітили у попередньому уроці, середня ціна за місяцями виглядає так:

Середня ціна за місяцями

Це свідчить про те, що повинен бути певний зв’язок, і ми можемо спробувати навчити модель лінійної регресії, щоб спрогнозувати відношення між Month і Price, або між DayOfYear і Price. Ось графік розсіювання, який показує останній зв’язок:

Графік розсіювання Ціни проти Дня року

Перевіримо, чи існує кореляція, використовуючи функцію corr:

print(new_pumpkins['Month'].corr(new_pumpkins['Price']))
print(new_pumpkins['DayOfYear'].corr(new_pumpkins['Price']))

Виглядає, що кореляція досить мала: -0.15 за Month і -0.17 за DayOfMonth, але може існувати ще один важливий зв’язок. Виглядає, що існують різні кластери цін, які відповідають різним сортам гарбузів. Щоб підтвердити цю гіпотезу, побудуємо графік розсіювання кожної категорії гарбузів різним кольором. Передаючи параметр ax функції scatter, ми можемо відобразити всі точки на одному графіку:

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)

Графік розсіювання Ціни проти Дня року з кольоровим позначенням

Наше дослідження свідчить, що сорт має більший вплив на загальну ціну, ніж фактична дата продажу. Ми можемо підкріпити це стовпчиковою діаграмою:

new_pumpkins.groupby('Variety')['Price'].mean().plot(kind='bar')

Стовпчикова діаграма ціни за сортом

Наразі зосередимося лише на одному сорті гарбузів, "pie type", і подивимось, як дата впливає на ціну:

pie_pumpkins = new_pumpkins[new_pumpkins['Variety']=='PIE TYPE']
pie_pumpkins.plot.scatter('DayOfYear','Price') 

Графік розсіювання Ціни проти Дня року для pie type

Якщо тепер обчислити кореляцію між Price і DayOfYear за допомогою функції corr, отримаємо близько -0.27 — це означає, що навчання прогнозної моделі має сенс.

Перед навчанням моделі лінійної регресії важливо впевнитися, що наші дані чисті. Лінійна регресія погано працює з відсутніми значеннями, тому варто видалити всі порожні клітинки:

pie_pumpkins.dropna(inplace=True)
pie_pumpkins.info()

Іншим підходом може бути заповнення порожніх значень середніми значеннями відповідного стовпця.

Проста лінійна регресія

ML для початківців - Лінійна і поліноміальна регресія за допомогою Scikit-learn

🎥 Натисніть на зображення вище, щоб переглянути короткий відеоогляд лінійної та поліноміальної регресії.

Для навчання моделі лінійної регресії ми використаємо бібліотеку Scikit-learn.

from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split

Почнемо з розділення вхідних значень (ознаки) і очікуваного результату (мітки) у окремі масиви numpy:

X = pie_pumpkins['DayOfYear'].to_numpy().reshape(-1,1)
y = pie_pumpkins['Price']

Зверніть увагу, що нам довелося виконати reshape для вхідних даних, щоб пакет лінійної регресії правильно їх зрозумів. Лінійна регресія очікує 2D-масив на вході, де кожен рядок — це вектор вхідних ознак. У нашому випадку, оскільки є лише одна ознака, нам потрібен масив розміром N×1, де N — розмір набору даних.

Далі потрібно розділити дані на навчальний і тестовий набори, щоб можна було перевірити модель після навчання:

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

Нарешті, навчання власне моделі лінійної регресії займає лише два рядки коду. Спочатку створюємо об’єкт LinearRegression, а потім підганяємо його до наших даних за допомогою методу fit:

lin_reg = LinearRegression()
lin_reg.fit(X_train,y_train)

Об’єкт LinearRegression після виконання fit містить усі коефіцієнти регресії, до яких можна отримати доступ за допомогою властивості .coef_. У нашому випадку є лише один коефіцієнт, який має бути близько -0.017. Це означає, що ціни, схоже, трохи знижуються з часом, але не дуже сильно, приблизно на 2 центи за день. Ми також можемо отримати точку перетину регресії з віссю Y за допомогою lin_reg.intercept_ — вона буде близько 21 у нашому випадку, що вказує на ціну на початку року.

Щоб побачити, наскільки точна наша модель, ми можемо передбачити ціни на тестовому наборі даних, а потім виміряти, наскільки близькі наші передбачення до очікуваних значень. Це можна зробити, використовуючи метрику середньоквадратичної помилки (MSE), яка є середнім усіх квадратів різниць між очікуваним і передбаченим значенням.

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%. Не дуже добре. Іншим показником якості моделі є коефіцієнт детермінації, який можна отримати так:

score = lin_reg.score(X_train,y_train)
print('Model determination: ', score)

Якщо значення дорівнює 0, це означає, що модель не враховує вхідні дані і діє як найгірший лінійний прогноз, що просто є середнім значенням результату. Значення 1 означає, що ми можемо ідеально передбачити всі очікувані виходи. У нашому випадку коефіцієнт становить близько 0.06, що досить низько.

Ми також можемо побудувати графік тестових даних разом із лінією регресії, щоб краще побачити, як працює регресія у нашому випадку:

plt.scatter(X_test,y_test)
plt.plot(X_test,pred)

Linear regression

Поліноміальна регресія

Інший тип лінійної регресії — це поліноміальна регресія. Хоча іноді між змінними існує лінійний зв’язок — чим більша гарбуз за обсягом, тим вища ціна — іноді ці зв’язки не можна зобразити у вигляді площини або прямої лінії.

✅ Ось ще кілька прикладів даних, для яких можна використати поліноміальну регресію

Знову погляньте на зв’язок між Датою та Ціною. Чи здається цей розкиданий графік такого, що його обов’язково треба аналізувати за допомогою прямої лінії? Чи не можуть ціни коливатися? У цьому випадку ви можете спробувати поліноміальну регресію.

✅ Поліноми — це математичні вирази, які можуть складатися з однієї або кількох змінних і коефіцієнтів.

Поліноміальна регресія створює криву лінію, щоб краще підходити для нелінійних даних. У нашому випадку, якщо ми додамо змінну DayOfYear у квадраті до вхідних даних, ми зможемо наблизити наші дані параболічною кривою, яка матиме мінімум у певній точці протягом року.

Scikit-learn включає корисний pipeline API, щоб поєднати різні кроки обробки даних. Pipeline — це ланцюжок оцінювачів. У нашому випадку ми створимо pipeline, який спочатку додає поліноміальні ознаки до нашої моделі, а потім навчає регресію:

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) означає, що ми включатимемо всі поліноми другого ступеня з вхідних даних. У нашому випадку це буде просто DayOfYear2, але за наявності двох вхідних змінних X і Y це додасть X2, XY та Y2. Ми також можемо використовувати поліноми вищих ступенів, якщо хочемо.

Pipeline можна використовувати так само, як і оригінальний об’єкт LinearRegression, тобто ми можемо викликати fit для pipeline, а потім використовувати predict для отримання результатів передбачення. Ось графік, що показує тестові дані та наближену криву:

Polynomial regression

З використанням поліноміальної регресії ми можемо отримати трохи нижче MSE та вищий коефіцієнт детермінації, але незначно. Нам варто врахувати інші ознаки!

Ви можете побачити, що мінімальні ціни на гарбузи спостерігаються десь близько Геловіну. Як ви це можете пояснити?

🎃 Вітаємо, ви щойно створили модель, яка може допомогти передбачити ціну гарбузів для пирогів. Ви, ймовірно, зможете повторити ту ж процедуру для всіх типів гарбузів, але це було б нудно. Навчімося зараз враховувати сорт гарбуза у нашій моделі!

Категоріальні ознаки

В ідеальному світі ми хочемо мати можливість передбачати ціни для різних сортів гарбуза, використовуючи одну й ту ж модель. Однак стовпець Variety дещо відрізняється від таких стовпців, як Month, бо він містить нечислові значення. Такі стовпці називаються категоріальними.

ML for beginners - Categorical Feature Predictions with Linear Regression

🎥 Натисніть на зображення вище для короткого відеоогляду використання категоріальних ознак.

Тут ви можете побачити, як середня ціна залежить від сорту:

Average price by variety

Щоб врахувати сорт, спочатку нам потрібно перетворити його у числову форму, або закодувати його. Є кілька способів зробити це:

  • Просте числове кодування побудує таблицю різних сортів, а потім замінить назву сорту на індекс у цій таблиці. Це не найкраща ідея для лінійної регресії, бо лінійна регресія бере фактичне числове значення індексу і додає його до результату, множачи на якийсь коефіцієнт. У нашому випадку залежність між номером індексу та ціною явно нелінійна, навіть якщо ми впевнемося, що індекси впорядковані в певний спосіб.
  • One-hot кодування замінить стовпець Variety на 4 різні стовпці, по одному для кожного сорту. Кожен стовпець міститиме 1, якщо відповідний рядок належить до певного сорту, і 0 в інших випадках. Це означає, що в лінійній регресії буде чотири коефіцієнти — по одному для кожного сорту гарбузів, відповідальних за «початкову ціну» (а точніше «додаткову ціну») для цього конкретного сорту.

Код нижче показує, як можна виконати one-hot кодування сорту:

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:

X = pd.get_dummies(new_pumpkins['Variety'])
y = new_pumpkins['Price']

Решта коду така сама, як і вище, для навчання лінійної регресії. Якщо ви спробуєте це, то побачите, що середньоквадратична помилка приблизно така сама, але коефіцієнт детермінації набагато вищий (~77%). Щоб отримати ще більш точні передбачення, ми можемо врахувати більше категоріальних ознак, а також числові ознаки, такі як Month або DayOfYear. Щоб отримати один великий масив ознак, ми можемо використати join:

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 закодовані категоріальні + числові) дані з наведеного вище прикладу разом з поліноміальною регресією. Ось повний код для вашої зручності:

# налаштувати навчальні дані
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 та коефіцієнт детермінації
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%. У фінальному розділі про регресію ви дізнаєтесь про логістичну регресію для визначення категорій.


🚀Виклик

Перевірте декілька різних змінних у цій нотатці, щоб побачити, як кореляція відповідає точності моделі.

Огляд та самостійне вивчення

У цьому уроці ми дізнались про лінійну регресію. Існують також інші важливі типи регресії. Прочитайте про покрокові, Ridge, Lasso та Elasticnet методи. Хорошим курсом для подальшого вивчення є курс Стенфордського університету зі статистичного навчання

Завдання

Побудуйте модель


Відмова від відповідальності:
Цей документ було перекладено за допомогою сервісу автоматичного перекладу Co-op Translator. Хоча ми прагнемо до точності, просимо враховувати, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ рідною мовою слід вважати авторитетним джерелом. Для критично важливої інформації рекомендується звертатися до професійного людського перекладу. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникли внаслідок використання цього перекладу.