Логистическая регрессия — это метод машинного обучения для задач бинарной классификации (0 или 1), который можно использовать для оценки вероятности чего-либо. Например, возможность того, что пользователь купит определенный продукт, возможность пациента, страдающего определенным заболеванием, и возможность того, что пользователь нажмет на рекламу.
Общее содержание этой статьи выглядит следующим образом:
- Выберите функцию предсказания.
- Вычислите функцию потерь.
- Вычислите минимум функции потерь, используя градиентный спуск.
- Векторизировать.
- Реализуйте алгоритм логистической регрессии на основе градиентного спуска.
- Полиномиальные признаки.
- Мультикатегория.
- Регуляризация.
функция предсказания
Хотя у логистической регрессии есть слово «регрессия», на самом деле это алгоритм классификации, который можно использовать для задач бинарной классификации (конечно, его также можно использовать для задач множественной классификации, которые будут представлены в следующих главах). Функция прогнозирования выбирает сигмовидную функцию, и выражение функции выглядит следующим образом:
Вы можете использовать код Python, чтобы нарисовать его:
import numpy as np
import matplotlib.pyplot as plt
def sigmoid(t):
return 1. / (1. + np.exp(-t))
x = np.linspace(-10, 10, 500)
plt.plot(x, sigmoid(x))
plt.show()
Для случая линейной границы его выражение:
Определите функцию предсказания как:
Выражается как вероятность исхода, принимающего 1, поэтому:
Построить функцию потерь
Функция потерь определяется следующим образом:
Выполните преобразование:
Градиентный спуск для решения функции потерь
Чтобы найти минимальное значение функции потерь, вы можете использовать метод градиентного спуска, гдеДля размера шага обучения:
Ниже приводится результат после частной производной:
Конкретный процесс вывода выглядит следующим образом:
так:
Поскольку 1/m — константа,также является константой, поэтому окончательное выражение:
векторизация
Окончательный результат после векторизации:
Конкретное происхождение -todo
Python реализует логистическую регрессию
Ниже приведен алгоритм логистической регрессии, реализованный в коде Python, использующий градиентный спуск для оптимизации функции потерь.
def __init__(self):
self.coef_ = None
self.intercept_ = None
self._theta = None
def _sigmoid(self, t):
return 1. / (1. + np.exp(-t))
def fit(self, X_train, y_train, eta=0.01, n_iters=1e4):
X_b = np.hstack([np.ones((len(X_train), 1)), X_train])
initial_theta = np.zeros(X_b.shape[1])
self._theta = gradient_descent(X_b, y_train, initial_theta, eta, n_iters)
self.intercept_ = self._theta[0]
self.coef_ = self._theta[1:]
return self
Код реализации градиентного спуска выглядит следующим образом:
def J(theta, X_b, y):
y_hat = self._sigmoid(X_b.dot(theta))
try:
return - np.sum(y*np.log(y_hat) + (1-y)*np.log(1-y_hat)) / len(y)
except:
return float('inf')
def dJ(theta, X_b, y):
return X_b.T.dot(self._sigmoid(X_b.dot(theta)) - y) / len(y)
def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8):
theta = initial_theta
cur_iter = 0
while cur_iter < n_iters:
gradient = dJ(theta, X_b, y)
last_theta = theta
theta = theta - eta * gradient
if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
break
cur_iter += 1
return theta
Метод прогнозирования и метод подсчета очков:
def predict(self, X_predict):
assert self.intercept_ is not None and self.coef_ is not None, \
"must fit before predict!"
assert X_predict.shape[1] == len(self.coef_), \
"the feature number of X_predict must be equal to X_train"
X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict])
proba = self._sigmoid(X_b.dot(self._theta))
return np.array(proba >= 0.5, dtype='int')
def score(self, X_test, y_test):
y_predict = self.predict(X_test)
assert len(y_true) == len(y_predict), \
"the size of y_true must be equal to the size of y_predict"
return np.sum(y_true == y_predict) / len(y_true)
Полиномиальные функции
В приведенных выше предположениях граница решения рассматривается как прямая линия. Часто распределение точек выборки нелинейно. Мы можем ввести полиномиальные члены, чтобы изменить распределение выборок.
Сначала мы моделируем набор данных с нелинейным распределением:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(666)
X = np.random.normal(0, 1, size=(200, 2))
y = np.array(X[:,0]**2 + X[:,1]**2 < 1.5, dtype='int')
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()
Для такого набора данных это можно решить только путем добавления полиномов, код выглядит следующим образом:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
def PolynomialLogisticRegression(degree):
return Pipeline([
# 给样本特征添加多形式项;
('poly', PolynomialFeatures(degree=degree)),
# 数据归一化处理;
('std_scaler', StandardScaler()),
('log_reg', LogisticRegression())
])
poly_log_reg = PolynomialLogisticRegression(degree=2)
poly_log_reg.fit(X, y)
plot_decision_boundary(poly_log_reg, axis=[-4, 4, -4, 4])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()
Граница решения для окончательных данных выглядит следующим образом:
def plot_decision_boundary(model, axis):
x0, x1 = np.meshgrid(
np.linspace(axis[0], axis[1], int((axis[1]-axis[0])*100)).reshape(-1,1),
np.linspace(axis[2], axis[3], int((axis[3]-axis[2])*100)).reshape(-1,1)
)
X_new = np.c_[x0.ravel(), x1.ravel()]
y_predict = model.predict(X_new)
zz = y_predict.reshape(x0.shape)
from matplotlib.colors import ListedColormap
custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)
Проблема мультиклассификации
Выше мы упоминали, что логистическая регрессия может решать только задачи с двумя классами, а решение задач с несколькими классами требует дополнительного преобразования. Обычно есть два пути:
- OVR (One vs Rest), пара оставшихся значений.
- OVO (One vs One) означает «один на один».
Эти два метода можно использовать не только для алгоритмов логистической регрессии, но и для всех алгоритмов машинного обучения бинарной классификации, Этот метод можно использовать для преобразования задач бинарной классификации в задачи множественной классификации.
OVR
Как показано на рисунке выше, при классификации n типов выбороксоответственноВозьмите определенный класс образцов как один класс и обработайте оставшиеся n-1 образцов класса как другой класс, чтобы его можно было преобразовать в n задач бинарной классификации. Наконец, можно получить n моделей алгоритмов (как показано на рисунке выше, в итоге будет 4 модели алгоритмов), и выборки, которые необходимо предсказать, передаются в n моделей соответственно, а тип выборки соответствует модели с наибольшая вероятность является результатом предсказания.
Для проблемы множественной классификации логистической регрессии в sklearn по умолчанию используется метод ovo. В то же время sklearn также предоставляет общий метод вызова:
from sklearn.multiclass import OneVsRestClassifier
from sklearn.linear_model import LogisticRegression
log_reg = LogisticRegression()
ovr = OneVsRestClassifier(log_reg)
ovr.fit(X_train, y_train)
ovr.score(X_test, y_test)
OVO
Среди n типов образцов каждый раз выбираются два типа образцов, и, наконец, формируютсяДихотомический случай, т.алгоритмическая модель, естьРезультат прогнозирования, тип выборки с наибольшим разнообразием среди этих результатов является окончательным результатом прогнозирования.
В реализации логистической регрессии sklearn ovr используется по умолчанию для мультиклассификации.Если вы используете ovo, вам нужно указатьmulti_class
,в то же времяsolver
Параметры также необходимо изменить (p.s: sklearn не использует градиентный спуск, как описано выше, для оптимизации функции потерь):
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
iris = datasets.load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
log_reg2 = LogisticRegression(multi_class="multinomial", solver="newton-cg")
log_reg2.fit(X_train, y_train)
log_reg2.score(X_test, y_test)
from sklearn.multiclass import OneVsRestClassifier
ovr = OneVsRestClassifier(log_reg)
ovr.fit(X_train, y_train)
ovr.score(X_test, y_test)
from sklearn.multiclass import OneVsOneClassifier
ovo = OneVsOneClassifier(log_reg)
ovo.fit(X_train, y_train)
ovo.score(X_test, y_test)
Регуляризация
Обычно выражение регуляризации выглядит следующим образом:
Вы можете преобразовать его и изменить местоположение гиперпараметра. Если гиперпараметр C больше, исходная функция потерьположение относительно важно. Если гиперпараметры очень малы, положение регуляризатора относительно важно. Если вы хотите сделать обычный член неважным, вам нужно увеличить параметр C. Это выражение обычно используется в sklearn.
Алгоритм логистической регрессии в sklearn автоматически инкапсулирует функцию регуляризации модели, и ему нужно только настроить C и штраф (выбор регулярного термина).или.