机器学习算法逻辑回归(LR)的学习与应用(疾病问诊)

来源:互联网 发布:网络咨询医生平均收入 编辑:程序博客网 时间:2024/05/01 16:20

实验目的

逻辑回归(Logistic Regression, LR)模型其实仅在线性回归的基础上,套用了一个逻辑函数,但也就由于这个逻辑函数,使得逻辑回归模型成为了机器学习领域一颗耀眼的明星,更是计算广告学的核心。单纯的使用线性回归去对数据进行分类,系统的鲁棒性很差,所以一般会对线性回归的结果做一个逻辑函数的映射,在这里,逻辑函数为sigmoid函数,函数模型为S形:

实验介绍

语言:             Python

GitHub地址:luuuyi/logistic_regression

实验步骤

1)原理介绍

回归是一种极易理解的模型,就相当于y=f(x),表明自变量x与因变量y的关系。最常见问题有如医生治病时的望、闻、问、切,之后判定病人是否生病或生了什么病,其中的望闻问切就是获取自变量x,即特征数据,判断是否生病就相当于获取因变量y,即预测分类。

但是对于一个单纯的线性模型,分类效果受数据集噪点的影响,分类表现不会特别突出,但是通过增加一个结果对于逻辑函数的映射,在辅与优化方法,能够很好地对训练数据集进行收敛训练,最终得到一个依托于训练数据集求出的最完美的参数集合。

具体介绍可以百度或者参考以下两篇博文:

逻辑回归

逻辑回归模型基础

2)简单实现

①梯度上升方法

照惯例,先简单实现以下LR的核心代码:

def sigmoid(in_datas):    return 1.0/(1.0+exp(-in_datas))def gradientAscent(datas,labels):    datas_mat = mat(datas)    labels_mat = mat(labels).transpose()    h, w = shape(datas_mat)    alpha = 0.001    max_iter = 500    weights = ones((w,1))    for i in range(max_iter):        res = sigmoid(datas_mat*weights)        errors = (labels_mat - res)        weights = weights + alpha*datas_mat.transpose()*errors          #梯度上升变形,朝着标准标签的方向缓慢移动    return weights

第一个是逻辑函数,也就是sigmoid函数的实现;第二个是梯度上升的训练方法,对于数据集,与初始的模型参数做线性运算之后将结果通过sigmoid函数映射到(0,1)区间,对于一个简单的二分类问题,正样本为1,负样本为0,当结果处于(0,1)区间范围内时,可以通过结果与端点的差值,反向调整权值数据,最终目的是缩小这一差值,达到收敛,这里使用的是梯度上升的方法去迭代500次计算,学习率为0.001,之后对模型进行可视化表现:

可以看出分类还是比较准确的,只有两个数据被错误分类。

②随机梯度上升

但是这其实是对于整个数据集进行划分,每一次迭代的时候都读入了所有的数据集进行计算,当样本量和特征维度特别大的时候计算耗时特别久,虽然能得出很好的结果,但是开销太大。现在介绍一个随机梯度上升的优化方法;系统每一次在数据集中随机选择一条数据进行训练,训练次数为样本总数:

def randomGradientAscent(datas,labels):    datas_arr = array(datas)            #array和matrix有区别    h, w = shape(datas_arr)    alpha = 0.01    weights = ones(w)                   #一维矩阵    for i in range(h):        res = sigmoid(sum(datas_arr[i]*weights))        errors = labels[i] - res        weights = weights + alpha*errors*datas_arr[i]    return weights

对结果可视化看一下:

可以看出训练效果并没有上一个那么理想,但这其实并不能说明什么,上一个参数值是通过了500次迭代,每一次都是对整个训练样本数据集进行计算的结果,计算量之间没有可比性,结果也没有代表意义。

③改进的随机梯度上升

但是随机梯度上升方法一个好处就是,训练系统对于数据集,无论有多少样本,或者是样本的特征维度有多大,都有很好的计算优势,因为每一次只用读取一条数据进行训练,对于之后新采集到的样本也能加入其中。基于这个基础,我们改进了一下该方法:

def advancedRandomGradientAscent(datas,labels,iter_nums=150):    import random    datas_arr = array(datas)               h, w = shape(datas_arr)    weights = ones(w)                      for i in range(iter_nums):        indexs = range(h)        for j in range(h):            alpha = 4/(1.0+j+i)+0.01            random_index = int(random.uniform(0,len(indexs)))            res = sigmoid(sum(datas_arr[random_index]*weights))            errors = labels[random_index] - res            weights = weights + alpha*errors*datas_arr[random_index]            del(indexs[random_index])    return weights

大体上和上一个函数差不多,不同点在于首先在学习率上,将不再使用一个固定的值,通俗点来说体现在与随着迭代次数的增加,权值向着标准位置偏移的步幅变缓,能这样理解,经过多次迭代之后,其实系统的分类能力已经趋于稳定,当前训练的权值相对于标准的权值来说已经无限接近了,步幅太大会导致权值在标准权值左右大幅振动,可能带来误差,为了能够得到一个很好的收敛效果,可以适当降低学习率。

