by joey周琦
LR介绍
逻辑回归属于probabilistic discriminative model这一类的分类算法
probabilistic discriminative mode这类算法的思路如下:
- 直接建模
- 利用最大似然估计和训练数据,估计出模型中的参数
该类想法相对于生成模型(probabilistic generated model) 有参数较少的优点。因为生成模型需要
LR是工业界最长用的分类算法之一,其主要原因,个人认为有几点如下:
- 训练速度快,扛得住大数据
- 模型可解释度、可理解程度高,根据每个特征的系数,就可以判断出该特征在模型中的重要性,帮助判断模型是否合理
- 可以接受的精度
本文,对LR做一个简单的总结
LR二分类
首先做下简单的符号说明,在下述推导中,
对于
其中
最大化似然函数等价于最大化对数似然函数可以写为
我们要最大化对数似然函数,就是等价于对数似然函数的相反数,则最小化目标函数可以写为:
目标函数对参数
可以利用梯度下降法对参数
其中
这样大大节约了训练时间,也不会特别影响精度。有些系统为了避免过拟合,目标函数中可以加入L1或者 L2正则项(这里采用L2),可以避免
其中
LR多分类
关于多分类的,在特征
其中
那么最大似然函数则可以表示为:
取负并取对数,则得到目标函数:
可以推导(有点麻烦):
所以,梯度下降法对参数
随机梯度下降法:
随机梯度下降法+L2正则,目标函数变为:
则参数的更新变为:
值得注意的是:
- 数据来自kaggle练习比赛的https://www.kaggle.com/c/digit-recognizer/data, 在这里我只用了train.csv数据,其中10%作为测试数据
- 由于数据的feature是像素,0~255,比较大,所以学习率要设置的低一些,或者将feature归一化。
- 加入正则项并不一定可以提高精度
- 结果如果2分类,区分数字0与9,正确率99%。如果是多分类,正确率为84%左右。
LR二分类
import numpy as np
p_test = [ ]
p_train = [ ]
lines = [line.rstrip('\n') for line in open('train.csv')]
label = 0
features = np.zeros(784) #28*28 feature
for line in lines[1:]:
line = line[0:-1]
data = line.split(",")
for i in range(len(data)):
data[i]=float(data[i])
data=np.array(data)
if np.random.rand()<0.1:
p_test.append(data)
else:
p_train.append(data)
#Train LR for 2 class
learing_r = 0.001
w = np.random.rand(784) - 0.5
for img in p_train:
label = img[0]
value = np.array(img[1:])
if label==9: # classify 9 and 0 , ignore others
t=1
elif label==0:
t=0
else:
continue
y = 1.0/(1+np.exp(-np.dot(w,value)))
w = w - learing_r * (y-t) * value
#Test LR
right = 0
wrong = 0
for img in p_test:
label = img[0]
value = np.array(img[1:])
if label==9: # classify 9 and 0 , ignore others
t=1
elif label==0:
t=0
else:
continue
y = 1.0/(1+np.exp(-np.dot(w,value)))
if y>0.5:
pt=1
else:
pt=0
if pt==t:
right+=1
else:
wrong+=1
print right*1.0/(right+wrong)
LR多分类
'''
Created on 2015 8 23
@author: joeyqzhou
'''
import numpy as np
import bigfloat
p_test = [ ]
p_train = [ ]
lines = [line.rstrip('\n') for line in open('train.csv')]
label = 0
features = np.zeros(784) #28*28 feature
for line in lines[1:]:
line = line[0:-1]
data = line.split(",")
for i in range(len(data)):
data[i]=float(data[i])
data=np.array(data)
if np.random.rand()<0.1:
p_test.append(data)
else:
p_train.append(data)
#Train LR for multiple class
learing_r = 0.000001
W = [ ]
K = 10 # 10 class
for i in range(K):
W.append(np.random.rand(784)*0.1 - 0.05)
for img in p_train:
label = img[0]
value = np.array(img[1:])
y = np.zeros(K)
temp_y = np.zeros(K) #unnormalized y
for i in range(K):
temp_y[i] = bigfloat.exp( np.dot(W[i], value) )
for i in range(K):
y[i] = temp_y[i]/np.sum(temp_y)
for i in range(K): #update the parameter
if abs(i-label) < 0.0001:
W[i] = W[i] - learing_r * (y[i]-1) * value
else:
W[i] = W[i] - learing_r * (y[i]-0) * value
#Test LR for multiple class
right_count = 0
whole_count = 0
for img in p_test:
label = img[0]
value = np.array(img[1:])
y = np.zeros(K)
for i in range(K):
y[i] = np.dot(W[i], value) #not necessary to normalize
inx = np.argmax(y)
if abs(inx - label)<0.001:
right_count += 1
whole_count += 1
print right_count*1.0/whole_count