OvR 与 OvO - 逻辑回归解决多分类问题
所有的二分类算法都可以通过以下的方法改造成多分类算法:
-
OvR (One vs Rest) 也叫 (One vs All) 每次只做二分类,区分这个新来的样本点在一个类别和其他的类别中的预测值,然后对其他类别也做这样的分类,得到在每个分类上的预测值,取最大的值对应的类别为这个新来样本点的类别。
n个类别就要n个分类, 处理一个分类要T, 则要N*T的复杂度 -
OvO (One vs One) 每次只挑出2个类别进行二分类, 如果总共有4个类别,则可以形成 $C_4^2 = 6$ 对这样的分类。 复杂度: $C_n^2 * T$. 因为每次都只用2个类别比较,没有混淆其他类别的信息,所有分类会更加准确。
sklearn 中的Logistic Regression默认支持多分类,用超参数为 multi_class = 'ovr' or 'ovo'
我这个版本sklearn默认使用 multiclass='ovo', solver='newton-cg' 方式, 既ovo mode. 可以通过使用multiclass='ovr', solver='liblinear'改成ovr mode.
鸢尾花测试数据用2维样本特征做3分类:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data
y = iris.target
X = X[:, :2]#为了可视化,这里只取iris里的前2个维度作为特征进行fit
y = y[:] #分类3中鸢尾花,不再是二分类问题,而是多分类问题了
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
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, cmap=custom_cmap)
ovo 多分类模式:
log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)
log_reg.score(X_test, y_test)
plot_decision_boundary(log_reg, [4, 8, 2, 4.5])
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.scatter(X[y==2, 0], X[y==2, 1])
结果:
score: 0.7894736842105263
ovr模式:
log_reg1 = LogisticRegression(multi_class='ovr', solver='liblinear') # 这个方式是ovr的方式
log_reg1.fit(X_train, y_train)
log_reg1.score(X_test, y_test)
plot_decision_boundary(log_reg1, [4, 8, 2, 4.5])
plt.scatter(X[y==0, 0], X[y==0, 1])
plt.scatter(X[y==1, 0], X[y==1, 1])
plt.scatter(X[y==2, 0], X[y==2, 1])
plt.title("ovr-multiclass='ovr'-solver='liblinear'")
结果:
score: 0.6578947368421053
结论:可以看出来,ovr得到的准确度没有ovo好,从决策边界看,ovo的决策边界也更合理
OvO and OvR 分类器
sklearn提供了OvO and OvR 分类器,任何一个二分类算法都可以用这2个分类器实现多分类功能。
from sklearn.multiclass import OneVsRestClassifier
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
log_reg1 = LogisticRegression(multi_class='ovr', solver='liblinear')
ovr = OneVsRestClassifier(log_reg1)
ovr.fit(X_train, y_train)
ovr.score(X_test, y_test)
score: 0.9473684210526315
from sklearn.multiclass import OneVsOneClassifier
ovo = OneVsOneClassifier(log_reg)
ovo.fit(X_train, y_train)
ovo.score(X_test, y_test)
score: 1.0