机器学习算法与Python实践这个系列主要是参考《机器学习实战》这本书。由于本身想学习Python,而后也想对一些机器学习算法加深下了解,因此就想经过Python来实现几个比较经常使用的机器学习算法。刚好碰见这本一样定位的书籍,因此就参考这本书的过程来学习了。html
这节学习的是逻辑回归(Logistic Regression),也算进入了比较正统的机器学习算法。啥叫正统呢?我概念里面机器学习算法通常是这样一个步骤:python
1)对于一个问题,咱们用数学语言来描述它,而后创建一个模型,例如回归模型或者分类模型等来描述这个问题;git
2)经过最大似然、最大后验几率或者最小化分类偏差等等创建模型的代价函数,也就是一个最优化问题。找到最优化问题的解,也就是能拟合咱们的数据的最好的模型参数;算法
3)而后咱们须要求解这个代价函数,找到最优解。这求解也就分不少种状况了:数据库
a)若是这个优化函数存在解析解。例如咱们求最值通常是对代价函数求导,找到导数为0的点,也就是最大值或者最小值的地方了。若是代价函数能简单求导,而且求导后为0的式子存在解析解,那么咱们就能够直接获得最优的参数了。app
b)若是式子很难求导,例如函数里面存在隐含的变量或者变量相互间存在耦合,也就互相依赖的状况。或者求导后式子得不到解释解,例如未知参数的个数大于已知方程组的个数等。这时候咱们就须要借助迭代算法来一步一步找到最有解了。迭代是个很神奇的东西,它将远大的目标(也就是找到最优的解,例如爬上山顶)记在心上,而后给本身定个短时间目标(也就是每走一步,就离远大的目标更近一点),脚踏实地,心无旁贷,像个蜗牛同样,一步一步往上爬,支撑它的惟一信念是:只要我每一步都爬高一点,那么积跬步,确定能达到本身人生的巅峰,尽享山登绝顶我为峰的豪迈与忘我。框架
另外须要考虑的状况是,若是代价函数是凸函数,那么就存在全局最优解,方圆五百里就只有一个山峰,那命中注定了,它就是你要找的惟一了。但若是是非凸的,那么就会有不少局部最优的解,有无边无际的山峰,人的视野是伟大的也是眇小的,你不知道哪一个山峰才是最高的,可能你会被命运做弄,很无辜的陷入一个局部最优里面,坐井观天,觉得本身找到的就是最好的。没想到山外有山,人外有人,光芒总在未知的远处默默绽开。但也许命运眷恋善良的你,带给你的老是最好的归宿。也有不少不信命的人,以为人定胜天的人,誓要找到最好的,不然不会罢休,永不向命运妥协,除非本身有一天累了,倒下了,也要靠剩下的一口气,迈出一口气能支撑的路程。好悲凉啊……哈哈。dom
呃,不知道扯那去了,也不知道本身说的有没有错,有错的话请你们不吝指正。那下面就进入正题吧。正如上面所述,逻辑回归就是这样的一个过程:面对一个回归或者分类问题,创建代价函数,而后经过优化方法迭代求解出最优的模型参数,而后测试验证咱们这个求解的模型的好坏,冥冥人海,滚滚红尘,咱们是否找到了最适合的那个她。机器学习
1、逻辑回归(LogisticRegression)函数
Logistic regression (逻辑回归)是当前业界比较经常使用的机器学习方法,用于估计某种事物的可能性。以前在经典之做《数学之美》中也看到了它用于广告预测,也就是根据某广告被用户点击的可能性,把最可能被用户点击的广告摆在用户能看到的地方,而后叫他“你点我啊!”用户点了,你就有钱收了。这就是为何咱们的电脑如今广告泛滥的缘由了。
还有相似的某用户购买某商品的可能性,某病人患有某种疾病的可能性啊等等。这个世界是随机的(固然了,人为的肯定性系统除外,但也有可能有噪声或产生错误的结果,只是这个错误发生的可能性过小了,小到千万年不遇,小到忽略不计而已),因此万物的发生均可以用可能性或者概率(Odds)来表达。“概率”指的是某事物发生的可能性与不发生的可能性的比值。
Logistic regression能够用来回归,也能够用来分类,主要是二分类。还记得上几节讲的支持向量机SVM吗?它就是个二分类的例如,它能够将两个不一样类别的样本给分开,思想是找到最能区分它们的那个分类超平面。但当你给一个新的样本给它,它可以给你的只有一个答案,你这个样本是正类仍是负类。例如你问SVM,某个女生是否喜欢你,它只会回答你喜欢或者不喜欢。这对咱们来讲,显得太粗鲁了,要不但愿,要不绝望,这都不利于身心健康。那若是它能够告诉我,她很喜欢、有一点喜欢、不怎么喜欢或者一点都不喜欢,你想都不用想了等等,告诉你她有49%的概率喜欢你,总比直接说她不喜欢你,来得温柔。并且还提供了额外的信息,她来到你的身边你有多少但愿,你得再努力多少倍,知己知彼百战百胜,哈哈。Logistic regression就是这么温柔的,它给咱们提供的就是你的这个样本属于正类的可能性是多少。
还得来点数学。(更多的理解,请参阅参考文献)假设咱们的样本是{x, y},y是0或者1,表示正类或者负类,x是咱们的m维的样本特征向量。那么这个样本x属于正类,也就是y=1的“几率”能够经过下面的逻辑函数来表示:
这里θ是模型参数,也就是回归系数,σ是sigmoid函数。实际上这个函数是由下面的对数概率(也就是x属于正类的可能性和负类的可能性的比值的对数)变换获得的:
换句话说,y也就是咱们关系的变量,例如她喜不喜欢你,与多个自变量(因素)有关,例如你人品怎样、车子是两个轮的仍是四个轮的、长得赛过潘安仍是和犀利哥有得一拼、有千尺豪宅仍是三寸茅庐等等,咱们把这些因素表示为x1, x2,…, xm。那这个女的怎样考量这些因素呢?最快的方式就是把这些因素的得分都加起来,最后获得的和越大,就表示越喜欢。但每一个人内心其实都有一杆称,每一个人考虑的因素不一样,萝卜青菜,各有所爱嘛。例如这个女生更看中你的人品,人品的权值是0.6,不看重你有没有钱,没钱了一块儿努力奋斗,那么有没有钱的权值是0.001等等。咱们将这些对应x1, x2,…, xm的权值叫作回归系数,表达为θ1, θ2,…, θm。他们的加权和就是你的总得分了。请选择你的心仪男生,非诚勿扰!哈哈。
因此说上面的logistic回归就是一个线性分类模型,它与线性回归的不一样点在于:为了将线性回归输出的很大范围的数,例如从负无穷到正无穷,压缩到0和1之间,这样的输出值表达为“可能性”才能说服广大民众。固然了,把大值压缩到这个范围还有个很好的好处,就是能够消除特别冒尖的变量的影响(不知道理解的是否正确)。而实现这个伟大的功能其实就只须要平凡一举,也就是在输出加一个logistic函数。另外,对于二分类来讲,能够简单的认为:若是样本x属于正类的几率大于0.5,那么就断定它是正类,不然就是负类。实际上,SVM的类几率就是样本到边界的距离,这个活实际上就让logistic regression给干了。
因此说,LogisticRegression 就是一个被logistic方程归一化后的线性回归,仅此而已。
好了,关于LR的八卦就聊到这。纳入到正统的机器学习框架下,模型选好了,只是模型的参数θ仍是未知的,咱们须要用咱们收集到的数据来训练求解获得它。那咱们下一步要作的事情就是创建代价函数了。
LogisticRegression最基本的学习算法是最大似然。啥叫最大似然,能够看看个人另外一篇博文“从最大似然到EM算法浅解”。
假设咱们有n个独立的训练样本{(x1, y1) ,(x2, y2),…, (xn, yn)},y={0, 1}。那每个观察到的样本(xi, yi)出现的几率是:
上面为何是这样呢?当y=1的时候,后面那一项是否是没有了,那就只剩下x属于1类的几率,当y=0的时候,第一项是否是没有了,那就只剩下后面那个x属于0的几率(1减去x属于1的几率)。因此无论y是0仍是1,上面获得的数,都是(x, y)出现的几率。那咱们的整个样本集,也就是n个独立的样本出现的似然函数为(由于每一个样本都是独立的,因此n个样本出现的几率就是他们各自出现的几率相乘):
那最大似然法就是求模型中使得似然函数最大的系数取值θ*。这个最大似然就是咱们的代价函数(cost function)了。
OK,那代价函数有了,咱们下一步要作的就是优化求解了。咱们先尝试对上面的代价函数求导,看导数为0的时候可不能够解出来,也就是有没有解析解,有这个解的时候,就皆大欢喜了,一步到位。若是没有就须要经过迭代了,耗时耗力。
咱们先变换下L(θ):取天然对数,而后化简(不要看到一堆公式就惧怕哦,很简单的哦,只须要耐心一点点,本身动手推推就知道了。注:有xi的时候,表示它是第i个样本,下面没有作区分了,相信你的眼睛是雪亮的),获得:
这时候,用L(θ)对θ求导,获得:
而后咱们令该导数为0,你会很失望的发现,它没法解析求解。不信你就去尝试一下。因此没办法了,只能借助高大上的迭代来搞定了。这里选用了经典的梯度降低算法。
2、优化求解
2.一、梯度降低(gradient descent)
Gradient descent 又叫 steepest descent,是利用一阶的梯度信息找到函数局部最优解的一种方法,也是机器学习里面最简单最经常使用的一种优化方法。它的思想很简单,和我开篇说的那样,要找最小值,我只须要每一步都往下走(也就是每一步均可以让代价函数小一点),而后不断的走,那确定能走到最小值的地方,例以下图所示:
但,我同时也须要更快的到达最小值啊,怎么办呢?咱们须要每一步都找下坡最快的地方,也就是每一步我走某个方向,都比走其余方法,要离最小值更近。而这个下坡最快的方向,就是梯度的负方向了。
对logistic Regression来讲,梯度降低算法新鲜出炉,以下:
其中,参数α叫学习率,就是每一步走多远,这个参数蛮关键的。若是设置的太多,那么很容易就在最优值附加徘徊,由于你步伐太大了。例如要从广州到上海,可是你的一步的距离就是广州到北京那么远,没有半步的说法,本身能迈那么大步,是幸运呢?仍是不幸呢?事物总有两面性嘛,它带来的好处是能很快的从远离最优值的地方回到最优值附近,只是在最优值附近的时候,它有心无力了。但若是设置的过小,那收敛速度就太慢了,向蜗牛同样,虽然会落在最优的点,可是这速度若是是猴年马月,咱们也没这耐心啊。因此有的改进就是在这个学习率这个地方下刀子的。我开始迭代是,学习率大,慢慢的接近最优值的时候,个人学习率变小就能够了。所谓采二者之精华啊!这个优化具体见2.3 。
梯度降低算法的伪代码以下:
################################################
初始化回归系数为1
重复下面步骤直到收敛{
计算整个数据集的梯度
使用alpha x gradient来更新回归系数
}
返回回归系数值
################################################
注:由于本文中是求解的Logit回归的代价函数是似然函数,须要最大化似然函数。因此咱们要用的是梯度上升算法。但由于其和梯度降低的原理是同样的,只是一个是找最大值,一个是找最小值。找最大值的方向就是梯度的方向,最小值的方向就是梯度的负方向。不影响咱们的说明,因此当时本身就忘了改过来了,谢谢评论下面@wxltt的指出。另外,最大似然能够经过取负对数,转化为求最小值。代码里面的注释也是有误的,写的代码是梯度上升,注销成了梯度降低,对你们形成的不便,但愿你们海涵。
2.二、随机梯度降低SGD (stochastic gradient descent)
梯度降低算法在每次更新回归系数的时候都须要遍历整个数据集(计算整个数据集的回归偏差),该方法对小数据集尚可。但当遇到有数十亿样本和成千上万的特征时,就有点力不从心了,它的计算复杂度过高。改进的方法是一次仅用一个样本点(的回归偏差)来更新回归系数。这个方法叫随机梯度降低算法。因为能够在新的样本到来的时候对分类器进行增量的更新(假设咱们已经在数据库A上训练好一个分类器h了,那新来一个样本x。对非增量学习算法来讲,咱们须要把x和数据库A混在一块儿,组成新的数据库B,再从新训练新的分类器。但对增量学习算法,咱们只须要用新样本x来更新已有分类器h的参数便可),因此它属于在线学习算法。与在线学习相对应,一次处理整个数据集的叫“批处理”。
随机梯度降低算法的伪代码以下:
################################################
初始化回归系数为1
重复下面步骤直到收敛{
对数据集中每一个样本
计算该样本的梯度
使用alpha xgradient来更新回归系数
}
返回回归系数值
################################################
2.三、改进的随机梯度降低
评价一个优化算法的优劣主要是看它是否收敛,也就是说参数是否达到稳定值,是否还会不断的变化?收敛速度是否快?
上图展现了随机梯度降低算法在200次迭代中(请先看第三和第四节再回来看这里。咱们的数据库有100个二维样本,每一个样本都对系数调整一次,因此共有200*100=20000次调整)三个回归系数的变化过程。其中系数X2通过50次迭代就达到了稳定值。但系数X1和X0到100次迭代后稳定。并且可恨的是系数X1和X2还在很调皮的周期波动,迭代次数很大了,心还停不下来。产生这个现象的缘由是存在一些没法正确分类的样本点,也就是咱们的数据集并不是线性可分,但咱们的logistic regression是线性分类模型,对非线性可分状况无能为力。然而咱们的优化程序并没能意识到这些不正常的样本点,还一视同仁的对待,调整系数去减小对这些样本的分类偏差,从而致使了在每次迭代时引起系数的剧烈改变。对咱们来讲,咱们期待算法能避免来回波动,从而快速稳定和收敛到某个值。
对随机梯度降低算法,咱们作两处改进来避免上述的波动问题:
1)在每次迭代时,调整更新步长alpha的值。随着迭代的进行,alpha愈来愈小,这会缓解系数的高频波动(也就是每次迭代系数改变得太大,跳的跨度太大)。固然了,为了不alpha随着迭代不断减少到接近于0(这时候,系数几乎没有调整,那么迭代也没有意义了),咱们约束alpha必定大于一个稍微大点的常数项,具体见代码。
2)每次迭代,改变样本的优化顺序。也就是随机选择样原本更新回归系数。这样作能够减小周期性的波动,由于样本顺序的改变,使得每次迭代再也不造成周期性。
改进的随机梯度降低算法的伪代码以下:
################################################
初始化回归系数为1
重复下面步骤直到收敛{
对随机遍历的数据集中的每一个样本
随着迭代的逐渐进行,减少alpha的值
计算该样本的梯度
使用alpha x gradient来更新回归系数
}
返回回归系数值
################################################
比较原始的随机梯度降低和改进后的梯度降低,能够看到两点不一样:
1)系数再也不出现周期性波动。2)系数能够很快的稳定下来,也就是快速收敛。这里只迭代了20次就收敛了。而上面的随机梯度降低须要迭代200次才能稳定。
3、Python实现
我使用的Python是2.7.5版本的。附加的库有Numpy和Matplotlib。具体的安装和配置见前面的博文。在代码中已经有了比较详细的注释了。不知道有没有错误的地方,若是有,还望你们指正(每次的运行结果都有可能不一样)。里面我写了个可视化结果的函数,但只能在二维的数据上面使用。直接贴代码:
logRegression.py
4、测试结果
测试代码:
test_logRegression.py
测试数据是二维的,共100个样本。有2个类。以下:
testSet.txt
训练结果:
(a)梯度降低算法迭代500次。(b)随机梯度降低算法迭代200次。(c)改进的随机梯度降低算法迭代20次。(d)改进的随机梯度降低算法迭代200次。
5、参考文献
[1] Logisticregression (逻辑回归) 概述