Повний посібник із логістичної регресії в Python PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

Повний посібник із логістичної регресії в Python

Вступ

Іноді плутають з лінійна регресія новачками – через поділення терміну регресія - логістична регресія сильно відрізняється від лінійна регресія. Тоді як лінійна регресія передбачає такі значення, як 2, 2.45, 6.77 або безперервні значення, роблячи це a регресія алгоритм, логістична регресія передбачає такі значення, як 0 або 1, 1 або 2 або 3, які є дискретні значення, роблячи це a класифікація алгоритм. Так, називається регресія але є а класифікація алгоритм. Докладніше про це за мить.

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

У цьому посібнику ми будемо виконувати логістичну регресію в Python за допомогою бібліотеки Scikit-Learn. Також пояснимо, чому слово «регресія» присутній у назві та як працює логістична регресія.

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

мотивація

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

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

Турецька ферма працює з двома видами гарбузового насіння, один називається Çerçevelik а інший Ургуп Сіврісі.

Щоб класифікувати гарбузове насіння, ваша команда дотримувалася документу 2021 року «Використання методів машинного навчання в класифікації насіння гарбуза (Cucurbita pepo L.). Генетичні ресурси та еволюція сільськогосподарських культур» з Коклу, Сарігіла та Озбека – у цьому документі є методологія фотографування та вилучення розмірів насіння із зображень.

Після завершення процесу, описаного в статті, були отримані такі вимірювання:

  • Область – кількість пікселів у межах гарбузового насіння
  • По периметру – окружність гарбузового насіння в пікселях
  • Довжина великої осі – також окружність гарбузового насіння в пікселях
  • Довжина малої осі – мала осьова відстань гарбузового насіння
  • Ексцентричність – ексцентриситет гарбузового насіння
  • Опукла область – кількість пікселів найменшої опуклої оболонки в області, утвореній гарбузовим насінням
  • Обсяг – відношення площі гарбузового насіння до пікселів обмежувальної рамки
  • Еквівалентний діаметр – квадратний корінь із множення площі гарбузового насіння на чотири поділене на пі
  • Компактність – відношення площі гарбузового насіння до площі кола з такою ж окружністю
  • Solidity – опуклий і опуклий стан гарбузового насіння
  • Округлість – овальність гарбузового насіння без урахування спотворень його країв
  • Співвідношення сторін – співвідношення сторін гарбузового насіння

Це вимірювання, з якими вам доведеться працювати. Крім вимірювань, є також Клас етикетка для двох видів гарбузового насіння.

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

Розуміння набору даних

Примітка: Ви можете завантажити набір даних гарбуза тут.

Після завантаження набору даних ми можемо завантажити його в структуру фрейму даних за допомогою pandas бібліотека. Оскільки це файл Excel, ми будемо використовувати read_excel() метод:

import pandas as pd

fpath = 'dataset/pumpkin_seeds_dataset.xlsx' 
df = pd.read_excel(fpath)

Після завантаження даних ми можемо швидко переглянути перші 5 рядків за допомогою head() метод:

df.head() 

Це призводить до:

	Area 	Perimeter 	Major_Axis_Length 	Minor_Axis_Length 	Convex_Area 	Equiv_Diameter 	Eccentricity 	Solidity 	Extent 	Roundness 	Aspect_Ration 	Compactness 	Class
0 	56276 	888.242 	326.1485 			220.2388 			56831 			267.6805 		0.7376 			0.9902 		0.7453 	0.8963 		1.4809 			0.8207 			Çerçevelik
1 	76631 	1068.146 	417.1932 			234.2289 			77280 			312.3614 		0.8275 			0.9916 		0.7151 	0.8440 		1.7811 			0.7487 			Çerçevelik
2 	71623 	1082.987 	435.8328 			211.0457 			72663 			301.9822 		0.8749 			0.9857 		0.7400 	0.7674 		2.0651 			0.6929 			Çerçevelik
3 	66458 	992.051 	381.5638 			222.5322 			67118 			290.8899 		0.8123 			0.9902 		0.7396 	0.8486 		1.7146 			0.7624 			Çerçevelik
4 	66107 	998.146 	383.8883 			220.4545 			67117 			290.1207 		0.8187 			0.9850 		0.6752 	0.8338 		1.7413 			0.7557 			Çerçevelik