来看一下分类效果的可视化结果:

可以看出改进的随机梯度上升方法,在迭代次数为150次的时候其实效果已经比较理想了,但是与第一个500次迭代的结果还是有一点点差距。

当将迭代次数改为500次和1000次之后又会发生什么样的变化:

500次:

1000次:

其实效果上倒是没有多大的改进了,不过在一些临界数据的分类上会更加的细致,由此能看出到模型趋于稳定的情况下,单纯提高迭代次数对于模型的优化改进已经不是特别明显了;对于数据集中的一些噪点干扰,LR回归模型还是不能做到绝对的线性可分;

3)场景应用

这里使用了一份网上的数据,为马匹疝病的诊断数据,将其一分为二,一部分为训练数据,一部分为测试数据,原数据中每一行(每一条数据)有21个特征,最后的0,1标签代表是否致死,通过对训练数据的迭代训练,我们构建一个简单的分类模型,进而使用模型对测试集进行模型误差分析。

def colicTest():    fd_train = open('horseColicTraining.txt')    fd_test = open('horseColicTest.txt')    train_datas=[]; train_labels=[]    for line in fd_train.readlines():        line_data_list = line.strip().split('\t')        tmp_list=[]        for i in range(21):            tmp_list.append(float(line_data_list[i]))        train_datas.append(tmp_list)        train_labels.append(float(line_data_list[21]))    weights = advancedRandomGradientAscent(train_datas,train_labels,500)    error_count = 0; total_size = 0.0    for line in fd_test.readlines():        total_size += 1.0        line_data_list = line.strip().split('\t')        test_data = []        for i in range(21):            test_data.append(float(line_data_list[i]))        if int(classifyResult(array(test_data),weights)) != int(line_data_list[21]):            error_count += 1    error_rate = float(error_count)/total_size    print "The Error Ratio is: %f" % error_rate    return error_rate
通过对前面介绍的几个函数集合整理,得到上面这个分析函数,最终的输出结果为:

上面的警告为浮点数位数计算溢出了,解决方法可以使用Python pip安装一个叫做bigfloat的包,在安装之前还要给系统先配置一个什么环境,反正是一个C++的库,有兴趣可以去看一下;

结果为38%,看起来好像很糟糕,但其实不然,这份数据其实是通过一个残缺的数据集修复得到的,关于数据集的修复,网上还有学术界有大量的研讨资料,这里使用的方法是残缺数据补0的做法,因为补0并不会对回归的权值更新带来额外的问题,回顾一下这条代码:

weights = weights + alpha*errors*datas_arr[random_index]

在做权值更新的时候,某一条数据的某一维特征假如说因为残缺补全为0,那么在这一维的梯度上升计算中,他结果为0,也就是该数据的该特征对于权值的更新没有贡献,它不影响权值的结果,这是一个比较折中同时也比较保守的方法,因为对于最终结果是没有贡献的。


最后,博主最近开始学习机器学习,希望结识更多的有识之士一起探讨交流,下一章研究SVM。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 和隔壁邻居吵架了怎么办 教师上课期间孩子出问题责任怎么办 孩子一考试妈妈就焦虑怎么办 妈妈爱发脾气孩子也发脾气怎么办 孩子对家人有抵触情绪怎么办 孩子因为没耐心哭闹怎么办 宝宝哭闹真是没耐心怎么办 对自己孩子没耐心怎么办 跳了把腰伤了怎么办 爸爸对妈妈家暴怎么办 逆反心强23岁怎么办 觉得自己心理有问题怎么办 小孩心理脆弱过于敏感怎么办? 父母老是骂打我怎么办 爸妈打架闹离婚怎么办 夫妻离婚后孩子户口怎么办 离婚后孩子户口怎么办落户 50岁父母要离婚怎么办 父母离婚小孩没有出生证该怎么办 离婚。父母一直在劝说该怎么办 老婆跟人跑了怎么办啊 父母50了要离婚怎么办 父母吵架了我该怎么办 父母看孩子总是吵架怎么办 20岁父母离婚我怎么办 碰到没素质的人怎么办 父母抛弃了我该怎么办 父母说家里没钱困难怎么办 遇到素质低的老婆怎么办 孩子考试心里素质差怎么办 5岁儿童脾气不好怎么办 有一个素质差的父母怎么办 孩子对什么都无所谓怎么办 孩子在学习上无所谓怎么办 孩子对学习无所谓的态度怎么办 孩子不上进什么都无所谓怎么办 倔强的学生不理老师怎么办 一岁宝宝特别犟怎么办 孩子遇到问题喜欢发脾气怎么办 企业培养新人跑了怎么办 二年级学生读不懂题目怎么办