#0. logistic回归概述

  • 优点:计算代价不高,易于理解和实现。
  • 缺点:容易欠拟合,分类精度可能不高。
  • 适用数据类型:数值型和标称型数据。
  • 类别:分类算法。
  • 试用场景:解决二分类问题。
  • 简述:Logistic回归算法基于Sigmoid函数,或者说Sigmoid就是逻辑回归函数。Sigmoid函数定义如下:1/(1+exp(-z))。函数值域范围(0,1)。可以用来做分类器。

#1. 回归和Logistic回归的概念
回归
: 假设有一些数据点, 我们利用一条直线对这些点进行拟合(这条线成为最佳拟合直线), 这个拟合的过程称为回归

Logistic回归主要思想
: 根据现有数据对分类边界线建立回归公式, 以此进行分类

Logistic regression是线性回归的一种,线性回归是一种回归

回归其实就是对已知公式的未知参数进行估计。比如已知公式是y = a*x + b,未知参数是a和b。我们现在有很多真实的(x,y)数据(训练样本),回归就是利用这些数据对a和b的取值去自动估计。估计的方法是在给定训练样本点和已知的公式后,对于一个或多个未知参数,机器会自动枚举参数的所有可能取值,直到找到那个最符合样本点分布的参数(或参数组合)。(实际运算有一些优化算法,如果随机梯度下降,不会去枚举的).

##1.1. Sigmoid函数
在logistic回归中需要用到一个函数的性质:
sigmoid的函数有一个性质是讲结果映射到概率([0,1])之间进行输出

Logistic方程

Logistic方程

Logistic Regression 就是一个被sigmoid方程归一化后的线性回归

1
2
def sigmoid(vecX) :
return 1.0 / (1 + math.exp(-vecX))
1
2
3
4
5
6
7
Logistic的一般过程
1. 收集数据 : 采用任意方法收集数据
2. 准备数据 : 由于需要进行距离计算, 因此要求数据类型为数值型. 另外, 结构化数据格式则最佳
3. 分析数据 : 采用任意方法对数据进行分析
4. 训练算法 : 大部分时间用于训练, 训练目的是为了找到最佳的分类回归系数
5. 测试算法 : 分类测试
6. 使用算法 : 输入一些数据, 转换成对应的结构化数值, 然后, 基于训练好的回归系数对这些数值进行简单的回归计算, 判定他们属于那个类别

#2. 梯度下降方法

梯度下降为了找到Logistic回归分类器在数据集中的最佳回归系数,也是整个logistic回归中最重要的一部训练系数

梯度其实就是高数求导方法,对E这个公式针对每个维数(w0,w1)求偏导后的向量▽E(w)=(∂E/∂w0,∂E/∂w1)
对E这个公式针对每个维数(w0,w1)求偏导后的向量▽E(w)=(∂E/∂w0,∂E/∂w1)
梯度为最陡峭上升的方向,对应的梯度下降的训练法则为: w=w - alpha ▽E(w) 这里的η代表学习速率,决定梯度下降搜索中的步长 。
上式的w是向量,即可用将该式写成分量形式为:wi=wi- alpha
∂E/∂wi
现在关键就使计算∂E/∂wi:
推导过程很简单,书上写的很详细,这里只记录结论(其实就是对目标函数求导):
∂E/∂wi=∑(h(x)-y)*(xi)
这里的∑是对样本空间,即训练集进行一次遍历,耗费时间较大,可以使用梯度下降的随机近似.

##2.1. 随机梯度下降的随机近似
既然是随机近似,肯定是用近似方法来改善梯度下降时候的时间复杂度问题。
在∂E/∂wi=∑(h(x)-y)(xi) 的时候∑耗费了大量的时间,特别是在训练集庞大的时候。
如果把求和去掉如何,即变为∂E/∂wi=(h(x)-y)
(xi)会减少很多时间消耗,就形成了随机梯度下降算法

只是要注意一下标准的梯度下降和随机梯度下降的区别

  1. 标准下降时在权值更新前汇总所有样例得到的标准梯度,随机下降则是通过考察每次训练实例来更新。
  2. 对于步长 alpha的取值,标准梯度下降的alpha比随机梯度下降的大。因为标准梯度下降的是使用准确的梯度,理直气壮地走,随机梯度下降使用的是近似的梯度,就得小心翼翼地走,怕一不小心误入歧途南辕北辙了。
  3. 当E(w)有多个局部极小值时,随机梯度反而更可能避免进入局部极小值中。

##2.2. 随机梯度下降的伪码和实现
随机梯度下降在我的理解就是用来训练回归系数值!

1
2
3
4
5
6
7
8
9
伪代码:
初始化回归系数为1
重复下面步骤直到收敛{
对数据集中每个样本
计算该样本的梯度
使用alpha x gradient来更新回归系数
}
返回回归系数值

对logistic Regression来说,梯度下降算法新鲜出炉,如下
随机梯度下降

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def stocGradDescent(self) :
"""
计算权重系数向量
"""
m, n = weiCount(self.train_vec_list)
for j in range(10):
dataIndex = range(m)#生成一个长度为1500左右的list
for index in range(m) :
alpha = 4 / (1.0 + j + index) + 0.01
randIndex = int(random.uniform(0, len(dataIndex)))
h = sigmoid(sumArray(self.train_vec_list[randIndex], self.weights))
#print "h:",h,
error = self.class_list[randIndex] - h
#print "error", error,
self.weights = arraySub(self.weights, arrayMulti(alpha, error, self.train_vec_list[randIndex]))
del(dataIndex[randIndex])
def weiCount(data_mat) :
#返回train_vec_list行数和列数
return len(data_mat), len(data_mat[0])
def sumArray(lineVec, weights) :
#两向量的内积
total = 0
for index in range(len(lineVec)) :
total += (lineVec[index] * weights[index])
#print "total:", total,
return total
def arrayMulti(count, error, lineVec) :
for index in range(len(lineVec)) :
lineVec[index] = count * error * lineVec[index]
return lineVec
def arraySub(weights, lineVec) :
for index in range(len(weights)) :
weights[index] = weights[index] + lineVec[index]
return weights