Тут ми маємо всі вимірювання у відповідних стовпцях, наші риси, а також Клас колонка, наш мета, який є останнім у фреймі даних. Ми можемо побачити, скільки вимірювань ми маємо, використовуючи shape атрибут:

df.shape 

Вихід:

(2500, 13)

Результат форми повідомляє нам, що в наборі даних є 2500 записів (або рядків) і 13 стовпців. Оскільки ми знаємо, що є один цільовий стовпець, це означає, що у нас є 12 стовпців функцій.

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

Цю перевірку можна провести шляхом підрахунку кожного зразка насіння за допомогою value_counts() метод:

df['Class'].value_counts() 

Наведений вище код відображає:

Çerçevelik       1300
Ürgüp Sivrisi    1200
Name: Class, dtype: int64

Ми бачимо, що є 1300 зразків Çerçevelik насіння та 1200 зразків ст Ургуп Сіврісі насіння. Зверніть увагу, що різниця між ними становить 100 зразків, дуже невелика різниця, що добре для нас і вказує на те, що немає необхідності змінювати баланс кількості зразків.

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

df.describe().T

Отримана таблиця:

					count 	mean 			std 			min 		25% 			50% 			75% 			max
Area 				2500.0 	80658.220800 	13664.510228 	47939.0000 	70765.000000 	79076.00000 	89757.500000 	136574.0000
Perimeter 			2500.0 	1130.279015 	109.256418 		868.4850 	1048.829750 	1123.67200 		1203.340500 	1559.4500
Major_Axis_Length 	2500.0 	456.601840 		56.235704 		320.8446 	414.957850 		449.49660 		492.737650 		661.9113
Minor_Axis_Length 	2500.0 	225.794921 		23.297245 		152.1718 	211.245925 		224.70310 		240.672875 		305.8180
Convex_Area 		2500.0 	81508.084400 	13764.092788 	48366.0000 	71512.000000 	79872.00000 	90797.750000 	138384.0000
Equiv_Diameter 		2500.0 	319.334230 		26.891920 		247.0584 	300.167975 		317.30535 		338.057375 		417.0029
Eccentricity 		2500.0 	0.860879 		0.045167 		0.4921 		0.831700 		0.86370 		0.897025 		0.9481
Solidity 			2500.0 	0.989492 		0.003494 		0.9186 		0.988300 		0.99030 		0.991500 		0.9944
Extent 				2500.0 	0.693205 		0.060914 		0.4680 		0.658900 		0.71305 		0.740225 		0.8296
Roundness 			2500.0 	0.791533 		0.055924 		0.5546 		0.751900 		0.79775 		0.834325 		0.9396
Aspect_Ration 		2500.0 	2.041702 		0.315997 		1.1487 		1.801050 		1.98420 		2.262075 		3.1444
Compactness 		2500.0 	0.704121 		0.053067 		0.5608 		0.663475 		0.70770 		0.743500 		0.9049

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

Крім того, дивлячись на мінімальний (min) і максимальний (max) стовпці, деякі функції, такі як Area та Convex_Area, мають великі відмінності між мінімальними та максимальними значеннями. Це означає, що ці стовпці містять дуже малі дані, а також дуже великі значення даних, або більш висока амплітуда між значеннями даних.

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

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

Існують деякі алгоритми машинного навчання, наприклад алгоритми на основі дерева, такі як Випадкова класифікація лісу, на які не впливають висока дисперсія даних, викиди та екстремальні значення. Логістична регресія відрізняється, вона заснована на функції, яка класифікує наші значення, і на параметри цієї функції можуть впливати значення, які виходять за межі загальної тенденції даних і мають високу дисперсію.

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

Примітка: В інформатиці є такий популярний вислів: «Сміття всередину, сміття назовні» (GIGO), який добре підходить для машинного навчання. Це означає, що коли у нас є сміттєві дані – вимірювання, які не описують явища самі по собі, дані, які не були зрозумілі та добре підготовлені відповідно до певного алгоритму чи моделі, ймовірно, створять неправильні результати, які не працюватимуть на щодня.
Це одна з причин, чому дослідження, розуміння даних і принцип роботи обраної моделі є такими важливими. Роблячи це, ми можемо уникнути зайвого сміття в нашій моделі – натомість додати в неї цінність і отримати цінність.

Візуалізація даних

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

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

import seaborn as sns


