|
|
3 months ago | |
|---|---|---|
| .. | ||
| solution | 4 months ago | |
| README.md | 3 months ago | |
| assignment.md | 4 months ago | |
| notebook.ipynb | 9 months ago | |
README.md
Създаване на регресионен модел с помощта на Scikit-learn: регресия по четири начина
Забележка за начинаещи
Линейната регресия се използва, когато искаме да предвидим числова стойност (например, цена на къща, температура или продажби). Тя работи, като намира права линия, която най-добре представя връзката между входните характеристики и изходния резултат.
В този урок се съсредоточаваме върху разбирането на концепцията, преди да разгледаме по-напреднали техники за регресия.

Инфографика от Dasani Madipalli
Предварителен тест преди лекцията
Този урок е наличен и на R!
Въведение
Досега разгледахте какво е регресия със примерни данни, събрани от набора с данни за цените на тиквите, който ще използваме през целия урок. Също така сте ги визуализирали с Matplotlib.
Сега сте готови да навлезете по-дълбоко в регресията за машинното обучение. Докато визуализацията ви помага да разберете данните, истинската сила на машинното обучение идва от обучението на модели. Моделите се обучават на исторически данни, за да улавят автоматично зависимости в данните, и ви позволяват да предскажете резултати за нови данни, които моделът не е виждал преди.
В този урок ще научите повече за два вида регресия: базова линейна регресия и полиномиална регресия, заедно с част от математиката зад тези техники. Тези модели ще ни позволят да предскажем цените на тиквите в зависимост от различни входни данни.
🎥 Натиснете върху изображението по-горе за кратко видео с обзор на линейната регресия.
През тази учебна програма предполагаме минимални знания по математика и целим да я направим достъпна за студенти от други области, затова следете за бележки, 🧮 акценти, диаграми и други инструменти за учене, които помагат за по-доброто разбиране.
Предварителни изисквания
Вече трябва да сте запознати със структурата на тиквените данни, които разглеждаме. Можете да ги намерите предварително заредени и почистени във файла notebook.ipynb към този урок. Във файла цената на тиквата е показана за бушел в нов DataFrame. Уверете се, че можете да стартирате тези ноутбуци в среди като Visual Studio Code.
Подготовка
Като напомняне, вие зареждате тези данни, за да можете да им задавате въпроси.
- Кога е най-доброто време да купувам тикви?
- Каква цена мога да очаквам за кашон с миниатюрни тикви?
- Трябва ли да ги купувам в кошници от половин бушел или в кутия от 1 1/9 бушел?
Нека продължим да изследваме тези данни.
В предишния урок създадохте Pandas DataFrame и го напълнихте с част от оригиналния набор от данни, стандартизирайки цените по бушел. По този начин обаче събрахте около 400 точки данни и само за есенните месеци.
Вижте предварително заредените данни в ноутбука, предоставен към този урок. Данните са заредени, а първоначален диаграма на разсейване показва месечна информация. Може би можем да получим малко повече детайли за естеството на данните, като ги почистим още.
Линия на линейна регресия
Както научихте в Урок 1, целта на упражнението по линейна регресия е да може да начертаете линия, която да:
- Показва връзката между променливите. Показва връзката между променливите
- Прави прогнози. Прави точни прогнози къде би попаднала нова точка в отношение към тази линия.
Типично за регресия с минимални квадрати е да се начертае такава линия. Терминът "Минимални квадрати" се отнася до процеса на минимизиране на общата грешка в нашия модел. За всяка точка измерваме вертикалното разстояние (наречено остатък) между реалната точка и нашата регресионна линия.
Тези разстояния се повдигат на квадрат по две основни причини:
-
Магнитуда пред посока: Искаме да третираме грешката -5 по същия начин както грешката +5. Квадратирането прави всички стойности положителни.
-
Налагане на наказание за отклонения: Квадратирането дава по-голяма тежест на по-големите грешки, карайки линията да стои по-близо до далечните точки.
След това събираме всички тези квадратирани стойности. Целта ни е да намерим конкретната линия, при която тази окончателна сума е най-малка (най-ниската възможна стойност) — откъдето идва името "Минимални квадрати".
🧮 Покажи ми математиката
Тази линия, наречена линия на най-добро напасване, може да бъде изразена чрез уравнение:
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. С разсейваща диаграма бързо можете да визуализирате този коефициент. Графика с точки, подредени около права линия, има висока корелация, но графика с точки, разпръснати хаотично между 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. Извършихме същите стъпки за почистване като в предишния урок и изчислихме колонатаDayOfYearсъс следното изразяване:
day_of_year = pd.to_datetime(pumpkins['Date']).apply(lambda dt: (dt-datetime(dt.year,1,1)).days)
Сега, когато разбирате математиката зад линейната регресия, нека създадем регресионен модел, за да видим дали можем да предскажем коя опаковка тикви ще има най-добри цени. Някой, купуващ тикви за празничен тиквен участък, може да иска тази информация, за да оптимизира покупките си.
Търсене на корелация
🎥 Натиснете върху изображението по-горе за кратко видео с обзор на корелацията.
От предишния урок вероятно сте видели, че средната цена за различни месеци изглежда така:
Това предполага, че трябва да има някаква корелация и можем да се опитаме да обучим модел за линейна регресия, за да предскажем връзката между 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')
Ако сега изчислим корелацията между Price и DayOfYear с функцията corr, ще получим нещо като -0.27 - което означава, че обучението на предсказателен модел има смисъл.
Преди да обучите модел за линейна регресия, е важно да се уверите, че данните са чисти. Линейната регресия не работи добре с липсващи стойности, затова е разумно да се изчистят всички празни клетки:
pie_pumpkins.dropna(inplace=True)
pie_pumpkins.info()
Друг подход би бил да замените липсващите стойности със средни стойности от съответната колона.
Простата линейна регресия
🎥 Натиснете върху изображението по-горе за кратко видео с обзор на линейната и полиномиалната регресия.
За да обучим нашия модел за линейна регресия, ще използваме библиотеката 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)
Полиномиална регресия
Друг вид линейна регресия е полиномиалната регресия. Докато понякога има линейна връзка между променливите – колкото по-голяма е тиквата като обем, толкова по-висока е цената – понякога тези връзки не могат да бъдат начертани като равнина или права линия.
✅ Ето още няколко примера на данни, които могат да използват полиномиална регресия.
Погледнете отново връзката между Дата и Цена. Изглежда ли тази точкова диаграма задължително да се анализира с права линия? Не може ли цените да варират? В този случай можете да опитате полиномиална регресия.
✅ Полиномите са математически изрази, които могат да съдържат една или повече променливи и коефициенти.
Полиномиалната регресия създава извита линия, която по-добре се адаптира към нелинейни данни. В нашия случай, ако включим квадратичната променлива 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 за получаване на резултатите от предвиждането. Ето графиката, показваща тестовите данни и приближаващата крива:
Използвайки Полиномиална Регресия, можем да получим леко по-нисък MSE и по-висок коефициент на детерминация, но не значително. Трябва да вземем предвид и други характеристики!
Виждате, че минималните цени на тиквите са наблюдавани някъде около Хелоуин. Как бихте обяснили това?
🎃 Поздравления, току-що създадохте модел, който може да предсказва цената на питките тикви. Вероятно бихте могли да повторите същата процедура за всички видове тикви, но това би било уморително. Нека сега научим как да вземем предвид вида тиква в нашия модел!
Категориални характеристики
В идеалния свят искаме да можем да предсказваме цени за различни видове тикви с един и същ модел. Въпреки това, колоната Variety е някак различна от колони като Month, защото съдържа нечислови стойности. Такива колони се наричат категориални.
🎥 Кликнете върху изображението по-горе за кратко видео с обзор на използването на категориални характеристики.
Тук можете да видите как средната цена зависи от вида:
За да вземем предвид вида, първо трябва да го преобразуваме в числова форма, или да го кодираме. Има няколко начина, по които можем да го направим:
- Простото числово кодиране ще построи таблица с различните видове и след това ще замени името на вида с индекс в тази таблица. Това не е най-добрата идея за линейна регресия, защото линейната регресия взима действителната числова стойност на индекса и я добавя към резултата, умножавайки със съответния коефициент. В нашия случай връзката между числото на индекса и цената е ясно нелинейна, дори ако осигурим индексирането да е в някакъв определен ред.
- One-hot encoding ще замести колоната
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']
Останалата част от кода е същата като използваната по-горе за обучение на Linear Regression. Ако го изпробвате, ще видите, че средно квадратичната грешка е приблизително същата, но получаваме много по-висок коефициент на детерминация (~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 = 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%. В последния раздел за регресия ще научите за логистична регресия, която служи за класификация.
🚀Предизвикателство
Изпробвайте няколко различни променливи в този ноутбук, за да видите как корелацията съответства на точността на модела.
Квиз след лекцията
Преглед и Самостоятелно обучение
В този урок научихме за линейната регресия. Съществуват и други важни видове регресия. Прочетете за техниките Stepwise, Ridge, Lasso и Elasticnet. Добър курс за допълнително обучение е Stanford Statistical Learning course
Задача
Отказ от отговорност:
Този документ е преведен с помощта на AI услуга за превод Co-op Translator. Въпреки че се стремим към точност, имайте предвид, че автоматичните преводи могат да съдържат грешки или неточности. Оригиналният документ на неговия език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Не носим отговорност за каквито и да е недоразумения или погрешни тълкувания, произтичащи от използването на този превод.