#3. 特征词和特征向量的选取
对文章分类时, 需要将文章抽象成机器可以识别的一种向量或者其他实现发现, 我在编写程序时使用了提取文章特征词的形式.

##3.1. 特征词提取来源和方法

  1. 对于每一个类别的文章都由属于整个特别的词语, 称为特征词,通过特征词来标识文章的类别
  2. 特征词的提取我知道两种方案

在取特征词的时候一定要注意去停用词, 停用词会在后文讲到

  • 使用TF也就是词频来统计特征, 对整个类别的文章统计所有词语出现的频率, 然后区别类别中出现频率最高的K个词语作为特征词(本人的程序使用了这种方法)
  • 使用TF-IDF来提取特征词, 这里给出维基百科的链接
    TF-IDF
    TF-IDF详细讲解
    文本向量表示及TF-IDF词汇权值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#TF-IDF的实现
def ComputeFreq(wordlist, text):
result = []
for word in wordlist:
countword = text.count(word)
texted = nltk.word_tokenize(text)
length = len(texted)
freq = countword/length
temp = {}
temp['word'] = word
temp['freq'] = freq
#print freq
result.append(temp)
return result
def Computetfidf(wordfreq, corpus):
result = []
for item in wordfreq:
word = item['word']
tf = item['freq']
dlength = len(corpus)
count = 1
for line in corpus:
if line.find(word)!=-1:
count = count+1
idf = math.log10(dlength/count)
tfidf = tf * idf
temp = {}
temp['word'] = word
temp['tfidf'] = tfidf
result.append(temp)
result.sort(lambda x,y : -cmp(x['tfidf'], y['tfidf']))
return result

##3.2. 停用词
在计算词频或者IDF时, 会发生一种现象, 一些并没有特色的词语出现的次数反而最高, 例如: 的, 和, 我等词语,这些词语被称为停用词, 所以我们应该在分词后将他们去掉

1
2
3
4
def makeStopWord(self) :
with open("stop_word.txt", "r") as stop_file :
self.stop_word = stop_file.read()
self.stop_word = self.stop_word.split()

##3.3. 特征词选取的具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def readEssay(self):
"""生成特征词集合"""
one_block = ""
with open("./lily/" + dict_list[0] +".txt", "r") as my_file :
line = my_file.read()
word_list = list(jieba.cut(line, cut_all = False))
word_dict = {}
for word in word_list :
if word not in word_dict :
word_dict[word] = 1
else :
word_dict[word] += 1
word_dict = sorted(word_dict.iteritems(), key = lambda d :d[1], reverse = True)
self.feature = []
for word, fre in word_dict :
self.feature.append(word)
self.feature = self.feature[ : self.dimension]
#for word in self.feature :
# print word,

##3.4. 特征向量的形成
当一个位置类别的文章进入分类器的时候, 我们首先应该讲这个文章转化成机器可以识别的一种语言, 即形成特征向量
步骤:

  1. 将文章分词,并且去停用词
  2. 将文章分词与特征词比对, 出现在特征词中的词语, 对应的向量位置为1, 特征向量的长度应该等于特征词的个数, 例如 : 将1000个特征词, 文章某个词语出现特征词集合中, 这个特征词在特征词集合的位置为123, 则生成的特征向量的第123位置1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def makeVector(self, line) :
"""将一个帖子的关键词转化成对应的特征向量"""
vector = [0] * self.dimension
final = []
#去停用词
for word in line :
#word = word.encode('utf8')
if word not in self.stop_word :
final.append(word)
#生成特征向量
for word in final :
if word in self.feature :
vector[self.feature.index(word)] += 1
#print vector
return vector

#4. 文章分类
将一篇文章生成特征向量, 然后用特征向量与系数向量做内积(系数向量就是随机梯度向量的训练结果), 然后使用sigmoid函数进行转化

  1. 概率大于0.5的说明属于分类1
  2. 概率小于0.5的说明属于分类0
1
2
3
def classifyVector(self, vecX) :
prob = sigmoid(sumArray(vecX, self.weights))
return prob

#5. 多重分类

  1. 由于logistic回归只能处理二重分类, 也就是回答是属于一个类别还是不是属于这个类别的问题.
  2. 当出现多重分类时, 需要进行一些思想的转化
  3. 将多个分类取其中一个作为正确分类, 将剩余所有类别作为错误分类(one vs rest), 进行训练系数
  4. 然后使用多个分类器, 实现多重分类

更多具体信息请看one vs rest

这种分类方式会产生一些偏差, 例如: 样本不均匀

#6. 总结

Logistic回归的目的是寻找一个非线性函数Sigmoid的最佳拟合参数,参数的求解过程可以由最优化算法来完成。在最优化算法中,最常用的就是梯度上升算法,而梯度上升算法有可以简化为随机梯度上升算法。

更多logistic回归的资料 :
logistic回归