sns.pairplot(data=df, hue='Class')

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

Дивлячись на парний графік, ми бачимо, що в більшості випадків точки з Çerçevelik класу чітко відокремлені від точок Ürgüp Sivrisi клас. Або точки одного класу розташовані праворуч, а інші — ліворуч, або одні з них знаходяться вгорі, а інші — внизу. Якби ми використали якусь криву чи лінію для розділення класів, це показує, що їх легше розділити, якби вони були змішані, класифікація була б важчим завданням.

У Eccentricity, Compactness та Aspect_Ration Деякі точки, які є «ізольованими» або відхиляються від загальної тенденції даних (викиди), також легко помітити.

Дивлячись на діагональ від верхнього лівого до нижнього правого кута діаграми, зверніть увагу, що розподіл даних також позначено кольорами відповідно до наших класів. Форми розподілу та відстань між обома кривими є іншими показниками того, наскільки вони роздільні – чим далі одна від одної, тим краще. У більшості випадків вони не накладаються, що означає, що їх легше розділити, що також сприяє виконанню нашого завдання.

У послідовності ми також можемо побудувати коробкові графіки всіх змінних за допомогою sns.boxplot() метод. У більшості випадків корисно орієнтувати коробкові діаграми горизонтально, щоб форми коробкових діаграм були такими ж, як і форми розподілу, ми можемо зробити це за допомогою orient Аргумент:


sns.boxplot(data=df, orient='h') 

Повний посібник із логістичної регресії в Python PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

Зверніть увагу на це в сюжеті вище Area та Convex_Area мають таку високу величину в порівнянні з величинами інших стовпців, що вони тиснуть інші коробкові діаграми. Щоб мати можливість переглянути всі коробкові діаграми, ми можемо масштабувати об’єкти та знову побудувати їх.

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

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

Примітка: Кореляція за умовчанням, обчислена за допомогою corr() метод - це Коефіцієнт кореляції Пірсона. Цей коефіцієнт вказується, коли дані є кількісними, мають нормальний розподіл, не мають викидів і мають лінійну залежність.

Іншим вибором було б розрахувати Коефіцієнт кореляції Спірмена. Коефіцієнт Спірмена використовується, коли дані є порядковими, нелінійними, мають будь-який розподіл і викиди. Зауважте, що наші дані не зовсім узгоджуються з припущеннями Пірсона чи Спірмена (існують також інші методи кореляції, як-от метод Кендалла). Оскільки наші дані є кількісними, і нам важливо виміряти їх лінійну залежність, ми будемо використовувати коефіцієнт Пірсона.

Давайте подивимося на кореляції між змінними, а потім перейдемо до попередньої обробки даних. Розрахуємо кореляції з corr() і візуалізуйте їх за допомогою Сіборна heatmap(). Стандартний розмір теплової карти, як правило, невеликий, тому ми будемо імпортувати matplotlib (загальний механізм візуалізації/бібліотека, на основі якого створено Seaborn) і змініть розмір figsize:

import matplotlib.pyplot as plt
plt.figure(figsize=(15, 10))

correlations = df.corr()
sns.heatmap(correlations, annot=True) 

Повний посібник із логістичної регресії в Python PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

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

Коли є високі кореляції, такі як одна з 0.99 між Aspec_Ration та Compactness, це означає, що ми можемо використовувати лише Aspec_Ration або тільки Compactness, замість обох (оскільки вони майже рівні провісники один одного). Те саме стосується Eccentricity та Compactness з -0.98 кореляція, для Area та Perimeter з 0.94 кореляція та деякі інші стовпці.

Попередня обробка даних

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

Стовпці функцій будуть нашими X дані та стовпець класу, наш y цільові дані:

y = df['Class']
X = df.drop(columns=['Class'], axis=1)

Перетворення категоріальних ознак на числові

Щодо нашого Class стовпець – його значення не є числами, це означає, що нам також потрібно їх перетворити. Є багато способів зробити це перетворення; тут ми будемо використовувати replace() метод і замінити Çerçevelik до 0 та Ürgüp Sivrisi до 1.

y = y.replace('Çerçevelik', 0).replace('Ürgüp Sivrisi', 1)

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

Розподіл даних на навчальні та тестові набори

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

