Skip to content

Latest commit

 

History

History
386 lines (256 loc) · 36.4 KB

File metadata and controls

386 lines (256 loc) · 36.4 KB

Изградња регресионог модела коришћењем Scikit-learn: регресија на четири начина

Напомена за почетнике

Линеарна регресија се користи када желимо да предвидимо нумеричку вредност (на пример, цену куће, температуру или продају). Она функционише тако што проналази праву линију која најбоље представља однос између улазних карактеристика и излаза.

У овој лекцији се фокусирамо на разумевање концепта пре него што истражимо напредније технике регресије. Линеарна насупрот полиномијалној регресији инфографика

Инфографика од Dasani Madipalli

Увод

До сада сте истражили шта је регресија користећи узорке података из скупа података о цени бундеве који ћемо користити током целе ове лекције. Такође сте то визуелизовали помоћу Matplotlib-а.

Сада сте спремни да дубље зароните у регресију за машинско учење. Док вам визуализација омогућава да разумете податке, права снага машинског учења долази из тренирања модела. Модели се тренирају на историјским подацима да би аутоматски ухватили зависности у подацима и омогућавају вам да предвидите исходе за нове податке које модел раније није видео.

У овој лекцији ћете сазнати више о два типа регресије: основна линеарна регресија и полиномијална регресија, заједно са неким математичким основама ових техника. Ови модели ће нам омогућити да предвидимо цене бундеве у зависности од различитих улазних података.

Машинско учење за почетнике - Разумевање линеарне регресије

🎥 Кликните на слику изнад за кратак видео преглед линеарне регресије.

Током читавог овог курикулума претпостављамо минимално познавање математике и тежимо да је учинимо приступачном за студенте из других области, па обратите пажњу на напомене, 🧮 илустрације, дијаграме и друге алате за учење који помажу разумевању.

Предуслов

До сада би требало да сте упознати са структуром података о бундеви које испитујемо. Можете их пронаћи учитане и очишћене у notebook.ipynb фајлу ове лекције. У том фајлу, цена бундеве је приказана по бушелу у новом DataFrame-у. Обавезно проверите да можете да покренете ове бележнице у језгру у Visual Studio Code.

Припрема

Као подсетник, ове податке учитавате да бисте могли да постављате питања у вези са њима.

  • Када је најбоље време за куповину бундеве?
  • Коју цену могу очекивати за кутију минијатурних бундевa?
  • Да ли их треба купити у корпама од пола бушела или у кутији од 1 1/9 бушела?

Хајде да наставимо са анализом ових података.

У претходној лекцији сте направили Pandas DataFrame и попунили га делом оригиналног скупа података, стандардизујући цене по бушелу. Међутим, тиме сте пришли само око 400 података и то само за јесење месеце.

Погледајте податке које смо претходно учитали у бележници која прати ову лекцију. Податци су учитани и приказан је почетни графикон распршености (scatterplot) за приказ месечних података. Можда можемо добити мало више детаља о природи података њиховим додатним чишћењем.

Линија линеарне регресије

Као што сте научили у Лекцији 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 сајту. Посетите и овaj калкулатор најмањих квадрата да бисте видели како вредности бројева утичу на линију.

Корелација

Још један термин који треба разумети је Коефицијент корелације између дате X и Y варијабле. Помоћу scatterplot-а можете брзо визуализовати овај коефицијент. График са тачкама распоређеним у прецизној линији има високу корелацију, док график са тачкама расутим на разним местима између X и Y има ниску корелацију.

Добар линеарни регресијски модел имаће висок (ближи 1 него 0) коефицијент корелације користећи методу регресије најмањих квадрата са линијом регресије.

✅ Покрените бележницу која прати ову лекцију и погледајте scatterplot Цена у односу на Месец. Да ли подаци који повезују Месец и Цену у продаји бундеве изгледају да имају високу или ниску корелацију, према Вашој визуелној процени распореда тачака? Да ли се то мења ако користите прецизнију меру уместо Месеца, нпр. дан у години (односно број дана од почетка године)?

У доњем коду претпоставићемо да смо очистили податке и добили DataFrame под називом new_pumpkins, сличан следећем:

