逻辑回归:解决分类问题(二分类)

基本思想:1.利用线性模型根据特征的重要性计算一个值

2,再用sigmoid 函数将f(X)的输出值映射为概率值

通过设置阈值例如0.5,将大于0.5的归为1  小于0.5的归于0

sigmoid 函数:把线性回归的输出作为逻辑回归的输入(0,1)之间的值

sigmoid函数的表达式为:1/1+e的-x次方

损失函数:极大似然估计函数的负数形式

损失函数:所有的样本的损失值(越小越好)

yi=真实值标签

pi=预测值

yi=1时

如预测值概率pi接近于1  log(1)=0  损失值越近与0  很好

如预测值概率pi接近于0  log(0)=趋近于无穷大  损失值非常大

yi=0时

如预测值概率pi接近于0  log(1)=0  损失值越近与0  很好

如预测值概率pi接近于1  log(0)=趋近于无穷大  损失值非常大

API演示

# 导包
from sklearn.model_selection import train_test_split,GridSearchCV #数据集划分
from sklearn.metrics import accuracy_score  # 准确率
from sklearn.linear_model import LogisticRegression  # 逻辑回归
from sklearn.neighbors import KNeighborsClassifier  # 线性回归
from sklearn.preprocessing import StandardScaler  # 标准化
import pandas as pd
import numpy as np

# 数据集的读取
data=pd.read_csv('../../data/breast-cancer-wisconsin.csv')
# 对数据集的默认值进行替换
data=data.replace('?',np.nan)
# 对空值的删除
data=data.dropna(axis=0)
# 对数据集的拆分

x=data.iloc[:,1:-1] # 特征
y=data.iloc[:,-1]  # 标签

#对数据集划分
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=22)

# 对数据进行标准化

transfer=StandardScaler()
x_train=transfer.fit_transform(x_train)
x_test=transfer.transform(x_test)

# 使用逻辑回归
def 逻辑():
    model=LogisticRegression()
    # 模型的训练
    model.fit(x_train,y_train)
    # 模型的预测
    y_pred=model.predict(x_test)
    print(f'预测的结果是:{y_pred}')
    # 模型的准确率
    print(f'模型的准确率是:{accuracy_score(y_test,y_pred)}')

# 使用knn
def knn():
    model=KNeighborsClassifier()
    param_grid={
        'n_neighbors':[i for i in range(1,11)]
    }
    # 网格搜索和交叉验证
    model=GridSearchCV(model,param_grid,cv=4)
    model.fit(x_train,y_train)
    y_pred=model.predict(x_test)
    print(f'预测的结果是:{y_pred}')
    # 模型的准确率
    print(f'模型的准确率是:{accuracy_score(y_test,y_pred)}')
    print(f'最优评分{model.best_score_}')
    print(f'最优组合{model.best_params_}')

if __name__=='__main__':
    # 逻辑()

   knn()

混淆矩阵:  用于展示真实值和预测值之间的正例和反例的情况,默认:会使用分类样本少的那一个

真正例(tp):预测值和真实值都是正例

真反例(TN):预测值和真实值都是反例

伪反例:(FN):真实结果为真例结果预测为 假例

伪正例:(FP):真实结果为假例结果预测为 真例

API实现:

import pandas as pd
from sklearn.metrics import confusion_matrix,precision_score,recall_score,f1_score

# 定义数据集 ,真实样本(10个,6个恶,4个良)

y_train=['恶性','恶性','恶性','恶性','恶性','恶性','良性','良性','良性','良性']

# 定义正反例
laber=['恶性','良性'] # 参数1:正例样本,参数2:负样本(反例)
df_laber=['恶性(正例)','良性(假例)']

# 定义模型A 预测对了3个恶性,4个良性

y_pre_A=['恶性','恶性','恶性','良性','良性','良性','良性','良性','良性','良性']

# 定义模型b 预测对了3个恶性,4个良性
y_pre_B=['恶性','恶性','恶性','恶性','恶性','恶性','恶性','恶性','恶性','良性']

# 构建混淆矩阵
# 参数1:真实样本  参数2:预测样本  参数3:样本的标签,规定什么是正例,什么是假例
cm_A=confusion_matrix(y_train,y_pre_A,labels=laber)
print(f'混淆矩阵a{cm_A}')
# 封装为df对象
df_A=pd.DataFrame(cm_A,index=df_laber,columns=df_laber)
print(f'混淆矩阵a的df对象\n{df_A}')