Роздуми про масштабування показують, що нам потрібно спочатку розділити X та y дані далі в набори навчання та тестування, а потім до відповідати скалер на навчальному наборі, і до трансформувати як навчальний, так і тестовий набори (без жодного впливу тестового набору на масштабувальник, який це робить). Для цього ми будемо використовувати Scikit-Learn train_test_split() метод:

from sklearn.model_selection import train_test_split
SEED = 42 

X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                    test_size=.25, 
                                                    random_state=SEED)

Установка test_size=.25 забезпечує використання 25% даних для тестування та 75% для навчання. Це можна було б пропустити, оскільки це розділення за замовчуванням, але Пітонічний спосіб написання коду радить, що бути «явним краще, ніж неявним».

Примітка: Речення «явне краще, ніж неявне» є посиланням на Дзен Пітонаабо PEP20. Він викладає деякі пропозиції щодо написання коду Python. Якщо ці пропозиції виконуються, код розглядається Пітонічний. Ви можете дізнатися про це більше тут.

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

X_train.shape, X_test.shape, y_train.shape, y_test.shape

Тут відображається:

((1875, 12), (625, 12), (1875,), (625,))

Ми бачимо, що після поділу у нас є 1875 записів для навчання та 625 для тестування.

Масштабування даних

Після того, як ми підготуємо наш тренувальний і тестовий набори, ми можемо приступити до масштабування даних за допомогою Scikit-Learn StandardScaler об’єкт (або інші програми масштабування, надані бібліотекою). Щоб уникнути витоку, скалер прикріплений до X_train дані та значення потягу потім використовуються для масштабування або трансформації як даних потягу, так і тестових даних:

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

Оскільки ви зазвичай дзвоните:

scaler.fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

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

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

column_names = df.columns[:12] 
X_train = pd.DataFrame(X_train, columns=column_names)

sns.boxplot(data=X_train, orient='h')

Повний посібник із логістичної регресії в Python PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

Нарешті ми можемо побачити всі наші бокс-сюжети! Зверніть увагу, що всі вони мають викиди та особливості, які представляють розподіл далі від нормального (які мають криві, нахилені вліво або вправо), наприклад Solidity, Extent, Aspect_Ration та Compactedness, ті самі, що мали вищу кореляцію.

Видалення викидів за допомогою методу IQR

Ми вже знаємо, що на логістичну регресію можуть впливати викиди. Одним із способів їх лікування є використання методу, який називається Міжквартильний діапазон or IQR. Початковий крок методу IQR полягає в тому, щоб розділити дані нашого поїзда на чотири частини, які називаються квартилями. Перший квартиль, Q1, становить 25% даних, другий, Q2, до 50%, третій, Q3, до 75%, а останній, Q4, до 100%. Ящики в коробці визначаються методом IQR і є його візуальним представленням.

Розглядаючи горизонтальну коробкову діаграму, вертикальна лінія ліворуч позначає 25% даних, вертикальна лінія посередині – 50% даних (або медіану), а остання вертикальна лінія праворуч – 75% даних. . Чим рівномірніший розмір обох квадратів, визначених вертикальними лініями, або чим більше середня вертикальна лінія розташована посередині, означає, що наші дані ближчі до нормального розподілу або менш спотворені, що корисно для нашого аналізу.

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

$$
Мінімум = Q1 – 1.5*IQR
$$

та

$$
Максимум = Q3 + 1.5*IQR
$$

IQR – це саме різниця між Q3 і Q1 (або Q3 – Q1), і це найбільш центральна точка даних. Ось чому, знаходячи IQR, ми фільтруємо викиди в крайніх точках даних або в точках мінімуму та максимуму. Коробкові графіки дають нам уявлення про те, якими будуть результати методу IQR.

Повний посібник із логістичної регресії в Python PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

Ми можемо використовувати панд quantile() метод, щоб знайти наші квантилі, і iqr від scipy.stats пакет для отримання інтерквартильного діапазону даних для кожного стовпця:

from scipy.stats import iqr

Q1 = X_train.quantile(q=.25)
Q3 = X_train.quantile(q=.75)

IQR = X_train.apply(iqr)

Тепер у нас є Q1, Q3 і IQR, ми можемо відфільтрувати значення, ближчі до медіани:


minimum = X_train < (Q1-1.5*IQR)
maximum = X_train > (Q3+1.5*IQR)


filter = ~(minimum | maximum).any(axis=1)


