逻辑回归
逻辑回归其实是一个分类算法而不是回归算法。通常是利用已知的自变量来预测一个离散型因变量的值(像二进制值0/1,是/否,真/假)。简单来说,它就是通过拟合一个逻辑函数(logit fuction)来预测一个事件发生的概率。所以它预测的是一个概率值,自然,它的输出值应该在0到1之间。
此时可以看看一个博客,推导公式:http://www.cnblogs.com/daguankele/p/6549891.html
它的核心思想是,如果线性回归的结果输出是一个连续值,而值的范围是无法限定的,那我们有没有办法把这个结果值映射为可以帮助我们判断的结果呢。而如果输出结果是 (0,1) 的一个概率值,这个问题就很清楚了。我们在数学上找了一圈,还真就找着这样一个简单的函数了,就是很神奇的sigmoid函数(如下):
如果把sigmoid函数图像画出来,是如下的样子:
假设你的一个朋友让你回答一道题。可能的结果只有两种:你答对了或没有答对。为了研究你最擅长的题目领域,你做了各种领域的题目。那么这个研究的结果可能是这样的:如果是一道十年级的三角函数题,你有70%的可能性能解出它。但如果是一道五年级的历史题,你会的概率可能只有30%。逻辑回归就是给你这样的概率结果。
Logistic回归简单分析
优点:计算代价不高,易于理解和实现
缺点:容易欠拟合,分类精度可能不高
适用数据类型:数值型和标称型数据
我们都知道逻辑回归是和Sigmod函数一起的,为了实现逻辑回归分类器,我们可以在每一个特征上都乘以一个回归系数,然后将所有的结果值相加,将总和代入S函数,进而得到一个范围在0~1之间的数值。任何大于0.5的数据被分人1类,小于0.5被归为0类。
而现在有了分类器的函数了,那么上面提到的最佳回归系数怎么求呢?这里就出现了基于最优化方法的最佳回归系数的确定。
梯度上升法:要找到某函数的最大值,最好的方法就是沿着该函数的梯度方向探寻。梯度上升法用来求函数的最大值,梯度下降法用来求函数的最小值。
梯度上升法伪代码:
//每个回归系数初始化为1
//重复R次:
//计算整个数据集的梯度
//使用alpha*gradient更新回归系数的向量
//返回回归系数
算法思想:
1、训练
1.1、初始化权重:
1.2、加载数据;
1.3、计算hypothesis
1.4、计算Loss
1.5、计算损失函数J(theta):如果明白变化可以看看极大似然推导公式
1.6、想要最小化损失函数minJ(theta),更新theta(梯度下降法)
即:倒数求解可以私下导一导
2、测试:
练习代码:
#! /usr/bin/python
# -*- coding: utf-8 -*-
import os
import string
import sys
import math
class LogisticRegression :
def __init__ ( self ) :
self.__X = [] #特征集合
self.__Y = [] #标签
self.__theta = [] #权重
self.__LEARNING_RATE = 7 #学习率
self.__FEATURE_CNT = 1 + 2 #特征数
self.__load_training_data () #加载数据
self.__SAMPLE_CNT = len ( self.__Y ) #样本数
self.__feature_scaling () #特征缩放
for idx in range ( 0, self.__FEATURE_CNT ) :
self.__theta.append(0)
def __load_training_data(self) :
fp = open ( "testSet.txt", "r" )
for line in fp.readlines() :
(x1, x2,y) = line.strip('\r\n').split ( '\t' )
self.__X.append ( [1, float(x1), float(x2)] )
self.__Y.append(float(y))
fp.close()
def __feature_scaling(self) :
max_value = []
min_value = []
for fidx in range ( 0, self.__FEATURE_CNT ) :
max_value.append(0)
min_value.append(100)
for idx in range ( 0, self.__SAMPLE_CNT) :
for fidx in range ( 1, self.__FEATURE_CNT ) :
if max_value[fidx] < self.__X[idx][fidx] :
max_value[fidx] = self.__X[idx][fidx]
if min_value[fidx] > self.__X[idx][fidx] :
min_value[fidx] = self.__X[idx][fidx]
for idx in range ( 0, self.__SAMPLE_CNT) :
x = self.__X[idx]
for fidx in range ( 1, self.__FEATURE_CNT ) :
self.__X[idx][fidx] = ( x[fidx] - min_value[fidx] ) / ( max_value[fidx] - min_value[fidx] )
def batch_learning_alogrithm (self) :
last_loss = 0
for itr in range ( 1, 100000 ) :
#1、训练数据
self.__training ()
loss = self.__get_loss ()
sys.stdout.write ( "After %s iteratorion loss = %lf\n" % (itr, loss) )
if math.fabs ( loss - last_loss) <= 0.01 :
break;
last_loss = loss
sys.stdout.write ( "The coef of the logistic model :\n")
for idx in range ( 0, self.__FEATURE_CNT ) :
sys.stdout.write ( "theta[%d] = %lf\n" % ( idx, self.__theta[idx]) )
def __training (self) :
#初始化权重为[0 0 0]
weight = []
for idx in range ( 0, self.__FEATURE_CNT ) :
weight.append(0)
"""计算loss"""
for idx in range ( 0, self.__SAMPLE_CNT) :
x = self.__X[idx]
y = self.__Y[idx]
h = self.__sigmoid( x )
for fidx in range ( 0, self.__FEATURE_CNT ) :
weight[fidx] += ( h - y ) * x[fidx]
"""更新权重"""
for idx in range ( 0, self.__FEATURE_CNT ) :
self.__theta[idx] -= self.__LEARNING_RATE * weight[idx] / self.__SAMPLE_CNT
def __sigmoid ( self, x ) :
logit = 0
for idx in range ( 0, self.__FEATURE_CNT):
logit += self.__theta[idx] * x[idx]
return 1.0 / ( 1.0 + math.exp ( -logit ) )
def __get_loss (self ) :
loss = 0
for idx in range ( 0, self.__SAMPLE_CNT) :
x = self.__X[idx]
y = self.__Y[idx]
h = self.__sigmoid( x )
loss += y * math.log (h) + ( 1 - y ) * math.log ( 1 - h )
return loss
def test ( self ) :
wrong_ans = 0
for idx in range ( 0, self.__SAMPLE_CNT) :
x = self.__X[idx]
y = self.__Y[idx]
h = self.__sigmoid( x )
check = 0
if y > 0.5 and h< 0.5 :
check = -1
if y < 0.5 and h > 0.5 :
check = -1
sys.stdout.write ( "样本 %d : 真值 = %.2lf, 预测 = %.2lf check = %d\n" % ( idx, y, h, check ))
wrong_ans -= check
print "错误 = %d" % wrong_ans
if __name__ == "__main__" :
lr = LogisticRegression()
lr.batch_learning_alogrithm ()
lr.test()
补充:
对于数据输入一般讲数据和标签分开:
def __load_training_data(self):
fp = open("./ex4x.dat", "r")
for line in fp.readlines():
(x1, x2) = line.strip('\r\n').split()
self.__X.append([1, float(x1), float(x2)])
fp.close()
fp = open("./ex4y.dat", "r")
for line in fp.readlines():
y = line.strip('\r\n\t')
self.__Y.append(float(y))
fp.close()
ex4x.dat ex4y.dat
testSet.txt
-0.017612 14.053064 0
-1.395634 4.662541 1
-0.752157 6.538620 0
-1.322371 7.152853 0
0.423363 11.054677 0
0.406704 7.067335 1
0.667394 12.741452 0
-2.460150 6.866805 1
0.569411 9.548755 0
-0.026632 10.427743 0
0.850433 6.920334 1
1.347183 13.175500 0
1.176813 3.167020 1
-1.781871 9.097953 0
-0.566606 5.749003 1
0.931635 1.589505 1
-0.024205 6.151823 1
-0.036453 2.690988 1
-0.196949 0.444165 1
1.014459 5.754399 1
1.985298 3.230619 1
-1.693453 -0.557540 1
-0.576525 11.778922 0
-0.346811 -1.678730 1
-2.124484 2.672471 1
1.217916 9.597015 0
-0.733928 9.098687 0
-3.642001 -1.618087 1
0.315985 3.523953 1
1.416614 9.619232 0
-0.386323 3.989286 1
0.556921 8.294984 1
1.224863 11.587360 0
-1.347803 -2.406051 1
1.196604 4.951851 1
0.275221 9.543647 0
0.470575 9.332488 0
-1.889567 9.542662 0
-1.527893 12.150579 0
-1.185247 11.309318 0
-0.445678 3.297303 1
1.042222 6.105155 1
-0.618787 10.320986 0
1.152083 0.548467 1
0.828534 2.676045 1
-1.237728 10.549033 0
-0.683565 -2.166125 1
0.229456 5.921938 1
-0.959885 11.555336 0
0.492911 10.993324 0
0.184992 8.721488 0
-0.355715 10.325976 0
-0.397822 8.058397 0
0.824839 13.730343 0
1.507278 5.027866 1
0.099671 6.835839 1
-0.344008 10.717485 0
1.785928 7.718645 1
-0.918801 11.560217 0
-0.364009 4.747300 1
-0.841722 4.119083 1
0.490426 1.960539 1
-0.007194 9.075792 0
0.356107 12.447863 0
0.342578 12.281162 0
-0.810823 -1.466018 1
2.530777 6.476801 1
1.296683 11.607559 0
0.475487 12.040035 0
-0.783277 11.009725 0
0.074798 11.023650 0
-1.337472 0.468339 1
-0.102781 13.763651 0
-0.147324 2.874846 1
0.518389 9.887035 0
1.015399 7.571882 0
-1.658086 -0.027255 1
1.319944 2.171228 1
2.056216 5.019981 1
-0.851633 4.375691 1
-1.510047 6.061992 0
-1.076637 -3.181888 1
1.821096 10.283990 0
3.010150 8.401766 1
-1.099458 1.688274 1
-0.834872 -1.733869 1
-0.846637 3.849075 1
1.400102 12.628781 0
1.752842 5.468166 1
0.078557 0.059736 1
0.089392 -0.715300 1
1.825662 12.693808 0
0.197445 9.744638 0
0.126117 0.922311 1
-0.679797 1.220530 1
0.677983 2.556666 1
0.761349 10.693862 0
-2.168791 0.143632 1
1.388610 9.341997 0
0.317029 14.739025 0