目录
什么是逻辑回归?
逻辑回归算法是用来解决分类问题的。回归与分类的区别在于:回归所预测的目标量的取值是连续的(例如房屋的价格);而分类所预测的目标变量的取值是离散的(例如判断肿瘤大小是否为恶性)。
如图所示,X为数据点-肿瘤的大小,Y为观测值-是否为恶性肿瘤(0良性肿瘤,1恶性肿瘤)。通过构建线性回归模型,即可根据肿瘤大小,预测是否为恶性肿瘤,hθ(x)≥.05为恶性,hθ(x)<0.5为良性。
那有的人就会提出疑问,逻辑回归可以做分类,那么线性回归可不可以做分类呢?答案是可以,但是线性回归的鲁棒性(稳定和可靠)很差,如下图所示,因最右边噪点的存在,使回归模型在训练上表现很差,这主要是由于线性回归在整个实数域内敏感度一致,而分类范围,需要在[0,1]。
Sigmoid 函数
Sigmoid 函数在有个很漂亮的“S”形,如下图所示:
对于线性回归的情况,方程如下:
构造预测函数为:取值在[0,1]
似然函数
梯度下降
在梯度下降的算法中,还有两个比较重要的点叫做学习率和步数。
学习率是指你在下山的过程中每走的一步大小,你要是厉害能一步跨到山底也算是你厉害,当然你也有可能跨到对面山上,所以学习率我们在设置的时候就要设置的稍微小点,当然也别太小了,这样学习的会很慢。学习率是自己设定的,比如0.01。
迭代次数就是指你在下山过程中你要走多少步,小了的话你可能没有走到山底,多了的话可能你就会在山底来回的走。
学习率和迭代次数都是自定义的,需要通过经验和实际操作去验证和设置。最好在运行代码的时候打印出来,这个就会看到收敛的情况,当很长一段时间内,收敛的效果已经不明显了,基本就到头了。
梯度下降有三种方法:
判定边界
损失函数
逻辑回归优点
逻辑回归缺点
总结一下:回归假设数据服从伯努利分布,通过极大似然函数的方法,运用梯度下降来求解参数,最终达到数据二分类的目的。
代码实现
Logistic Regression参数详解
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
verbose=0, warm_start=False)
其中,参数 penalty 表示惩罚项( L1 、 L2 值可选
正则化选择参数:penalty
在调参时如果我们主要的目的只是为了解决过拟合,一般penalty选择L2正则化就够了。但是如果选择L2正则化发现还是过拟合,即预测效果差的时候,就可以考虑L1正则化。另外,如果模型的特征非常多,我们希望一些不重要的特征系数归零,从而让模型系数稀疏化的话,也可以使用L1正则化。
penalty参数的选择会影响我们损失函数优化算法的选择。即参数solver的选择,如果是L2正则化,那么4种可选的算法{‘newton-cg’, ‘lbfgs’, ‘liblinear’, ‘sag’}都可以选择。
但是如果penalty是L1正则化的话,就只能选择‘liblinear’了。这是因为L1正则化的损失函数不是连续可导的,而{‘newton-cg’, ‘lbfgs’,‘sag’}这三种优化算法时都需要损失函数的一阶或者二阶连续导数。而‘liblinear’并没有这个依赖。
优化算法选择参数:solver
newton-cg, lbfgs和sag这三种优化算法时都需要损失函数的一阶或者二阶连续导数,因此不能用于没有连续导数的L1正则化,只能用于L2正则化。而liblinear通吃L1正则化和L2正则化。
其他参数
这里的参数只做介绍,一般也不需要调试
一般来说,我们知道这些参数所使用的的场景,那么就会少走一些坑,比如我们知道L1,L2正则项的意义是什么,L2主要解决过拟合,L1特征选取,也可以解决过拟合,默认是L2
代码案例
具体的代码步骤,我这里就不一一的做详细的解释了,因为我喜欢在jupyter notebook中机器学习,每一步都可以知道如何优化,下面的案例我首先通过逻辑回归进行调参,并使用相关系数进行特征选取,然后得出的效果分数可以达到91%,这比不做特征选取要好很多,随后我又使用逻辑回归自带的特征评估权重做了一次选取,最后效果有所提升。
feature_weight = model.coef_.tolist()[0]
feature_name = X_name
feature_sort = pd.Series(data = feature_weight ,index = feature_name)
feature_sort = feature_sort.sort_values(ascending = False)
print(feature_sort.index)
plt.figure(figsize=(10,8))
sns.barplot(feature_sort.values,feature_sort.index, orient='h')
选取了8个重要的特征
完整代码如下,由于数据集是科研的数据,这里就不做导入说明了
# 导入数据 分割数据
df=**************不做展示***********************
# # 特征筛选(经过一番测试,不需要进行特征筛选)
# X_name=df.corr()[["n23"]].sort_values(by="n23",ascending=False).iloc[1:9].index.values.astype("U")
# X_name=feature_sort.index[:1]
# 测试出来的最佳特征!!!!!!!!
X_name=['n22', 'n8', 'n19f1', 'n18', 'n13', 'n10new','n9','leibie']
print(X_name)
X=df.loc[:,X_name]
# X=df.iloc[:,:-1]
y=df.iloc[:,-1]
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2,stratify=y,random_state=1)
# X_train
score = []
C_range = np.linspace(0.01, 30, 50)
for i in C_range:
clf = LogisticRegression(C=i,penalty="l2").fit(X_train, y_train)
score.append(clf.score(X_test, y_test))
print(max(score), C_range[score.index(max(score))])
best_C=C_range[score.index(max(score))]
#设置标题
plt. title(f' LogisticRegression {max(score)}')
#设置x轴标签
plt. xlabel(' C')
#设置y轴标签
plt. ylabel(' Score')
#添加图例
# plt. legend()
plt.plot(C_range, score)
plt.show()
solvers = ["newton-cg", "lbfgs", "liblinear","sag"]
for solver in solvers:
clf = LogisticRegression(solver=solver,
C=best_C
).fit(X_train, y_train)
print("The accuracy under solver %s is %f" % (solver, clf.score(X_test, y_test)))
best_sover='liblinear'
model=LogisticRegression(C=11.02673469387755,penalty='l2',solver=best_sover)
# 训练模型
model.fit(X_train,y_train)
# 预测值
y_pred = model.predict(X_test)
'''
评估指标
'''
# 求出预测和真实一样的数目
true = np.sum(y_pred == y_test )
print('预测对的结果数目为:', true)
print('预测错的的结果数目为:', y_test.shape[0]-true)
# 评估指标
from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score,cohen_kappa_score
print('预测数据的准确率为: {:.4}%'.format(accuracy_score(y_test,y_pred)*100))
print('预测数据的精确率为:{:.4}%'.format(
precision_score(y_test,y_pred)*100))
print('预测数据的召回率为:{:.4}%'.format(
recall_score(y_test,y_pred)*100))
# print("训练数据的F1值为:", f1score_train)
print('预测数据的F1值为:',
f1_score(y_test,y_pred))
print('预测数据的Cohen’s Kappa系数为:',
cohen_kappa_score(y_test,y_pred))
# 打印分类报告
print('预测数据的分类报告为:','\n',
classification_report(y_test,y_pred))
from sklearn.metrics import precision_recall_curve
from sklearn import metrics
# 预测正例的概率
y_pred_prob=model.predict_proba(X_test)[:,1]
# y_pred_prob ,返回两列,第一列代表类别0,第二列代表类别1的概率
#https://blog.csdn.net/dream6104/article/details/89218239
fpr, tpr, thresholds = metrics.roc_curve(y_test,y_pred_prob, pos_label=2)
#pos_label,代表真阳性标签,就是说是分类里面的好的标签,这个要看你的特征目标标签是0,1,还是1,2
roc_auc = metrics.auc(fpr, tpr) #auc为Roc曲线下的面积
# print(roc_auc)
plt.figure(figsize=(8,6))
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.plot(fpr, tpr, 'r',label='AUC = %0.2f'% roc_auc)
plt.legend(loc='lower right')
# plt.plot([0, 1], [0, 1], 'r--')
plt.xlim([0, 1.1])
plt.ylim([0, 1.1])
plt.xlabel('False Positive Rate') #横坐标是fpr
plt.ylabel('True Positive Rate') #纵坐标是tpr
plt.title('Receiver operating characteristic example')
plt.show()
结果显示
效果还是有所提升,通过反复的调试,我们的逻辑回归已经大功告成了!