print('*'*30)
cm_B=confusion_matrix(y_train,y_pre_B,labels=laber)
print(f'混淆矩阵a{cm_B}')
# 封装为df对象
df_B=pd.DataFrame(cm_B,index=df_laber,columns=df_laber)
print(f'混淆矩阵a的df对象\n{df_B}')

分类模型的评估指标:精确率,召回率,F1—score

精确率:对正例样本的预测准确率,真正例/(真正例+伪正利)

作用:模型判断为正例的结果中有多少为正确的,这个值越高说明模型预测为正例的结果中,真正正例的占比就越高

API:

from sklearn.metrics import precision_score

# 定义数据集 ,真实样本(10个,6个恶,4个良)
y_train=['恶性','恶性','恶性','恶性','恶性','恶性','良性','良性','良性','良性']

# 定义模型A 预测对了3个恶性,4个良性
y_pre_A=['恶性','恶性','恶性','良性','良性','良性','良性','良性','良性','良性']

# 定义模型b 预测对了3个恶性,4个良性
y_pre_B=['恶性','恶性','恶性','恶性','恶性','恶性','恶性','恶性','恶性','良性']
# 精确率,参数1:真实标签  参数2:预测标签   参数3:二分类中的正类
resultA=precision_score(y_train,y_pre_A,pos_label='恶性')
print(f'A模型的精确率是:{resultA}')

resultB=precision_score(y_train,y_pre_B,pos_label='恶性')
print(f'B模型的精确率是:{resultB}')

召回率:预测为真正例样本占所有真实正例标签的样本的比重  真正例/真正例+伪反例

作用:降低把正例误判为反例的概率,这个值越高说明对正例样本的捕获性就越高,越不会误判

API:

from sklearn.metrics import recall_score

# 定义数据集 ,真实样本(10个,6个恶,4个良)
y_train=['恶性','恶性','恶性','恶性','恶性','恶性','良性','良性','良性','良性']

# 定义模型A 预测对了3个恶性,4个良性
y_pre_A=['恶性','恶性','恶性','良性','良性','良性','良性','良性','良性','良性']

# 定义模型b 预测对了3个恶性,4个良性
y_pre_B=['恶性','恶性','恶性','恶性','恶性','恶性','恶性','恶性','恶性','良性']
# 精确率,参数1:真实标签  参数2:预测标签   参数3:二分类中的正类
resultA=recall_score(y_train,y_pre_A,pos_label='恶性')
print(f'A模型的召回率是:{resultA}')

resultB=recall_score(y_train,y_pre_B,pos_label='恶性')
print(f'B模型的召回率是:{resultB}')

F1-score: 对精确率和召回率都有要求综合考虑

F1-score=2*(精确率*召回率/精确率+召回率)

API:

from sklearn.metrics import f1_score

# 定义数据集 ,真实样本(10个,6个恶,4个良)
y_train=['恶性','恶性','恶性','恶性','恶性','恶性','良性','良性','良性','良性']

# 定义模型A 预测对了3个恶性,4个良性
y_pre_A=['恶性','恶性','恶性','良性','良性','良性','良性','良性','良性','良性']

# 定义模型b 预测对了3个恶性,4个良性
y_pre_B=['恶性','恶性','恶性','恶性','恶性','恶性','恶性','恶性','恶性','良性']
# 精确率,参数1:真实标签  参数2:预测标签   参数3:二分类中的正类
resultA=f1_score(y_train,y_pre_A,pos_label='恶性')
print(f'A模型的f1分数是:{resultA}')

resultB=f1_score(y_train,y_pre_B,pos_label='恶性')
print(f'B模型的f1分数是:{resultB}')

POC曲线和AUC值

ROC曲线:常用作评估分类模型的性能的可视化工具

X:假正率  Y:真正率

x:假正率(FPR):负样本中被预测为正样本的概率

=伪正例/伪正例+真假率

y:y:真正率(TPR): 正样本中被预测为正样本的概率

=真正率/真正例+伪反例

AUC值:ROC曲线的优劣可以通过ROC曲线下的面积也就是AUC值来衡量,这个面积越大说明分类器的性能越好

AUC=0.5:等同于随机猜想

AUC=1:分类器的性能完美

AUC=0:猜测为相反值

热编码:对于字符类型的需要通过热编码转化为数值型,是这个列为1,不是则为0

