Введение
Иногда путают с линейная регрессия новичками - из-за совместного использования термина регресс – логистическая регрессия сильно отличается от линейная регрессия. В то время как линейная регрессия предсказывает такие значения, как 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')
На графике выше обратите внимание, что 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)
На этой тепловой карте нам нужно обратить внимание на значения, близкие к 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')
Наконец-то мы можем увидеть все наши боксплоты! Обратите внимание, что все они имеют выбросы и особенности, которые представляют собой распределение, более далекое от нормального (с кривыми, наклоненными влево или вправо), такие как 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.
Мы можем использовать панд 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-счети точность.
- Точность: чтобы понять, какие правильные значения прогноза были сочтены правильными нашим классификатором. Точность разделит эти истинные положительные значения на все, что было предсказано как положительное:
$$
точность = дробь {текст {истинно положительный}} {текст {истинно положительный} + текст {ложноположительный}}
$$
- Вспоминать: чтобы понять, сколько истинных срабатываний определил наш классификатор. Отзыв рассчитывается путем деления истинных положительных результатов на все, что должно было быть предсказано как положительное:
$$
отзыв = frac {текст {истинно положительный}} {текст {истинно положительный} + текст {ложноотрицательный}}
$$
- Счет F1: является сбалансированным или среднее гармоническое точности и отзыва. Наименьшее значение равно 0, а максимальное — 1. Когда
f1-score
равно 1, это означает, что все классы были предсказаны правильно — это очень сложная оценка для реальных данных:
$$
текст{f1-оценка} = 2* дробь{текст{точность} * текст{отзыв}}{текст{точность} + текст{отзыв}}
$$
- точность: описывает, сколько прогнозов наш классификатор дал правильно. Наименьшее значение точности равно 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')
- Матрица путаницы: матрица показывает, сколько выборок модель получила правильно или неправильно для каждого класса. Значения, которые были правильными и правильно предсказанными, называются настоящие позитивы, а те, которые были предсказаны как положительные, но не были положительными, называются ложные срабатывания. Та же самая номенклатура настоящие негативы и ложные негативы используется для отрицательных значений;
Глядя на график матрицы путаницы, мы видим, что у нас есть 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 данные.
Это уравнение привело к прямой линии, которая использовалась для прогнозирования новых значений. Вспоминая введение, разница теперь в том, что мы будем предсказывать не новые значения, а класс. Так что эту прямую нужно изменить. С помощью логистической регрессии мы вводим нелинейность, и теперь прогноз делается с использованием кривой вместо линии:
Обратите внимание, что в то время как линия линейной регрессии продолжает двигаться и состоит из непрерывных бесконечных значений, кривая логистической регрессии может быть разделена посередине и иметь экстремумы в значениях 0 и 1. Эта форма «S» является причиной, по которой она классифицирует данные — точки, которые находятся ближе или попадают на самую высокую оконечность, принадлежат к классу 1, а точки, которые находятся в нижнем квадранте или ближе к 0, принадлежат к классу 0. Середина «S» — это среднее между 0 и 1, 0.5 — это порог для точек логистической регрессии.
Мы уже понимаем визуальную разницу между логистической и линейной регрессией, но как насчет формулы? Формула логистической регрессии выглядит следующим образом:
$$
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
, которые оптимизируют производительность алгоритма логистической регрессии.
Также важно обратить внимание на статистический подход к логистической регрессии. Оно имеет предположения о поведении данных и о других статистических данных, которые должны выполняться, чтобы гарантировать удовлетворительные результаты, такие как:
- наблюдения независимы;
- нет мультиколлинеарности среди объясняющих переменных;
- нет экстремальных выбросов;
- существует линейная зависимость между независимыми переменными и логитом переменной отклика;
- объем выборки достаточно велик.
Обратите внимание, сколько из этих предположений уже учтено в нашем анализе и обработке данных.
Надеюсь, вы продолжите изучать возможности логистической регрессии во всех ее различных подходах!
- блокчейн
- C + +
- код
- Coingenius
- наука о данных
- визуализация данных
- Java
- Matplotlib
- невзаимозаменяемый токен
- NumPy
- OpenSea
- панд
- PHP
- Платон
- Платон Ай
- Платон Интеллектуальные данные
- Платон игра
- Платоблокчейн
- ПлатонДанные
- платогейминг
- Polygon
- Питон
- реагировать
- scikit учиться
- рожденное море
- умный контракт
- Solana
- Стекабьюс
- Vyper
- Web3
- зефирнет