logistic 回归,虽然名字里有 “回归” 二字,但实际上是解决分类问题的一类线性模型。在某些文献中,logistic 回归又被称作 logit 回归,maximum-entropy classification(MaxEnt,最大熵分类),或 log-linear classifier(对数线性分类器)。该模型利用函数 logistic function 将单次试验(single trial)的可能结果输出为概率。 scikit-learn 中 logistic 回归在 LogisticRegression 类中实现了二分类(binary)、一对多分类(one-vs-rest)及多项式 logistic 回归,并带有可选的 L1 和 L2 正则化。
在 LogisticRegression 类中实现了这些优化算法: liblinear, newton-cg, lbfgs, sag 和 saga。 liblinear应用了坐标下降算法(Coordinate Descent, CD),并基于 scikit-learn 内附的高性能 C++ 库 LIBLINEAR library 实现。不过 CD 算法训练的模型不是真正意义上的多分类模型,而是基于 “one-vs-rest” 思想分解了这个优化问题,为每个类别都训练了一个二元分类器。因为实现在底层使用该求解器的 LogisticRegression 实例对象表面上看是一个多元分类器。 sklearn.svm.l1_min_c 可以计算使用 L1时 C 的下界,以避免模型为空(即全部特征分量的权重为零)。 lbfgs, sag 和 newton-cg 求解器只支持 L2罚项以及无罚项,对某些高维数据收敛更快。这些求解器的参数 multi_class设为 multinomial 即可训练一个真正的多项式 logistic 回归 [5] ,其预测的概率比默认的 “one-vs-rest” 设定更为准确。 sag 求解器基于平均随机梯度下降算法(Stochastic Average Gradient descent) [6]。在大数据集上的表现更快,大数据集指样本量大且特征数多。 saga 求解器 [7] 是 sag 的一类变体,它支持非平滑(non-smooth)的 L1 正则选项 penalty=“l1” 。因此对于稀疏多项式 logistic 回归 ,往往选用该求解器。saga求解器是唯一支持弹性网络正则选项的求解器。 lbfgs是一种近似于Broyden–Fletcher–Goldfarb–Shanno算法[8]的优化算法,属于准牛顿法。lbfgs求解器推荐用于较小的数据集,对于较大的数据集,它的性能会受到影响。
默认情况下,lbfgs求解器鲁棒性占优。对于大型数据集,saga求解器通常更快。对于大数据集,还可以用 SGDClassifier ,并使用对数损失(log loss)这可能更快,但需要更多的调优。
LogisticRegressionCV 对 logistic 回归 的实现内置了交叉验证(cross-validation),可以找出最优的 C和l1_ratio参数 。newton-cg, sag, saga 和 lbfgs 在高维数据上更快,这是因为采用了热启动(warm-starting)。
属性:
classes_:ndarray of shape (n_classes, ) 分类器已知的类标签列表。 coef_:ndarray of shape (1, n_features) or (n_classes, n_features) 决策函数中的特征系数。 intercept_:ndarray of shape (1,) or (n_classes,) 将截距(也称为偏差)添加到决策函数中。 n_iter_:ndarray of shape (n_classes,) or (1, ) 所有类的实际迭代次数。另见: SGDClassifier LogisticRegressionCV 例子:
>>> from sklearn.datasets import load_iris >>> from sklearn.linear_model import LogisticRegression >>> X, y = load_iris(return_X_y=True) >>> clf = LogisticRegression(random_state=0).fit(X, y) >>> clf.predict(X[:2, :]) array([0, 0]) >>> clf.predict_proba(X[:2, :]) array([[9.8...e-01, 1.8...e-02, 1.4...e-08], [9.7...e-01, 2.8...e-02, ...e-08]]) >>> clf.score(X, y) 0.97...方法:
__init__(self, penalty='l2', *, dual=False, tol=0.0001, C=1.0, fit_intercept=True, intercept_scaling=1, class_weight=None, random_state=None, solver='lbfgs', max_iter=100, multi_class='auto', verbose=0, warm_start=False, n_jobs=None, l1_ratio=None) decision_function(self, X) 预测样本的置信度得分。 参数: X:array_like or sparse matrix, shape (n_samples, n_features) 样本 返回: array, shape=(n_samples,) if n_classes == 2 else (n_samples, n_classes) 每个(样本,类)组合的置信度得分 densify(self) 将系数矩阵转换为密集数组格式。 返回 self 拟合估计量。 fit(self, X, y, sample_weight=None) 根据给定的训练数据拟合模型。 参数: X:array-like of shape (n_samples, n_features) 训练数据 Y:array-like of shape (n_samples,) or (n_samples, n_targets) 目标值 返回: self:object 返回self的实例。 get_params(self, deep=True) 获取此估计器的参数。 参数: deep:bool, default=True 如果为True,则返回此估计器的参数以及包含的子对象(即估计器)。 返回: params:mapping of string to any 映射到其值的参数名。 predict(self, X) 参数: X:array_like or sparse matrix, shape (n_samples, n_features) 返回: C:array, shape (n_samples,) 返回预测值 predict_log_proba(self, X) 预测概率估计的对数。 所有类的返回估计值按类的标签排序。 参数 X:array-like of shape (n_samples, n_features) 返回 T:array-like of shape (n_samples, n_classes) 返回模型中每个类的样本的日志概率, predict_proba(self, X) 概率估计。 所有类的返回估计值按类的标签排序。 参数: X:array-like of shape (n_samples, n_features) 待评分向量,其中n_samples是样本数,n_features是特征数。 返回 T:array-like of shape (n_samples, n_classes) 返回模型中每个类的样本概率,其中类按其所在的顺序排列 score(self, X, y, sample_weight=None) 返回预测的决定系数R^2。 系数R^2定义为(1-u/v),其中u是残差平方和((y_true-y_pred)**2).sum(), v是平方和的总和((y_true-y_true.mean())**2).sum()。最好的分数是1.0, 它可以是负的(因为模型可以任意恶化)。一个常数模型总是预测y的期望值,而不考虑输入特性, 则得到R^2分数为0.0。 参数: X:array-like of shape (n_samples, n_features) 测试样本。 y:array-like of shape (n_samples,) or (n_samples, n_outputs) X的真值。 sample_weight:array-like of shape (n_samples,), default=None 样本权重。 返回: scorefloat 得分 set_params(self, **params) 设置此估计器的参数。 参数: **params:dict 估计参数 返回: Self:object 估计实例例子: Logistic回归中的L1罚项和稀疏系数
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2020/6/30 20:37 # @Author : LaoChen """ 通过对不同C值采用L1、L2和弹性净罚时解的稀疏性(零系数百分比)的比较, 可以看出C的较大值给模型带来了更大的自由度。 相反,C的较小值对模型的约束更大。在L1中,这将导致更稀疏的解决方案。 Elastic-Net 惩罚的稀疏性介于L1和L2之间。 """ import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import LogisticRegression from sklearn import datasets from sklearn.preprocessing import StandardScaler X, y = datasets.load_digits(return_X_y=True) X = StandardScaler().fit_transform(X) # classify small against large digits y = (y > 4).astype(np.int) l1_ratio = 0.5 # L1 weight in the Elastic-Net regularization fig, axes = plt.subplots(3, 3) # Set regularization parameter for i, (C, axes_row) in enumerate(zip((1, 0.1, 0.01), axes)): # turn down tolerance for short training time clf_l1_LR = LogisticRegression(C=C, penalty='l1', tol=0.01, solver='saga') clf_l2_LR = LogisticRegression(C=C, penalty='l2', tol=0.01, solver='saga') clf_en_LR = LogisticRegression(C=C, penalty='elasticnet', solver='saga', l1_ratio=l1_ratio, tol=0.01) clf_l1_LR.fit(X, y) clf_l2_LR.fit(X, y) clf_en_LR.fit(X, y) coef_l1_LR = clf_l1_LR.coef_.ravel() coef_l2_LR = clf_l2_LR.coef_.ravel() coef_en_LR = clf_en_LR.coef_.ravel() # coef_l1_LR contains zeros due to the # L1 sparsity inducing norm sparsity_l1_LR = np.mean(coef_l1_LR == 0) * 100 sparsity_l2_LR = np.mean(coef_l2_LR == 0) * 100 sparsity_en_LR = np.mean(coef_en_LR == 0) * 100 print("C=%.2f" % C) print("{:<40} {:.2f}%".format("Sparsity with L1 penalty:", sparsity_l1_LR)) print("{:<40} {:.2f}%".format("Sparsity with Elastic-Net penalty:", sparsity_en_LR)) print("{:<40} {:.2f}%".format("Sparsity with L2 penalty:", sparsity_l2_LR)) print("{:<40} {:.2f}".format("Score with L1 penalty:", clf_l1_LR.score(X, y))) print("{:<40} {:.2f}".format("Score with Elastic-Net penalty:", clf_en_LR.score(X, y))) print("{:<40} {:.2f}".format("Score with L2 penalty:", clf_l2_LR.score(X, y))) if i == 0: axes_row[0].set_title("L1 penalty") axes_row[1].set_title("Elastic-Net\nl1_ratio = %s" % l1_ratio) axes_row[2].set_title("L2 penalty") for ax, coefs in zip(axes_row, [coef_l1_LR, coef_en_LR, coef_l2_LR]): ax.imshow(np.abs(coefs.reshape(8, 8)), interpolation='nearest', cmap='binary', vmax=1, vmin=0) ax.set_xticks(()) ax.set_yticks(()) axes_row[0].set_ylabel('C = %s' % C) plt.show()