ID Месец ДанУгодини Врста Град Паковање Најнижа цена Највиша цена Цена
70 9 267 ВРСТА ЗА ПИТЕ БАЛТИМОР 1 1/9 бушел картонске кутије 15.0 15.0 13.636364
71 9 267 ВРСТА ЗА ПИТЕ БАЛТИМОР 1 1/9 бушел картонске кутије 18.0 18.0 16.363636
72 10 274 ВРСТА ЗА ПИТЕ БАЛТИМОР 1 1/9 бушел картонске кутије 18.0 18.0 16.363636
73 10 274 ВРСТА ЗА ПИТЕ БАЛТИМОР 1 1/9 бушел картонске кутије 17.0 17.0 15.454545
74 10 281 ВРСТА ЗА ПИТЕ БАЛТИМОР 1 1/9 бушел картонске кутије 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)

Сада када разумете математику иза линеарне регресије, хајде да направимо регресијски модел да видимо да ли можемо предвидети која паковања буњева имају најбоље цене. Неки који купују бундеве за свечани јесењи паркинг можда желе ове информације како би оптимизовали своју куповину пакета бундеве.

Тражење корелације

Машинско учење за почетнике - Тражење корелације: кључ за линеарну регресију

🎥 Кликните на слику изнад за кратак видео преглед корелације.

Из претходне лекције вероватно сте видели да просечна цена за различите месеце изгледа овако:

Просечна цена по месецу

Ово сугерише да треба да постоји нека корелација, и можемо покушати да тренирамо линеарни регресијски модел да предвидимо однос између Месец и Цена, или између ДануГодини и Цена. Ево графикона распршености који приказује овај други однос:

Графикон распршености Цена према Дану у години

Хајде да проверимо да ли постоји корелација помоћу функције corr:

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

Чини се да је корелација прилично мала, -0.15 по Месецу и -0.17 по Дану у месецу, али можда постоји неки други важан однос. Изгледа да постоје различити скупови цена који одговарају разним врстама бундеве. Да бисмо потврдили ову хипотезу, хајде да нацртамо сваку категорију бундеве другим бојама. Прослеђивањем 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')

Тракасти график цена по врсти

За сада се фокусирајмо само на једну врсту бундеве, 'type за питу', и видимо какав утицај датум има на цену:

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

Графикон распршености Цена према Дану у години

Ако сада израчунамо корелацију између Цена и ДанУгодини користећи функцију corr, добићемо нешто око -0.27 - што значи да има смисла тренирати предиктивни модел.

Пре тренирања линеарног регресијског модела, важно је да подаци буду чисти. Линеарна регресија не функционише добро са недостајућим вредностима, па има смисла уклонити све празне ћелије:

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

Други приступ би био да се те празне вредности попуне просечним вредностима из одговарајуће колоне.

Једноставна линеарна регресија

Машинско учење за почетнике - Линеарна и полиномијална регресија коришћењем 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 за комбиновaње различитих корака обраде података заједно. 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 за почетнике - Предвиђања категоријалних карактеристика помоћу линеарне регресије

🎥 Кликните на слику изнад за кратак видео преглед коришћења категоријалних карактеристика.

Овде можете видети како просечна цена зависи од врсте:

Average price by variety

Да бисмо узели у обзир врсту, прво морамо да је конвертујемо у нумерички облик, односно да je енкодирајемо. Постоји неколико начина да то урадимо:

  • Једноставно нумеричко кодирање ће направити табелу различитих врста, а затим заменити име врсте индексом у тој табели. Ово није најбоља идеја за линеарну регресију, јер линеарна регресија узима стварну нумеричку вредност индекса и додаје је резултату, множећи неким коефицијентом. У нашем случају, веза између броја индекса и цене је очигледно нелинеарна, чак и ако се уверимо да су индекси поређани на одређени начин.
  • 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%. У завршном делу о регресији научићете о логистичкој регресији за одређивање категорија.


🚀Изазов

Испробајте неколико различитих променљивих у овом notebook-у да бисте видели како корелација одговара тачности модела.

Преглед и самостално учење

У овом часу смо учили о линеарној регресији. Постоје и други важни типови регресије. Прочитајте о Stepwise, Ridge, Lasso и Elasticnet техникама. Добар курс за учење више је Stanford Statistical Learning course

Задатак

Направи модел


Резервaција од одговорности: Овај документ је преведен уз помоћ AI услуге за превод Co-op Translator. Иако тежимо тачности, молимо вас да имате у виду да аутоматски преводи могу садржати грешке или нетачности. Изворни документ на свом оригиналном језику треба сматрати ауторитетним извором. За критичне информације препоручује се професионални људски превод. Нисмо одговорни за било каква неспоразуми или погрешне интерпретације проузроковане коришћењем овог превода.