Полное руководство по логистической регрессии в Python PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.

Полное руководство по логистической регрессии в Python

Введение

Иногда путают с линейная регрессия новичками - из-за совместного использования термина регресслогистическая регрессия сильно отличается от линейная регрессия. В то время как линейная регрессия предсказывает такие значения, как 2, 2.45, 6.77 или непрерывные значения, делая это регресс алгоритм, логистическая регрессия предсказывает такие значения, как 0 или 1, 1 или 2 или 3, которые дискретные значения, делая это классификация алгоритм. Да, это называется регресс но это классификация алгоритм. Подробнее об этом чуть позже.

Поэтому, если ваша задача по науке о данных связана с непрерывными значениями, вы можете применить регресс алгоритм (линейная регрессия является одним из них). В противном случае, если речь идет о классификации входных данных, дискретных значений или классов, вы можете применить классификация алгоритм (логистическая регрессия является одним из них).

В этом руководстве мы будем выполнять логистическую регрессию на Python с помощью библиотеки Scikit-Learn. Мы также объясним, почему слово «регресс» присутствует в названии и в том, как работает логистическая регрессия.

Для этого мы сначала загрузим данные, которые будут классифицированы, визуализированы и предварительно обработаны. Затем мы построим модель логистической регрессии, которая будет понимать эти данные. Затем эта модель будет оценена и использована для прогнозирования значений на основе новых входных данных.

мотивация

Компания, в которой вы работаете, стала партнером турецкой сельскохозяйственной фермы. Это партнерство предполагает продажу тыквенных семечек. Семена тыквы очень важны для питания человека. Они содержат хорошую пропорцию углеводов, жиров, белков, кальция, калия, фосфора, магния, железа и цинка.

В команде по науке о данных ваша задача состоит в том, чтобы определить разницу между типами тыквенных семечек, просто используя данные — или сортировка данные в зависимости от типа семян.

Турецкая ферма работает с двумя видами семян тыквы, один из которых называется Черчевелик и другие Ургюп Сивриси.

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

После завершения процесса, описанного в статье, были извлечены следующие измерения:

  • Площадь – количество пикселей в границах тыквенного семени
  • Периметр – окружность тыквенного семени в пикселях
  • Длина большой оси — также окружность в пикселях тыквенного семени
  • Длина малой оси - расстояние малой оси тыквенного семени
  • эксцентричность - эксцентриситет тыквенного семени
  • Выпуклая область – количество пикселей наименьшей выпуклой оболочки в области, образованной тыквенным семенем
  • степень – отношение площади тыквенного семени к пикселям ограничивающей рамки
  • Эквивалентный диаметр – квадратный корень из произведения площади тыквенного семени на четыре, деленный на число пи
  • Компактность – доля площади тыквенного семени по отношению к площади круга с такой же длиной окружности
  • основательность – выпуклость и выпуклость семян тыквы
  • круглость – овальность тыквенных семечек без учета искажения ее краев
  • Соотношение сторон - соотношение сторон тыквенных семечек

Это измерения, с которыми вы должны работать. Кроме замеров есть еще Класс Этикетка для двух видов тыквенных семечек.

Чтобы начать классифицировать семена, давайте импортируем данные и начнем их рассматривать.

Понимание набора данных

Примечание: Вы можете скачать набор данных тыквы здесь.

После загрузки набора данных мы можем загрузить его в структуру фрейма данных с помощью 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 образцов Черчевелик семян и 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. Вертикальный поиск. Ай.

На графике выше обратите внимание, что Area и Convex_Area имеют такую ​​большую величину по сравнению с величинами других столбцов, что они раздавливают другие диаграммы. Чтобы иметь возможность просматривать все диаграммы, мы можем масштабировать функции и снова отображать их.

Прежде чем сделать это, давайте просто поймем, что если есть значения признаков, которые тесно связаны с другими значениями, например, если есть значения, которые также становятся больше, когда другие значения признаков становятся больше, имея Положительная корреляция; или, если есть значения, которые делают обратное, становятся меньше, в то время как другие значения становятся меньше, имея отрицательная корреляция.