数据探索性分析EDA

通过画图来展示特征和标签之间的关系

API:

import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import  train_test_split
from sklearn.preprocessing import  StandardScaler
from sklearn.metrics import accuracy_score
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.metrics import  confusion_matrix,precision_score,recall_score,f1_score,roc_auc_score,classification_report  #混淆矩阵

# # 数据集的读取
# data=pd.read_csv('../../data/churn.csv')

# 数据集的详情
# data.info()
#
# print(data.head())
#
# print(data.columns)
# # 进行种类的划分查看yes和no的个数
# a=y.value_counts()
# print(a)
# 通过数据集的展示后发现
"""
No     5174
Yes    1869
流失的为少数的所有为Yes正例,No为反例

"""
# 数据的预处理
# 热编码

#1、定义函数 实现:数据预处理
def dm01_数据预处理():
    #1.1读取数据
    data=pd.read_csv("../../data/churn.csv")
    # data.info()

    #1.2因为上述Churn、gender字段字符串类型。我们对其做热编码(one-hot)处理
    #get_dummies
    data=pd.get_dummies(data)
    # data.info()
    # print(data.head(2))
    #1.3删除列
    data.drop(['gender_Male','Churn_No'],axis=1,inplace=True)
    # print(data.info())

    #1.4 所以我要修改标签列名字flag
    data.rename(columns={'Churn_Yes':'flag'},inplace=True)
    data.info()
    # print(data.head(2))

    #1.5查看数据集  标签是否均衡  何为均衡:1:1
    print(data.flag.value_counts())  #False 不流失   True流失


#2.定义函数  用于显示 :EDA  数据探索性分析
def dm02_会员流失可视化情况():
    #1.读取数据
    data=pd.read_csv("../data/churn.csv")
    data=pd.get_dummies(data)
    data.drop(['gender_Male', 'Churn_No'], axis=1, inplace=True)
    data.rename(columns={'Churn_Yes': 'flag'}, inplace=True)

    #通过计数柱状图 ,绘制月度会员流失情况
    #参1:数据
    # 参2 x轴的列名
    #参3:hue  将数据进行分类
    sns.countplot(data,x='Contract_Month',hue='flag')  #Contract_Month复制,别手敲
    plt.show()


def dm03_逻辑回归模型训练与评估():
    # 1.1读取数据
    data = pd.read_csv("../../data/churn.csv")
    # 热编码
    # 1.2因为上述Churn、gender字段字符串类型。我们对其做热编码(one-hot)处理
    # get_dummies
    data = pd.get_dummies(data)
    # data.info()
    # print(data.head(2))
    # 1.3删除列
    data.drop(['gender_Male', 'Churn_No'], axis=1, inplace=True)
    # print(data.info())

    # 1.4 所以我要修改标签列名字flag
    data.rename(columns={'Churn_Yes': 'flag'}, inplace=True)
    # 选择特征和标签
    x=data.iloc[:,:-2]
    y=data.flag
    # # 对数据集的划分
    x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.2,random_state=22)
    # 对数据进行标准化
    t=StandardScaler()
    x_train=t.fit_transform(x_train)
    x_test=t.transform(x_test)

    # 模型的训练,逻辑回归
    model=LogisticRegression()
    model.fit(x_train,y_train)
    # 模型的预测
    y_pred=model.predict(x_test)
    # 输出预测结果
    print(f'预测结果是{y_pred}')
    print(f'模型的准确率为{accuracy_score(y_test,y_pred)}')
    print(f"准确率:{accuracy_score(y_test, y_pred)}")
    print(f"精确率:{precision_score(y_test, y_pred)}")
    print(f"召回率:{recall_score(y_test, y_pred)}")
    print(f"f1值:{f1_score(y_test, y_pred)}")
    print(f'训练好的分类模型会自动记录类别顺序:{model.classes_}')
    # #auc值为
    # # 1. 先获取模型对测试集的类别概率(二维数组:[样本数, 2],列0=No的概率,列1=Yes的概率)
    y_proba = model.predict_proba(x_test)[:,1]  # 这是第二列的索引
    print(f"roc曲线下面积:{roc_auc_score(y_test, y_proba)}")

    print(f"分类评估报告:{classification_report(y_test, y_pred)}")


if __name__=='__main__':
    # dm01_数据预处理()
    dm03_逻辑回归模型训练与评估()


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