X_train = X_train[filter]

Після фільтрації наших навчальних рядків ми можемо побачити, скільки з них все ще в даних shape:

X_train.shape

Це призводить до:

(1714, 12)

Ми бачимо, що після фільтрації кількість рядків зросла з 1875 до 1714. Це означає, що 161 рядок містив викиди або 8.5% даних.

Примітка: Рекомендується, щоб фільтрація викидів, видалення значень NaN та інші дії, пов’язані з фільтрацією та очищенням даних, залишалися нижче або до 10% даних. Спробуйте подумати про інші рішення, якщо ваша фільтрація або видалення перевищує 10% ваших даних.

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

y_train.shape

Це виводить:

(1875,)

Зверніть увагу на це y_train все ще має 1875 рядків. Нам потрібно зіставити кількість y_train рядів до числа X_train рядків, а не просто довільно. Нам потрібно видалити y-значення вилучених екземплярів гарбузового насіння, які, ймовірно, розкидані по y_train встановити. Відфільтрований X_train stil має свої оригінальні індекси, а індекс має прогалини, де ми видалили викиди! Тоді ми можемо використати індекс X_train DataFrame для пошуку відповідних значень y_train:

y_train = y_train.iloc[X_train.index]

Зробивши це, ми можемо переглянути y_train форму знову:

y_train.shape

Які результати:

(1714,)

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

тепер, y_train також має 1714 рядків, і вони такі ж, як у X_train рядки. Ми нарешті готові створити нашу модель логістичної регресії!

Впровадження моделі логістичної регресії

Найважче зроблено! Попередня обробка зазвичай складніша, ніж розробка моделі, коли йдеться про використання таких бібліотек, як Scikit-Learn, які оптимізували застосування моделей ML лише до кількох рядків.

По-перше, ми імпортуємо LogisticRegression клас і створити його екземпляр, створюючи a LogisticRegression об’єкт:

from sklearn.linear_model import LogisticRegression
logreg = LogisticRegression(random_state=SEED)

По-друге, ми адаптуємо дані про поїзди до logreg модель з fit() і передбачити наші тестові дані за допомогою predict() метод, що зберігає результати як y_pred:



logreg.fit(X_train.values, y_train)
y_pred = logreg.predict(X_test)

Ми вже зробили прогнози з нашою моделлю! Давайте подивимося на перші 3 рядки X_train щоб побачити, які дані ми використали:

X_train[:3]

Наведений вище код виводить:

       Area          Perimeter     Major_Axis_Length    Minor_Axis_Length    Convex_Area   Equiv_Diameter       Eccentricity  Solidity      Extent        Roundness     Aspect_Ration        Compactness
0      -1.098308     -0.936518     -0.607941            -1.132551            -1.082768     -1.122359            0.458911      -1.078259     0.562847      -0.176041     0.236617             -0.360134
1      -0.501526     -0.468936     -0.387303            -0.376176            -0.507652     -0.475015            0.125764      0.258195      0.211703      0.094213      -0.122270            0.019480
2      0.012372      -0.209168     -0.354107            0.465095              0.003871      0.054384            -0.453911     0.432515      0.794735      0.647084      -0.617427            0.571137

І при перших 3 передбаченнях в y_pred щоб побачити результати:

y_pred[:3] 

Це призводить до:

array([0, 0, 0])

Для цих трьох рядків наші прогнози полягали в тому, що це було насіння першого класу, Çerçevelik.

з логістична регресія, замість прогнозування остаточного класу, наприклад 0, ми також можемо передбачити ймовірність того, що рядок належить до 0 клас. Ось що насправді відбувається, коли логістична регресія класифікує дані, і predict() метод потім пропускає це передбачення через поріг, щоб повернути «жорсткий» клас. Щоб передбачити ймовірність належності до класу, predict_proba() використовується:

y_pred_proba = logreg.predict_proba(X_test)

Давайте також подивимося на перші 3 значення прогнозів ймовірностей y:

y_pred_proba[:3] 

Які результати:

        # class 0   class 1   
array([[0.54726628, 0.45273372],
       [0.56324527, 0.43675473],
       [0.86233349, 0.13766651]])

Тепер замість трьох нулів у нас один стовпець для кожного класу. У колонці ліворуч, починаючи з 0.54726628, це ймовірності даних, що відносяться до класу 0; і в правій колонці, починаючи з 0.45273372, це ймовірність того, що він відноситься до класу 1.