Это важно учитывать, потому что наличие сильных связей в данных может означать, что некоторые столбцы были получены из других столбцов или имеют значение, аналогичное нашей модели. Когда это происходит, результаты модели могут быть завышены, и нам нужны результаты, более близкие к реальности. Если есть сильная корреляция, это также означает, что мы можем уменьшить количество признаков и использовать меньше столбцов, что сделает модель более удобной. экономный.

Примечание: Корреляция по умолчанию, рассчитанная с помощью corr() метод является Коэффициент корреляции Пирсона. Этот коэффициент указывается, когда данные являются количественными, нормально распределенными, не имеют выбросов и имеют линейную зависимость.

Другим вариантом было бы вычислить Коэффициент корреляции Спирмена. Коэффициент Спирмена используется, когда данные порядковые, нелинейные, имеют любое распределение и имеют выбросы. Обратите внимание, что наши данные не полностью соответствуют предположениям Пирсона или Спирмена (есть и другие методы корреляции, такие как метод Кендалла). Поскольку наши данные количественные и нам важно измерить их линейную зависимость, мы будем использовать коэффициент Пирсона.

Давайте посмотрим на корреляции между переменными, а затем мы можем перейти к предварительной обработке данных. Мы рассчитаем корреляции с corr() метод и визуализировать их с помощью Seaborn 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. Вертикальный поиск. Ай.

На этой тепловой карте нам нужно обратить внимание на значения, близкие к 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. В этом случае мы бы представили утечка данных, так как значения тестового набора, который скоро появится, повлияли бы на масштабирование. Утечка данных — частая причина невоспроизводимых результатов и кажущейся высокой производительности моделей машинного обучения.

Размышление о масштабировании показывает, что нам нужно сначала разделить X и y данные дальше в обучающие и тестовые наборы, а затем в соответствовать скейлер на тренировочном наборе, и трансформировать как обучающий, так и тестовый наборы (без того, чтобы тестовый набор влиял на масштабировщик, который это делает). Для этого мы будем использовать Scikit-Learn’s 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. Вертикальный поиск. Ай.

Наконец-то мы можем увидеть все наши боксплоты! Обратите внимание, что все они имеют выбросы и особенности, которые представляют собой распределение, более далекое от нормального (с кривыми, наклоненными влево или вправо), такие как 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. Вертикальный поиск. Ай.

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

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, которые упростили применение моделей машинного обучения всего до пары строк.

Сначала мы импортируем LogisticRegression класс и создайте его экземпляр, создав 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. Точность: чтобы понять, какие правильные значения прогноза были сочтены правильными нашим классификатором. Точность разделит эти истинные положительные значения на все, что было предсказано как положительное:

$$
точность = дробь {текст {истинно положительный}} {текст {истинно положительный} + текст {ложноположительный}}
$$

  1. Вспоминать: чтобы понять, сколько истинных срабатываний определил наш классификатор. Отзыв рассчитывается путем деления истинных положительных результатов на все, что должно было быть предсказано как положительное:

$$
отзыв = frac {текст {истинно положительный}} {текст {истинно положительный} + текст {ложноотрицательный}}
$$

  1. Счет F1: является сбалансированным или среднее гармоническое точности и отзыва. Наименьшее значение равно 0, а максимальное — 1. Когда f1-score равно 1, это означает, что все классы были предсказаны правильно — это очень сложная оценка для реальных данных:

$$
текст{f1-оценка} = 2* дробь{текст{точность} * текст{отзыв}}{текст{точность} + текст{отзыв}}
$$

  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. Вертикальный поиск. Ай.

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

Глядя на график матрицы путаницы, мы видим, что у нас есть 287 ценности, которые были 0 и предсказано как 0 - или настоящие позитивы для класса 0 (семена черчевелика). У нас также есть 250 настоящие плюсы для класса 1 (семена Ürgüp Sivrisi). Истинные позитивы всегда располагаются на диагонали матрицы, идущей от левого верхнего угла к правому нижнему.

