# Python实现多分类Logistic回归的原理与实战解析
## 引言:从二分类到多分类的拓展
Logistic回归作为经典的分类算法,在二分类问题中表现出色。然而现实世界中的分类问题往往涉及多个类别,如新闻分类、疾病诊断、产品推荐等场景都需要将样本划分到多个类别中。多分类Logistic回归通过扩展二元模型,实现了对多类别问题的有效处理,成为机器学习领域的重要工具。
## 多分类Logistic回归理论基础
### Softmax函数与概率分布
多分类Logistic回归的核心是Softmax函数,它将线性模型的输出转换为概率分布。假设有K个类别,对于第i个样本,其属于第k个类别的概率为:
$$P(y_i=k|\mathbf{x}_i) = \frac{e^{\mathbf{w}_k^T\mathbf{x}_i}}{\sum_{j=1}^{K}e^{\mathbf{w}_j^T\mathbf{x}_i}}$$
其中$\mathbf{w}_k$是第k个类别的权重向量。
```python
import numpy as np
from typing import List, Tuple
def softmax(z: np.ndarray) -> np.ndarray:
"""
Softmax函数实现
参数:
z: 输入向量或矩阵,形状为(n_samples, n_classes)或(n_classes,)
返回:
概率分布,形状与输入相同
"""
# 数值稳定性优化:减去最大值避免指数溢出
exp_z = np.exp(z - np.max(z, axis=-1, keepdims=True))
return exp_z / np.sum(exp_z, axis=-1, keepdims=True)
# 测试Softmax函数
def test_softmax():
# 单个样本
z_single = np.array([2.0, 1.0, 0.1])
probs_single = softmax(z_single)
print(f"单个样本输入: {z_single}")
print(f"Softmax输出: {probs_single}")
print(f"概率和为: {np.sum(probs_single):.6f}")
# 多个样本
z_batch = np.array([[1, 2, 3],
[3, 2, 1],
[0, 0, 0]])
probs_batch = softmax(z_batch)
print(f"\n批量输入形状: {z_batch.shape}")
print(f"批量Softmax输出形状: {probs_batch.shape}")
print(f"每行概率和: {np.sum(probs_batch, axis=1)}")
if __name__ == "__main__":
test_softmax()
```
### 交叉熵损失函数
多分类问题使用交叉熵损失函数:
$$J(\mathbf{W}) = -\frac{1}{N}\sum_{i=1}^{N}\sum_{k=1}^{K}y_{ik}\log(p_{ik})$$
其中$y_{ik}$是真实标签的one-hot编码,$p_{ik}$是预测概率。
```python
class CrossEntropyLoss:
"""交叉熵损失函数实现"""
@staticmethod
def compute(y_true: np.ndarray, y_pred: np.ndarray, epsilon: float = 1e-12) -> float:
"""
计算交叉熵损失
参数:
y_true: 真实标签,形状(n_samples, n_classes),one-hot编码
y_pred: 预测概率,形状(n_samples, n_classes)
epsilon: 小数值避免log(0)
返回:
平均交叉熵损失
"""
# 限制预测值范围,避免数值问题
y_pred = np.clip(y_pred, epsilon, 1. - epsilon)
# 计算交叉熵
loss = -np.mean(np.sum(y_true * np.log(y_pred), axis=1))
return loss
@staticmethod
def gradient(y_true: np.ndarray, y_pred: np.ndarray) -> np.ndarray:
"""
计算损失函数的梯度
返回:
梯度,形状(n_samples, n_classes)
"""
return y_pred - y_true
def test_cross_entropy():
# 模拟数据
n_samples = 100
n_classes = 3
# 真实标签(one-hot编码)
y_true = np.zeros((n_samples, n_classes))
true_labels = np.random.randint(0, n_classes, n_samples)
y_true[np.arange(n_samples), true_labels] = 1
# 预测概率
y_pred = np.random.rand(n_samples, n_classes)
y_pred = y_pred / y_pred.sum(axis=1, keepdims=True)
# 计算损失
loss = CrossEntropyLoss.compute(y_true, y_pred)
print(f"交叉熵损失: {loss:.6f}")
# 计算梯度
grad = CrossEntropyLoss.gradient(y_true, y_pred)
print(f"梯度形状: {grad.shape}")
print(f"梯度均值: {np.mean(grad):.6f}")
if __name__ == "__main__":
test_cross_entropy()
```
## 从零实现多分类Logistic回归
### 模型实现
```python
import numpy as np
from sklearn.base import BaseEstimator, ClassifierMixin
from sklearn.preprocessing import LabelBinarizer
from sklearn.utils.validation import check_X_y, check_array, check_is_fitted
class MultinomialLogisticRegression(BaseEstimator, ClassifierMixin):
"""多分类Logistic回归模型"""
def __init__(self, learning_rate: float = 0.01,
max_iter: int = 1000,
tol: float = 1e-4,
l2_lambda: float = 0.0,
verbose: bool = False):
"""
初始化多分类Logistic回归模型
参数:
learning_rate: 学习率
max_iter: 最大迭代次数
tol: 收敛阈值
l2_lambda: L2正则化系数
verbose: 是否打印训练信息
"""
self.learning_rate = learning_rate
self.max_iter = max_iter
self.tol = tol
self.l2_lambda = l2_lambda
self.verbose = verbose
self.loss_history_ = []
def _initialize_weights(self, n_features: int, n_classes: int):
"""初始化权重矩阵"""
# 使用Xavier初始化
scale = np.sqrt(2.0 / (n_features + n_classes))
self.W_ = np.random.randn(n_features, n_classes) * scale
self.b_ = np.zeros(n_classes)
def _softmax(self, X: np.ndarray) -> np.ndarray:
"""计算Softmax概率"""
# 线性部分
scores = X @ self.W_ + self.b_
# 数值稳定的Softmax
exp_scores = np.exp(scores - np.max(scores, axis=1, keepdims=True))
probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
return probs
def fit(self, X: np.ndarray, y: np.ndarray) -> 'MultinomialLogisticRegression':
"""
训练多分类Logistic回归模型
参数:
X: 特征矩阵,形状(n_samples, n_features)
y: 标签向量,形状(n_samples,)
返回:
训练好的模型实例
"""
# 验证输入
X, y = check_X_y(X, y)
# 标签编码
self.label_binarizer_ = LabelBinarizer()
y_onehot = self.label_binarizer_.fit_transform(y)
self.classes_ = self.label_binarizer_.classes_
n_classes = len(self.classes_)
# 添加偏置项的特征
n_samples, n_features = X.shape
# 初始化权重
self._initialize_weights(n_features, n_classes)
# 梯度下降优化
for i in range(self.max_iter):
# 前向传播
probs = self._softmax(X)
# 计算损失
loss = self._compute_loss(probs, y_onehot, X)
self.loss_history_.append(loss)
# 计算梯度
grad_W, grad_b = self._compute_gradients(X, y_onehot, probs)
# 更新权重
self.W_ -= self.learning_rate * grad_W
self.b_ -= self.learning_rate * grad_b
# 检查收敛
if i > 0 and abs(self.loss_history_[-2] - loss) < self.tol:
if self.verbose:
print(f"迭代 {i}: 提前收敛,损失 = {loss:.6f}")
break
# 打印进度
if self.verbose and i % 100 == 0:
print(f"迭代 {i}: 损失 = {loss:.6f}")
# 标记模型已训练
self.is_fitted_ = True
return self
def _compute_loss(self, probs: np.ndarray,
y_onehot: np.ndarray,
X: np.ndarray) -> float:
"""计算总损失"""
# 交叉熵损失
epsilon = 1e-12
probs_clipped = np.clip(probs, epsilon, 1. - epsilon)
cross_entropy = -np.mean(np.sum(y_onehot * np.log(probs_clipped), axis=1))
# L2正则化
if self.l2_lambda > 0:
l2_penalty = 0.5 * self.l2_lambda * np.sum(self.W_ ** 2)
cross_entropy += l2_penalty
return cross_entropy
def _compute_gradients(self, X: np.ndarray,
y_onehot: np.ndarray,
probs: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
"""计算权重梯度"""
n_samples = X.shape[0]
# 误差
error = probs - y_onehot
# 权重梯度
grad_W = (X.T @ error) / n_samples
# 偏置梯度
grad_b = np.mean(error, axis=0)
# L2正则化梯度
if self.l2_lambda > 0:
grad_W += self.l2_lambda * self.W_
return grad_W, grad_b
def predict_proba(self, X: np.ndarray) -> np.ndarray:
"""
预测类别概率
参数:
X: 特征矩阵
返回:
概率矩阵,形状(n_samples, n_classes)
"""
check_is_fitted(self, 'is_fitted_')
X = check_array(X)
return self._softmax(X)
def predict(self, X: np.ndarray) -> np.ndarray:
"""
预测类别标签
参数:
X: 特征矩阵
返回:
预测标签,形状(n_samples,)
"""
probs = self.predict_proba(X)
predictions = np.argmax(probs, axis=1)
return self.classes_[predictions]
def score(self, X: np.ndarray, y: np.ndarray) -> float:
"""
计算模型准确率
参数:
X: 特征矩阵
y: 真实标签
返回:
准确率
"""
predictions = self.predict(X)
return np.mean(predictions == y)
# 测试自定义模型
def test_custom_model():
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
# 生成多分类数据
X, y = make_classification(n_samples=1000, n_features=20,
n_classes=3, n_informative=10,
random_state=42)
# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 创建和训练模型
model = MultinomialLogisticRegression(
learning_rate=0.1,
max_iter=500,
l2_lambda=0.01,
verbose=True
)
model.fit(X_train, y_train)
# 评估模型
train_acc = model.score(X_train, y_train)
test_acc = model.score(X_test, y_test)
print(f"训练准确率: {train_acc:.4f}")
print(f"测试准确率: {test_acc:.4f}")
return model
if __name__ == "__main__":
model = test_custom_model()
```
## 使用Scikit-learn实现
### 基础应用
```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
def basic_multiclass_logistic():
"""使用Scikit-learn实现多分类Logistic回归"""
# 加载经典数据集
iris = load_iris()
X = iris.data
y = iris.target
feature_names = iris.feature_names
target_names = iris.target_names
print("数据集信息:")
print(f"样本数: {X.shape[0]}, 特征数: {X.shape[1]}")
print(f"类别数: {len(np.unique(y))}")
print(f"类别名称: {target_names}")
# 数据标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(
X_scaled, y, test_size=0.3, random_state=42, stratify=y
)www.pt.wandaihu.cn>www.vs.wandaihu.cn>
# 创建多分类Logistic回归模型
# multi_class='multinomial'表示使用Softmax回归
# solver='lbfgs'支持多分类的优化算法
model = LogisticRegression(
multi_class='multinomial',
solver='lbfgs',
max_iter=1000,
C=1.0, # 正则化强度的倒数,越小正则化越强
random_state=42
)
# 训练模型
model.fit(X_train, y_train)
# 模型评估
train_score = model.score(X_train, y_train)
test_score = model.score(X_test, y_test)
print(f"\n模型性能:")
print(f"训练准确率: {train_score:.4f}")
print(f"测试准确率: {test_score:.4f}")
# 预测概率
y_pred_proba = model.predict_proba(X_test)
y_pred = model.predict(X_test)
# 详细分类报告
print("\n分类报告:")
print(classification_report(y_test, y_pred, target_names=target_names))
# 混淆矩阵
cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=target_names,
yticklabels=target_names)
plt.title('混淆矩阵')
plt.xlabel('预测标签')
plt.ylabel('真实标签')
plt.tight_layout()
plt.show()
# 特征重要性分析
feature_importance = pd.DataFrame({
'feature': feature_names,
'coefficient': np.mean(np.abs(model.coef_), axis=0)
}).sort_values('coefficient', ascending=False)
print("\n特征重要性:")
print(feature_importance)
return model, X_test, y_test, target_names
if __name__ == "__main__":
model, X_test, y_test, target_names = basic_multiclass_logistic()
```
### 模型优化与调参
```python
from sklearn.model_selection import GridSearchCV, StratifiedKFold
from sklearn.pipeline import Pipeline
def optimize_logistic_regression():
"""Logistic回归模型优化"""
# 加载数据
from sklearn.datasets import load_wine
wine = load_wine()
X, y = wine.data, wine.target
# 创建管道
pipeline = Pipeline([
('scaler', StandardScaler()),
('classifier', LogisticRegression(
multi_class='multinomial',
solver='lbfgs',
random_state=42
))www.rb.wandaihu.cn>www.mo.wandaihu.cn>
])
# 定义参数网格
param_grid = {
'classifier__C': [0.001, 0.01, 0.1, 1, 10, 100],
'classifier__max_iter': [500, 1000, 2000],
'classifier__penalty': ['l2'], # 'multinomial'只支持l2
}
# 交叉验证设置
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
# 网格搜索
grid_search = GridSearchCV(
pipeline,
param_grid,
cv=cv,
scoring='accuracy',
n_jobs=-1,
verbose=1
)
# 执行搜索
grid_search.fit(X, y)
# 输出最佳参数
print("最佳参数:")
for param, value in grid_search.best_params_.items():
print(f"{param}: {value}")
print(f"\n最佳交叉验证准确率: {grid_search.best_score_:.4f}")
# 各参数组合的结果
results_df = pd.DataFrame(grid_search.cv_results_)
print("\n参数搜索详情:")
print(results_df[['mean_test_score', 'std_test_score',
'param_classifier__C', 'param_classifier__max_iter']].head())
return grid_search
def visualize_decision_boundary():
"""可视化决策边界(适用于二维特征)"""
from sklearn.datasets import make_classification
# 生成二维数据以便可视化
X, y = make_classification(
n_samples=300,
n_features=2,
n_classes=3,
n_informative=2,
n_redundant=0,
n_clusters_per_class=1,
random_state=42
)
# 训练模型
model = LogisticRegression(
multi_class='multinomial',
solver='lbfgs',
C=1.0,
random_state=42
)
model.fit(X, y)
# 创建网格点
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
np.arange(y_min, y_max, 0.1))
# 预测网格点
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# 绘制决策边界
plt.figure(figsize=(10, 8))
plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.Set3)
# 绘制数据点
scatter = plt.scatter(X[:, 0], X[:, 1], c=y,
edgecolors='k', cmap=plt.cm.Set3)
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.title('多分类Logistic回归决策边界')
plt.legend(*scatter.legend_elements(), title='类别')
plt.tight_layout()
plt.show()
if __name__ == "__main__":
# 执行优化
grid_search = optimize_logistic_regression()
# 可视化决策边界
visualize_decision_boundary()
```
## 实战案例:手写数字识别
```python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
def handwritten_digits_recognition():
"""手写数字识别实战案例"""
# 加载手写数字数据集
digits = load_digits()
X = digits.data
y = digits.target
print("手写数字数据集信息:")
print(f"样本数: {X.shape[0]}")
print(f"特征数: {X.shape[1]} (8x8像素图像展开)")
print(f"类别数: {len(np.unique(y))} (数字0-9)")
# 可视化部分样本
fig, axes = plt.subplots(2, 5, figsize=(10, 5))
for i, ax in enumerate(axes.flat):
ax.imshow(digits.images[i], cmap='binary')
ax.set_title(f"标签: {digits.target[i]}")
ax.axis('off')
plt.suptitle('手写数字样本示例')
plt.tight_layout()
plt.show()
# 数据预处理
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
X_scaled, y, test_size=0.2, random_state=42, stratify=y
)
# 训练多分类Logistic回归
model = LogisticRegression(
multi_class='multinomial',
solver='lbfgs',
max_iter=5000,
C=0.1,
random_state=42,
n_jobs=-1
)
print("\n训练模型中...")
model.fit(X_train, y_train)
# 评估模型
train_acc = model.score(X_train, y_train)
test_acc = model.score(X_test, y_test)
print(f"训练准确率: {train_acc:.4f}")
print(f"测试准确率: {test_acc:.4f}")
# 预测
y_pred = model.predict(X_test)
# 分类报告
print("\n分类报告:")
print(classification_report(y_test, y_pred))
# 混淆矩阵
cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(10, 8))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
square=True,
xticklabels=range(10),
yticklabels=range(10))
plt.title('手写数字识别混淆矩阵')
plt.xlabel('预测数字')
plt.ylabel('真实数字')
plt.tight_layout()
plt.show()
# 可视化错误分类样本
errors = X_test[y_pred != y_test]
error_preds = y_pred[y_pred != y_test]
error_true = y_test[y_pred != y_test]
if len(errors) > 0:
print(f"\n错误分类样本数: {len(errors)}")
# 反标准化以恢复原始像素值
errors_original = scaler.inverse_transform(errors)
n_errors = min(10, len(errors))
fig, axes = plt.subplots(2, 5, figsize=(12, 6))
fig.suptitle('错误分类样本示例')
for i, ax in enumerate(axes.flat[:n_errors]):
img = errors_original[i].reshape(8, 8)
ax.imshow(img, cmap='binary')
ax.set_title(f"预测: {error_preds[i]}\n真实: {error_true[i]}")
ax.axis('off')
plt.tight_layout()
plt.show()
# 特征重要性分析(像素重要性)
feature_importance = np.mean(np.abs(model.coef_), axis=0).reshape(8, 8)
plt.figure(figsize=(8, 6))
plt.imshow(feature_importance, cmap='hot', interpolation='nearest')
plt.colorbar(label='平均系数绝对值')
plt.title('像素重要性热力图')
plt.xlabel('X像素')
plt.ylabel('Y像素')
plt.tight_layout()
plt.show()
return model, X_test, y_test, y_pred
www.af.wandaihu.cn>www.bs.wandaihu.cn>www.ly.wandaihu.cn
def probability_analysis():
"""概率分析示例"""
model, X_test, y_test, y_pred = handwritten_digits_recognition()
# 获取预测概率
y_proba = model.predict_proba(X_test)
# 分析预测确定性
confidence = np.max(y_proba, axis=1)
plt.figure(figsize=(10, 6))
plt.hist(confidence[y_pred == y_test], bins=30, alpha=0.7,
label='正确分类', density=True)
plt.hist(confidence[y_pred != y_test], bins=30, alpha=0.7,
label='错误分类', density=True)
plt.xlabel('预测置信度')
plt.ylabel('密度')
plt.title('正确与错误分类的置信度分布')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# 展示不确定样本
low_confidence_idx = np.where(confidence < 0.7)[0]
if len(low_confidence_idx) > 0:
print(f"\n低置信度样本数: {len(low_confidence_idx)}")
n_samples = min(5, len(low_confidence_idx))
fig, axes = plt.subplots(1, n_samples, figsize=(15, 3))
for i, idx in enumerate(low_confidence_idx[:n_samples]):
ax = axes[i] if n_samples > 1 else axes
img = X_test[idx].reshape(8, 8)
ax.imshow(img, cmap='binary')
# 获取前3个最可能类别
top3_idx = np.argsort(y_proba[idx])[-3:][::-1]
top3_proba = y_proba[idx][top3_idx]
title = f"真实: {y_test[idx]}\n预测: {y_pred[idx]}"
for j, (cls, prob) in enumerate(zip(top3_idx, top3_proba)):
title += f"\n第{j+1}: {cls} ({prob:.3f})"
ax.set_title(title)
ax.axis('off')
plt.suptitle('低置信度预测样本')
plt.tight_layout()
plt.show()
if __name__ == "__main__":
probability_analysis()
```
## 性能优化与最佳实践
### 数据预处理建议
```python
from sklearn.preprocessing import PolynomialFeatures
from sklearn.decomposition import PCA
def data_preprocessing_tips():
"""数据预处理技巧"""
from sklearn.datasets import load_breast_cancer
# 加载数据
data = load_breast_cancer()
X, y = data.data, data.target
# 1. 特征标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 2. 特征选择(基于模型)
from sklearn.feature_selection import SelectFromModel
lr = LogisticRegression(penalty='l1', solver='liblinear', C=0.1)
selector = SelectFromModel(lr, threshold='median')
X_selected = selector.fit_transform(X_scaled, y)
print(f"原始特征数: {X.shape[1]}")
print(f"选择后特征数: {X_selected.shape[1]}")
# 3. 降维处理
pca = PCA(n_components=0.95) # 保留95%方差
X_pca = pca.fit_transform(X_scaled)
print(f"PCA降维后特征数: {X_pca.shape[1]}")
# 4. 多项式特征扩展
poly = PolynomialFeatures(degree=2, interaction_only=True)
X_poly = poly.fit_transform(X_scaled[:, :5]) # 只对前5个特征
print(f"多项式特征扩展后: {X_poly.shape[1]} 个特征")
return X_scaled, X_selected, X_pca, X_poly
def handling_imbalanced_data():
"""处理类别不平衡"""
from sklearn.datasets import make_classification
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler
# 生成不平衡数据
X, y = make_classification(
n_samples=1000, n_features=20, n_classes=3,
n_informative=10, weights=[0.1, 0.3, 0.6],
random_state=42
)
# 查看类别分布
unique, counts = np.unique(y, return_counts=True)
print("原始类别分布:")
for cls, count in zip(unique, counts):
print(f"类别 {cls}: {count} 样本 ({count/len(y)*100:.1f}%)")
# 1. 过采样(SMOTE)
smote = SMOTE(random_state=42)
X_smote, y_smote = smote.fit_resample(X, y)
unique_s, counts_s = np.unique(y_smote, return_counts=True)
print("\nSMOTE后类别分布:")
for cls, count in zip(unique_s, counts_s):
print(f"类别 {cls}: {count} 样本")
# 2. 欠采样
under = RandomUnderSampler(random_state=42)
X_under, y_under = under.fit_resample(X, y)
unique_u, counts_u = np.unique(y_under, return_counts=True)
print("\n欠采样后类别分布:")
for cls, count in zip(unique_u, counts_u):
print(f"类别 {cls}: {count} 样本")
# 3. 类权重调整
model_weighted = LogisticRegression(
multi_class='multinomial',
solver='lbfgs',
class_weight='balanced', # 自动调整类权重
max_iter=1000,
random_state=42
)
return model_weighted
```
## 模型评估与选择
```python
from sklearn.model_selection import learning_curve, validation_curve
def evaluate_model_performance():
"""模型性能评估"""
from sklearn.datasets import load_digits
digits = load_digits()
X, y = digits.data, digits.target
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 创建模型
model = LogisticRegression(
multi_class='multinomial',
solver='lbfgs',
max_iter=1000,
random_state=42
)
# 学习曲线
train_sizes, train_scores, test_scores = learning_curve(
model, X_train, y_train,
cv=5, n_jobs=-1,
train_sizes=np.linspace(0.1, 1.0, 10),
scoring='accuracy'
)
plt.figure(figsize=(10, 6))
plt.plot(train_sizes, np.mean(train_scores, axis=1),
'o-', label='训练准确率')
plt.plot(train_sizes, np.mean(test_scores, axis=1),
's-', label='验证准确率')
plt.fill_between(train_sizes,
np.mean(train_scores, axis=1) - np.std(train_scores, axis=1),
np.mean(train_scores, axis=1) + np.std(train_scores, axis=1),
alpha=0.1)
plt.fill_between(train_sizes,
np.mean(test_scores, axis=1) - np.std(test_scores, axis=1),
np.mean(test_scores, axis=1) + np.std(test_scores, axis=1),
alpha=0.1)
plt.xlabel('训练样本数')
plt.ylabel('准确率')
plt.title('学习曲线')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# 验证曲线(正则化强度)
param_range = np.logspace(-4, 4, 10)
train_scores, test_scores = validation_curve(
model, X_train, y_train,
param_name='C',
param_range=param_range,
cv=5, n_jobs=-1,
scoring='accuracy'
)
plt.figure(figsize=(10, 6))
plt.semilogx(param_range, np.mean(train_scores, axis=1),
'o-', label='训练准确率')
plt.semilogx(param_range, np.mean(test_scores, axis=1),
's-', label='验证准确率')
plt.fill_between(param_range,
np.mean(train_scores, axis=1) - np.std(train_scores, axis=1),
np.mean(train_scores, axis=1) + np.std(train_scores, axis=1),
alpha=0.1)
plt.fill_between(param_range,
np.mean(test_scores, axis=1) - np.std(test_scores, axis=1),
np.mean(test_scores, axis=1) + np.std(test_scores, axis=1),
alpha=0.1)
plt.xlabel('正则化强度 (C)')
plt.ylabel('准确率')
plt.title('验证曲线(正则化参数调优)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
if __name__ == "__main__":
evaluate_model_performance()
```
## 总结
多分类Logistic回归通过Softmax函数将二元分类扩展到多类别场景,成为处理多分类问题的基础且有效的方法。本文从理论原理、手动实现、Scikit-learn应用、到实战案例,全面介绍了多分类Logistic回归的各个方面。在实际应用中,需要注意数据预处理、特征工程、模型调参和评估等环节,同时根据具体问题选择合适的优化策略和处理方法。通过合理运用多分类Logistic回归,可以在保持模型简单可解释的同时,获得不错的分类性能。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3105615/ ,如需转载,请注明出处,否则将追究法律责任。