Примітка: Ця різниця в класифікації також відома як жорсткий та м'який передбачення. Жорстке передбачення поміщає передбачення в клас, тоді як м’яке передбачення виводить ймовірність примірника, що належить до класу.

Існує більше інформації про те, як було зроблено прогнозований вихід. Це не було насправді 0, але ймовірність класу 55%. 0, і 45% шанс класу 1. Це поверхні, як перші три X_test точки даних, що відносяться до класу 0, дійсно зрозумілі лише щодо третьої точки даних, з імовірністю 86% – і не так багато для перших двох точок даних.

Коли ви повідомляєте результати за допомогою методів ML, зазвичай найкраще повертати м’який клас і відповідну ймовірність як «впевненість» цієї класифікації.

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

Оцінка моделі за допомогою звітів про класифікацію

Третій крок — побачити, як модель працює на тестових даних. Ми можемо імпортувати Scikit-Learn classification_report() і передайте наші y_test та y_pred як аргументи. Після цього ми можемо роздрукувати його відповідь.

Звіт про класифікацію містить найбільш використовувані показники класифікації, такі як точність, згадувати, f1-оцінка та точність.

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

$$
точність = frac{текст{істинний позитивний}}{текст{істинний позитивний} + текст{хибний позитивний}}
$$

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

$$
recall = frac{текст{істинний позитивний}}{текст{істинний позитивний} + текст{хибний негативний}}
$$

  1. F1 бал: є збалансованим або гармонійне середнє точності та відкликання. Найменше значення 0, а найвище 1. Коли f1-score дорівнює 1, це означає, що всі класи були правильно передбачені – цей показник дуже важко отримати з реальними даними:

$$
text{f1-score} = 2* frac{text{precision} * text{recall}}{text{precision} + text{recall}}
$$

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

$$
точність = frac{текст{кількість правильних прогнозів}}{текст{загальна кількість прогнозів}}
$$

Примітка: Надзвичайно важко отримати 100% точність будь-яких реальних даних, якщо це станеться, майте на увазі, що може статися якийсь витік або щось не так – немає консенсусу щодо ідеального значення точності, і воно також залежить від контексту. Значення 70%, що означає, що класифікатор помилятиметься на 30% даних, або вище 70%, як правило, достатньо для більшості моделей.

from sklearn.metrics import classification_report
cr = classification_report(y_test, y_pred)
print(cr)

Потім ми можемо переглянути результат класифікаційного звіту:

				precision    recall  f1-score   support

           0       0.83      0.91      0.87       316
           1       0.90      0.81      0.85       309

    accuracy                           0.86       625
   macro avg       0.86      0.86      0.86       625
weighted avg       0.86      0.86      0.86       625

Це наш результат. Зверніть увагу на це precision, recall, f1-score та accuracy усі показники дуже високі, понад 80%, що є ідеальним, але на ці результати, ймовірно, вплинула висока кореляція, і вони не збережуться в довгостроковій перспективі.

Точність моделі становить 86%, тобто вона помиляється в класифікації в 14% випадків. У нас є така загальна інформація, але було б цікаво дізнатися, чи трапляються 14% помилок щодо класифікації класу 0 або класу 1. Щоб визначити, які класи неправильно визначені як які та з якою частотою, ми можемо обчислити та побудувати графік матриця плутанини прогнозів нашої моделі.

Оцінка моделі за допомогою матриці плутанини

Давайте обчислимо, а потім побудуємо матрицю плутанини. Зробивши це, ми зможемо зрозуміти кожну його частину. Щоб побудувати матрицю плутанини, ми використаємо Scikit-Learn confusion_matrix(), який ми імпортуємо з metrics модуль

Матрицю плутанини легше візуалізувати за допомогою Seaborn heatmap(). Отже, після її генерації ми передамо нашу матрицю плутанини як аргумент для теплової карти:

from sklearn.metrics import confusion_matrix

cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt='d')

Повний посібник із логістичної регресії в Python PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

  1. Матриця плутанини: матриця показує, скільки зразків модель отримала правильних чи неправильних для кожного класу. Значення, які були правильними і правильно передбачуваними, називаються справжні позитиви, а ті, які були прогнозовані як позитивні, але не були позитивними, називаються помилкові позитиви. Та сама номенклатура справжні негативи та помилкові негативи використовується для від’ємних значень;