У нас также есть 29 значения, которые должны были быть 0, но предсказывается как 1 (ложные срабатывания) и расширение 59 ценности, которые были 1 и предсказано как 0 (ложные негативы). С этими числами мы можем понять, что ошибка, которую делает модель больше всего, заключается в том, что она предсказывает ложноотрицательные результаты. Таким образом, в основном это может привести к тому, что семя Ürgüp Sivrisi будет классифицировано как семя Черчевелика.

Такого рода ошибки также объясняются 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
$$

в котором б0 был пересечением регрессии, b1 коэффициент и х1 данные.

Это уравнение привело к прямой линии, которая использовалась для прогнозирования новых значений. Вспоминая введение, разница теперь в том, что мы будем предсказывать не новые значения, а класс. Так что эту прямую нужно изменить. С помощью логистической регрессии мы вводим нелинейность, и теперь прогноз делается с использованием кривой вместо линии:

Полное руководство по логистической регрессии в Python PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.

Обратите внимание, что в то время как линия линейной регрессии продолжает двигаться и состоит из непрерывных бесконечных значений, кривая логистической регрессии может быть разделена посередине и иметь экстремумы в значениях 0 и 1. Эта форма «S» является причиной, по которой она классифицирует данные — точки, которые находятся ближе или попадают на самую высокую оконечность, принадлежат к классу 1, а точки, которые находятся в нижнем квадранте или ближе к 0, принадлежат к классу 0. Середина «S» — это среднее между 0 и 1, 0.5 — это порог для точек логистической регрессии.

Полное руководство по логистической регрессии в Python PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.

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

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

Его также можно записать как:

$$
y_{вероятность} = frac{1}{1 + e^{(b_0 + b_1 * x_1 + b_2 * x_2 + b_3 * x_3 + ldots + b_n * x_n)}}
$$

Или даже быть записано как:

$$
y_{вероятность} = 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 слева (фракция {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 + б_н * х_н)}
$$

$$
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 + б_н * х_н)}
$$

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 слева (фракция {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)}}
$$

В питоне имеем:

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 полученные результаты. Вот как рассчитывается логистическая регрессия и почему регресс является частью его имени. Но как быть с термином логистический?

Термин логистический происходит от логит, функцию, которую мы уже видели:

$$
ln влево( frac{p}{1-p} вправо)
$$

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

Заключение

В этом руководстве мы изучили один из самых фундаментальных алгоритмов классификации машинного обучения, т.е. логистическая регрессия.

Первоначально мы реализовали логистическую регрессию в виде черного ящика с библиотекой машинного обучения Scikit-Learn, а позже разобрались с ней шаг за шагом, чтобы понять, почему и откуда берутся термины регрессия и логистика.

Мы также исследовали и изучили данные, понимая, что это одна из наиболее важных частей анализа данных.

Отсюда я бы посоветовал вам поиграть с мультиклассовая логистическая регрессия, логистическая регрессия для более чем двух классов — вы можете применить тот же алгоритм логистической регрессии для других наборов данных, которые имеют несколько классов, и интерпретировать результаты.

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

Я бы еще посоветовал изучить L1 и L2 регуляризации, это способ «наказать» более высокие данные, чтобы они стали ближе к нормальным, сохраняя сложность модели, чтобы алгоритм мог получить лучший результат. Используемая нами реализация Scikit-Learn уже по умолчанию имеет регуляризацию L2. Еще одна вещь, на которую стоит обратить внимание, это разные решатели, Такие, как lbgs, которые оптимизируют производительность алгоритма логистической регрессии.

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

  • наблюдения независимы;
  • нет мультиколлинеарности среди объясняющих переменных;
  • нет экстремальных выбросов;
  • существует линейная зависимость между независимыми переменными и логитом переменной отклика;
  • объем выборки достаточно велик.

Обратите внимание, сколько из этих предположений уже учтено в нашем анализе и обработке данных.

Надеюсь, вы продолжите изучать возможности логистической регрессии во всех ее различных подходах!

Отметка времени:

Больше от Стекабьюс