机器学习之逻辑回归

逻辑回归

场景简介:使用逻辑回归实现对鸢尾花的分类预测。
基于python基本库的实现

模型说明

逻辑回归是一个分类模型,根据特征值来预测该样本归属哪一类。
逻辑回归的预测方程式(模型函数)为:
h(θ) = \frac{1}{1+e^{-θ^TX}}
它的函数图如下:

sigmoid.png

0<=h(θ) <=1

该函数就是逻辑回归的模型函数,也叫做sigmoid函数
X 为特征向量,θ的就是我们要学习的参数,shape为(n_x,1)
它的预测逻辑一般为:h(θ) >0.5 为正类,h(θ) <0.5 为负类。
当然0.5 这个值也是可以调整的

逻辑回归一般一次只区分两类,所以若要区分多个类(比如k个),则需要建立k或k-1个分类器。

代价函数与梯度下降

逻辑回归用于二分类,y的取值为:(0:负类 1:正类)
我们的模型函数得出的其实就是一个概率值,概率大于0.5归于正类,概率小于0.5 ,get_ipython于负类。
所以y的联合概率分布为:
L(θ) = \prod_{i=1}^{m}{}P(y^{(i)}| x^{(i)};θ) = \prod_{i=1}^{m}{}h_θ(x^{(i)})^{y^{(i)}}(1-h_θ(x^{(i)})^{y^{(i)}}
我们当然是希望L(θ)越大越好。这就是我们的目标。
因为在梯度下降中,我们需要目标函数是凸函数,具有一个极小值。
所以我们要取负,因为L(θ)是一个连乘,我们将其取对数log,将连乘转为求和,方便计算。即:
J(θ) = -log(L(θ)) = -\sum_{i=1}^{m}{}y^{(i)}log(h_θ(x^{(i)})+(1-y^{(i)})log(1-h_θ(x^{(i)}))
我们的目标就变成最小化 J(θ)

有了上述,我们就可以来实现逻辑回归了

变量说明

对所用到的变量做一个统一说明,方便检查。
θ·X = W·X+b

设:
m: 样本个数
nx:特征维度
θ:(w_0,w_1,w_2 ...w_{nx})
则:
X的shape 为:(m,nx) ,我们会在X的前面加一列全为1的,所以实际X为:(m,nx)
y的shape为:(m,1)
θ 的shape = (nx+1)

实现

Package

import numpy as np
from utils import calc_accuracy_class
from utils import fl_score
from sklearn import datasets
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

import pandas as pd 

加载数据

X,y = datasets.load_iris(return_X_y=True)
y = y.reshape(-1,1)
#将数据分为训练集和测试集
train_X,test_X,train_y,test_y = train_test_split(X,y,test_size = 0.20,random_state = 1)
print(f"train_X的大小为:{train_X.shape}")
print(f"tain_y的大小为:{train_y.shape}")
print(f"test_X的大小为:{test_X.shape}")
print(f"test_y的大小为:{test_y.shape}")
train_X的大小为:(120, 4)
tain_y的大小为:(120, 1)
test_X的大小为:(30, 4)
test_y的大小为:(30, 1)
#标准化
def nomalize(X,axis):
    mean = np.mean(X,axis)
    std = np.std(X,axis)
    return (X-mean)/std, mean,std
#将数据标准化
train_X,mean,std = nomalize(train_X,axis=0)
test_X = (test_X-mean)/std

#插入一列全为1的表示x0
train_X = np.insert(train_X,0,1,axis=1)
test_X = np.insert(test_X,0,1,axis=1)
print(train_X.shape)
print(test_X.shape)
(120, 5)
(30, 5)

初始化参数

def init_parameters(n):
    theta = np.random.randn(n,1)
    return theta

Sigmoid函数

def sigmoid(z):
    return 1/(1+np.exp(-z))

代价函数

costs = -\frac{1}{m}\sum_{i=1}^{m}{}y^{(i)}log(y'^{(i)})+(1-y^{(i)})log(1-y'^{(i)})

def compute_cost(y_hat,y):
    '''
    y_hat --当前阶段的预测值
    y -- 真实值
    '''
    m = y.shape[0]
    cost = -np.sum(y*np.log(y_hat)+(1-y)*(np.log(1-y_hat)))/m
    return cost
    

梯度下降

costs = -\frac{1}{m}\sum_{i=1}^{m}{}y^{(i)}log(y'^{(i)})+(1-y^{(i)})log(1-y'^{(i)})
y' = h_θ(x^{(i)}) = \frac{1}{1+e^{-θ^TX}}
设z=θ·x
可解得:
dz = (y'-y)
所以:
dθ = x.T·(y'-y)

def gradient_descent(X,y_hat,y,theta,lr):
    '''
    y_hat --当前阶段的预测值
    y -- 真实值
    lr -- 学习速率
    '''
    d_theta = np.dot(X.T,y_hat-y)
    theta = theta - lr*d_theta
    return theta

基本逻辑单元

基本逻辑单元,处理二分类。多分类不过由多个基本逻辑单元构成

class BasicLogicUnit:
    def __init__(self,X,y,category):
        '''
        X -- 训练样本,shape:(m,nx)
        y -- 0 or 1 shape:(m,1)
        category -- 真正的类别,即y为1时,所代表的类别
        '''
        self.X = X
        self.y = y
        self.category = category
        self.theta = init_parameters(self.X.shape[1])
        
        
    def fit(self,lr,steps):
        '''
        训练
        '''
        m,n_x = self.X.shape
        costs = []
        for step in range(steps):
            z = np.dot(self.X,self.theta)
            y_ = sigmoid(z)
            loss = compute_cost(y_,self.y)
            costs.append(loss)
            
            self.theta = gradient_descent(self.X,y_,self.y,self.theta,lr)
            
            if step % 50 == 0:
                print(f"\nAfter {step} step(s),cost is :{loss}")
        
        return costs
    def predict(self,X):
        '''
        预测
        '''
        z = np.dot(X,self.theta)
        return sigmoid(z)
        
        

逻辑回归模型

根据训练数据,整合多个逻辑单元进行预测

class LogicRegressionModel:
    def __init__(self):
        self.logic_unit_list = []
    
    def fit(self,tain_X,train_y,learning_rate =0.05,steps = 500):
        classes = set(np.squeeze(train_y))
        n_classes = len(classes)
        m,n_x = train_X.shape
        #根据分类的类别,一个个使用逻辑单元进行分类训练
        for c in classes:
            unit_train_y = np.where(train_y == c,1,0)
            logic_unit = BasicLogicUnit(train_X,unit_train_y,c)
            self.logic_unit_list.append(logic_unit)
            
            costs = logic_unit.fit(learning_rate,steps)
            #绘制损失曲线
            plt.xlim(0,steps)
            plt.plot(costs)
            plt.xlabel("steps")
            plt.ylabel("costs")
            #plt.title(f"c = {self.category}")
            
            y_pred = logic_unit.predict(train_X)
            y_pred = np.where(y_pred > 0.5,1,0)
            acc = calc_accuracy_class(y_pred,unit_train_y)
            print(f"{c}类的准确率为:{acc}")
            
    
    def predict(self,X):
        m = X.shape[0]
        #为了可视化,我们将其以DataFrame的形式输出
        zeros=  np.zeros((m,1),dtype=int)
        results_pd = pd.DataFrame(zeros,columns=["result"])
        for logic_unit in self.logic_unit_list:
            prob_y = logic_unit.predict(X)
            results_pd[logic_unit.category] = prob_y
        max_indexs = np.argmax(np.array(results_pd),axis=1)
        y_ = np.array(results_pd.columns)[max_indexs]
        y_ = y_.T
        results_pd["result"] = y_

        print(results_pd.head())
        return y_
    
model = LogicRegressionModel()
model.fit(train_X,train_y,learning_rate=0.05,steps=40)
After 0 step(s),cost is :1.3471522333761674
0类的准确率为:1.0

After 0 step(s),cost is :1.0414187137571345
1类的准确率为:0.7166666666666667

After 0 step(s),cost is :2.771585424064274
2类的准确率为:0.975
output_31_1.png
logits = model.predict(train_X)
fl_score(np.squeeze(logits),np.squeeze(train_y))
acc = calc_accuracy_class(logits,train_y)
print("准确率为:%g"%(acc))
  result             0         1         2
0      1  4.773352e-03  0.336848  0.114623
1      2  1.197002e-07  0.775613  0.997784
2      1  4.206618e-03  0.727077  0.010902
3      2  2.973954e-06  0.580281  0.991170
4      2  4.080572e-06  0.269009  0.997358
0 类的fl_score 为:1.0
1 类的fl_score 为:0.918918918918919
2 类的fl_score 为:0.9318181818181818
准确率为:0.95
from utils import calc_accuracy_class
logits = model.predict(test_X)
fl_score(np.squeeze(logits),np.squeeze(test_y))
acc = calc_accuracy_class(logits,test_y)
print("准确率为:%g"%(acc))

  result         0         1             2
0      0  0.999999  0.003394  1.241299e-08
1      1  0.038971  0.490671  2.159986e-03
2      1  0.001926  0.494310  6.139991e-02
3      0  0.999997  0.002576  7.951771e-08
4      2  0.000129  0.144131  9.728652e-01
0 类的fl_score 为:1.0
1 类的fl_score 为:0.8181818181818181
2 类的fl_score 为:0.7499999999999999
准确率为:0.866667

结果还ok,稍微有点过拟合。
完整代码地址:https://github.com/huanhuang/logicRegression.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容