Подивившись на графік матриці плутанини, ми можемо побачити, що маємо 287 цінності, які були 0 і передбачив як 0 - або справжні позитиви для класу 0 (насіння Çerçevelik). У нас також є 250 справжні позитиви для класу 1 (насіння Ürgüp Sivrisi). Справжні позитиви завжди розташовані на діагоналі матриці, яка йде від верхнього лівого кута до нижнього правого.

У нас також є 29 цінності, які мали бути 0, але прогнозовано як 1 (помилкові позитиви) і 59 цінності, які були 1 і передбачив як 0 (помилкові негативи). З цими цифрами ми можемо зрозуміти, що найбільша помилка моделі полягає в тому, що вона передбачає помилкові негативні результати. Отже, здебільшого можна класифікувати насіння Ürgüp Sivrisi як насіння Çerçevelik.

Ця помилка також пояснюється 81% запам'ятовування класу 1. Зверніть увагу, що метрики пов’язані. І різниця у відкликанні походить від наявності на 100 менше зразків класу Ürgüp Sivrisi. Це один із наслідків наявності всього на кілька зразків менше, ніж в іншому класі. Щоб ще більше покращити запам’ятовування, ви можете поекспериментувати з вагами класів або використовувати більше зразків Ürgüp Sivrisi.

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

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

В ідеалі за допомогою CV і пошуку в сітці ви також можете реалізувати об’єднаний спосіб виконання етапів попередньої обробки даних, розділення даних, моделювання та оцінювання – що стає простіше за допомогою Scikit-Learn трубопроводи.

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

Заглиблюючись у те, як насправді працює логістична регресія

Команда регресія Слово тут не випадково, щоб зрозуміти, що робить логістична регресія, ми можемо згадати, що робить із даними її рідна сестра, лінійна регресія. Формула лінійної регресії була наступною:

$$
y = b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n
$$

У якому b0 був відрізком регресії, b1 коефіцієнт і х1 дані.

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

Повний посібник із логістичної регресії в Python PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

Зауважте, що в той час як лінія лінійної регресії продовжується і складається з безперервних нескінченних значень, крива логістичної регресії може бути розділена посередині та має екстремуми в значеннях 0 і 1. Ця форма «S» є причиною, по якій дані класифікуються: точки, які знаходяться ближче або припадають на найвищу кінцівку, належать до класу 1, тоді як точки, які знаходяться в нижньому квадранті або ближче до 0, належать до класу 0. Середина «S» — це середина між 0 і 1, 0.5 — це поріг для точок логістичної регресії.

Повний посібник із логістичної регресії в Python PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

Ми вже розуміємо візуальну різницю між логістичною та лінійною регресією, але як щодо формули? Формула логістичної регресії така:

$$
y = b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n
$$

Це також можна записати так:

$$
y_{prob} = frac{1}{1 + e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}}
$$

Або навіть записати так:

$$
y_{prob} = frac{e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}}{1 + e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}}
$$

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

А яке значення в знаменнику? це є e, основа натурального логарифма (приблизно 2.718282), зведена до степеня лінійної регресії:

$$
e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}
$$

Інший спосіб написання:

$$
ln ліворуч (frac{p}{1-p} праворуч) = {(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}
$$

У цьому останньому рівнянні ln є натуральним логарифмом (за основою e) і p є ймовірністю, тому логарифм ймовірності результату такий самий, як і результат лінійної регресії.

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

Весь процес виведення логістичної регресії такий:

$$
p{X} = frac{e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}}{1 + e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}}
$$

$$
p(1 + e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}) = e^{(b_0 + b_1 * x_1 + b_2 *x_2 + b_3 * x_3 + ldots + b_n * x_n)}
$$

$$
p + p*e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)} = e^{(b_0 + b_1 * x_1 + b_2 *x_2 + b_3 * x_3 + ldots + b_n * x_n)}
$$

p
=

e

(

b
0

+

b
1

*

x
1

+

b
2

*

x
2

+

b
3

*

x
3

+
...
+

b
n

*

x
n

)

-
p
*

e

(

b
0

+

b
1

*

x
1

+

b
2

*

x
2

+

b
3

*

x
3

+
...
+

b
n

*

x
n

)

