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

Инфографика от Dasani Madipalli
Предварителен тест
Този урок е наличен и на R!
Въведение
Досега разгледахте какво е регресия чрез примерни данни от набора с цени на тикви, който ще използваме през целия урок. Също така го визуализирахте с помощта на Matplotlib.
Сега сте готови да навлезете по-дълбоко в регресията за ML. Докато визуализацията ви позволява да разберете данните, истинската сила на Машинното обучение идва от обучението на модели. Моделите се обучават върху исторически данни, за да уловят автоматично зависимостите в данните, и ви позволяват да предсказвате резултати за нови данни, които моделът не е виждал досега.
В този урок ще научите повече за два вида регресия: основна линейна регресия и полиномиална регресия, заедно с част от математиката зад тези техники. Тези модели ще ни позволят да предсказваме цените на тиквите в зависимост от различни входни данни.
🎥 Кликнете върху изображението по-горе за кратко видео с обобщение на линейната регресия.
В целия този учебен план предполагаме минимални знания по математика и се стремим да го направим достъпен за студенти от други области, затова внимавайте за бележки, 🧮 извадки, схеми и други учебни средства, които подпомагат разбирането.
Предварителни умения
До момента трябва да сте запознати със структурата на данните за тиквите, които разглеждаме. Можете да ги намерите предварително заредени и почистени във файла notebook.ipynb за този урок. Във файла цената на тиквите се показва на бушел в нов DataFrame. Уверете се, че можете да стартирате тези тетрадки (notebooks) в ядра (kernels) в Visual Studio Code.
Подготовка
Като напомняне, зареждате тези данни, за да можете да задавате въпроси спрямо тях.
- Кога е най-доброто време да се купуват тикви?
- Каква цена мога да очаквам за кутия с мини тикви?
- Трябва ли да ги купувам в кошници по половин бушел или в кутии по 1 1/9 бушел? Нека продължим да изследваме тези данни.
В предишния урок създадохте Pandas DataFrame и го запълнихте с част от оригиналния набор от данни, стандартизирайки цените на бушел. По този начин обаче събрахте само около 400 точки данни и то само за есенните месеци.
Вижте данните, които предварително заредихме в съпровождащата тетрадка за този урок. Данните са предварително заредени и е начертан първоначален разсейващ (scatter) график за данните по месеци. Може би можем да добавим малко повече детайли за естеството на данните чрез по-добро почистване.
Линия на линейната регресия
Както научихте в Урок 1, целта на упражнение по линейна регресия е да можете да начертаете линия, която да:
- Показва взаимовръзки между променливи. Показва връзката между променливите
- Прави прогнози. Прави точни прогнози за това къде нова точка данни би попаднала в съотношение с линията.
Точно такава линия обичайно се чертае с помощта на регресия с минимални квадрати (Least-Squares Regression). Терминът "минимални квадрати" се отнася до процеса на минимизиране на общата грешка в нашия модел. За всяка точка данни измерваме вертикалното разстояние (наречено остатък) между действителната точка и нашата регресионна линия.
Тези разстояния се повдигат на квадрат по две основни причини:
-
Величина пред посока: Искаме да третираме грешка -5 същo като грешка +5. Квaдратирането превръща всички стойности в положителни.
-
Накaзване на екстремни стойности: Квaдратирането придава по-голяма тежест на по-големите грешки, принуждавайки линията да стои по-близо до точки, които са далеч.
След това събираме всички тези квадратирани стойности. Целта ни е да намерим конкретна линия, при която тази крайна сума е най-малка (най-малката възможна стойност) — откъдето идва и името "минимални квадрати".
🧮 Покажи ми математиката
Тази линия, наречена линия на най-добро прилягане, може да бъде изразена с уравнение:
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. Използвайки разсейващ (scatter) график, може бързо да визуализирате този коефициент. Графика с точки, подредени в чиста линия, показва висока корелация, докато графика с точки разпръснати навсякъде между X и Y показва ниска корелация.
Добър линейно регресионен модел е този, който има висок (по-близо до 1 отколкото до 0) коефициент на корелация при приложена метода на регресия с минимални квадрати с линия на регресия.
✅ Стартирайте тетрадката, придружаваща този урок, и разгледайте разсейващия график Месец към Цена. Изглежда ли асоциацията между Месец и Цена за продажбата на тикви с висока или ниска корелация според вашата визуална интерпретация на графиката? Променя ли се това, ако използвате по-фина мярка вместо Месец, напр. ден от годината (т.е. брой дни от началото на годината)?
В следващия код ще приемем, че сме почистили данните и сме получили 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 на функцията за разсейващ график, можем да начертаем всички точки на един и същ график:
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_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.
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 е размерът на набора от данни.
След това трябва да разделим данните на обучаващ (train) и тестов (test) набор, за да можем да валидираме модела след обучението:
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 в нашия случай, указвайки цената в началото на годината.
За да видим колко е точен нашият модел, можем да предскажем цените върху тестов набор от данни и след това да измерим колко близо са предсказанията ни до очакваните стойности. Това може да се направи с помощта на метриката корен квадратен средна грешка (RMSE), която е корена на средната стойност на всички квадратирани разлики между очакваната и предсказаната стойност.
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%. Не много добре. Друг индикатор за качество на модела е коефициентът на детерминация, който може да се получи така:
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 е верига от оценители (estimators). В нашия случай ще създадем 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, за да получим резултатите от предсказването. Ето графика, показваща тестовите данни и крива на апроксимация:
С помощта на полиномиална регресия можем да получим леко по-ниска средна квадратична грешка и по-висок коефициент на детерминация, но незначително. Трябва да вземем предвид и други характеристики!
Можете да видите, че минималните цени на тиквите се наблюдават някъде около Хелоуин. Как бихте го обяснили?
🎃 Поздравления, току-що създадохте модел, който може да помага за предсказване на цената на тикви за пай. Вероятно можете да повторите същата процедура за всички видове тикви, но това би било досадно. Нека сега научим как да вземем предвид сорта тикви в нашия модел!
Категориални характеристики
В идеалния свят искаме да можем да предсказваме цените за различни сортове тикви, използвайки същия модел. Въпреки това, колоната Variety е различна от колони като Month, защото съдържа ненумерични стойности. Такива колони се наричат категориални.
🎥 Кликнете върху изображението по-горе за кратък видео преглед на използването на категориални характеристики.
Тук можете да видите как средната цена зависи от сорта:
За да вземем предвид сорта, първо трябва да го преобразуваме в числова форма, или да го кодираме. Има няколко начина да го направим:
- Простото числово кодиране ще изгради таблица на различни сортове, и ще замени името на сорта с индекс в тази таблица. Това не е най-добрата идея за линейна регресия, защото линейната регресия взема действителната числова стойност на индекса и я добавя към резултата, умножавайки по някакъв коефициент. В нашия случай връзката между номера на индекса и цената е явно нелинейна, дори ако направим така, че индексите да са подредени по някакъв конкретен начин.
- 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%. В последната част за регресия ще научите за логистичната регресия за определяне на категории.
🚀Предизвикателство
Тествайте няколко различни променливи в тази тетрадка, за да видите как корелацията съответства на точността на модела.
Викторина след лекцията
Преглед и самообучение
В този урок научихме за линейната регресия. Има и други важни видове регресия. Прочетете за техническите подходи Stepwise, Ridge, Lasso и Elasticnet. Добър курс за по-задълбочено изучаване е Stanford Statistical Learning course
Задача
Отказ от отговорност:
Този документ е преведен с помощта на AI преводаческа услуга Co-op Translator. Въпреки че се стремим към точност, моля, имайте предвид, че автоматизираните преводи могат да съдържат грешки или неточности. Оригиналният документ на неговия език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Не носим отговорност за никакви недоразумения или погрешни тълкувания, произтичащи от използването на този превод.