$$
frac{p}{1-p} = e^{(b_0 + b_1 * x_1 + b_2 *x_2 + b_3 * x_3 + ldots + b_n * x_n)}
$$

$$
ln ліворуч (frac{p}{1-p} праворуч) = (b_0 + b_1 * x_1 + b_2 *x_2 + b_3 * x_3 + ldots + b_n * x_n)
$$

Це означає, що модель логістичної регресії також має коефіцієнти та значення перетину. Оскільки він використовує лінійну регресію та додає до неї нелінійний компонент із натуральним логарифмом (e).

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

logreg.coef_

Який відображає коефіцієнти кожної з 12 ознак:

array([[ 1.43726172, -1.03136968,  0.24099522, -0.61180768,  1.36538261,
        -1.45321951, -1.22826034,  0.98766966,  0.0438686 , -0.78687889,
         1.9601197 , -1.77226097]])
logreg.intercept_

Це призводить до:

array([0.08735782])

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

X_test[:1]

Це повертає перший рядок X_test як масив NumPy:

array([[-1.09830823, -0.93651823, -0.60794138, -1.13255059, -1.0827684 ,
        -1.12235877,  0.45891056, -1.07825898,  0.56284738, -0.17604099,
         0.23661678, -0.36013424]])

За початковим рівнянням:

$$
p{X} = frac{e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}}{1 + e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}}
$$

У Python ми маємо:

import math

lin_reg = logreg.intercept_[0] + 
((logreg.coef_[0][0]* X_test[:1][0][0])+ 
(logreg.coef_[0][1]* X_test[:1][0][1])+ 
(logreg.coef_[0][2]* X_test[:1][0][2])+ 
(logreg.coef_[0][3]* X_test[:1][0][3])+ 
(logreg.coef_[0][4]* X_test[:1][0][4])+ 
(logreg.coef_[0][5]* X_test[:1][0][5])+ 
(logreg.coef_[0][6]* X_test[:1][0][6])+ 
(logreg.coef_[0][7]* X_test[:1][0][7])+ 
(logreg.coef_[0][8]* X_test[:1][0][8])+ 
(logreg.coef_[0][9]* X_test[:1][0][9])+ 
(logreg.coef_[0][10]* X_test[:1][0][10])+ 
(logreg.coef_[0][11]* X_test[:1][0][11]))

px = math.exp(lin_reg)/(1 +(math.exp(lin_reg)))
px

Це призводить до:

0.45273372469369133

Якщо ми знову подивимось на predict_proba результат першого X_test лінії, маємо:

logreg.predict_proba(X_test[:1])


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

1 - px


Зауважте, що обидва px та 1-px ідентичні predict_proba результати. Ось як розраховується логістична регресія і чому регресія є частиною його назви. Але що з терміном логістичний?

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

$$
Ліворуч (frac{p}{1-p} праворуч)
$$

Ми щойно розрахували це за допомогою px та 1-px. Це логіт, який ще називають логарифмічні коефіцієнти оскільки він дорівнює логарифму шансів де p це ймовірність.

Висновок

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

Спочатку ми реалізували логістичну регресію як чорну скриньку з бібліотекою машинного навчання Scikit-Learn, а пізніше ми крок за кроком розібралися в цьому, щоб чітко зрозуміти, чому та звідки походять терміни регресія та логістика.

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

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

Примітка: Доступна хороша колекція наборів даних тут для того, щоб з вами пограти.

Також радив би вивчити L1 і L2 регулярізації, вони є способом «покарати» вищі дані, щоб вони стали ближчими до нормальних, зберігаючи складність моделі, щоб алгоритм міг отримати кращий результат. Реалізація Scikit-Learn, яку ми використовували, уже має регулярізацію L2 за замовчуванням. Інша річ, на яку варто звернути увагу, — це інше вирішувачі, Такі, як lbgs, які оптимізують роботу алгоритму логістичної регресії.

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

  • спостереження незалежні;
  • немає мультиколінеарності між пояснювальними змінними;
  • немає екстремальних викидів;
  • існує лінійна залежність між пояснювальними змінними та логітом змінної відповіді;
  • розмір вибірки достатньо великий.

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

Сподіваюся, ви продовжуєте досліджувати, що може запропонувати логістична регресія в усіх її різних підходах!

Часова мітка:

Більше від Stackabuse