#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 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)会减少很多时间消耗,就形成了随机梯度下降算法
只是要注意一下标准的梯度下降和随机梯度下降的区别:
- 标准下降时在权值更新前汇总所有样例得到的标准梯度,随机下降则是通过考察每次训练实例来更新。
- 对于步长 alpha的取值,标准梯度下降的alpha比随机梯度下降的大。因为标准梯度下降的是使用准确的梯度,理直气壮地走,随机梯度下降使用的是近似的梯度,就得小心翼翼地走,怕一不小心误入歧途南辕北辙了。
- 当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 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, 特征向量的长度应该等于特征词的个数,
例如 : 将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函数进行转化
- 概率大于0.5的说明属于分类1
- 概率小于0.5的说明属于分类0
1 2 3
| def classifyVector(self, vecX) : prob = sigmoid(sumArray(vecX, self.weights)) return prob
|
#5. 多重分类
- 由于logistic回归只能处理二重分类, 也就是回答是属于一个类别还是不是属于这个类别的问题.
- 当出现多重分类时, 需要进行一些思想的转化
- 将多个分类取其中一个作为正确分类, 将剩余所有类别作为错误分类(
one vs rest), 进行训练系数
- 然后使用多个分类器, 实现多重分类
更多具体信息请看one vs rest
这种分类方式会产生一些偏差, 例如: 样本不均匀
#6. 总结
Logistic回归的目的是寻找一个非线性函数Sigmoid的最佳拟合参数,参数的求解过程可以由最优化算法来完成。在最优化算法中,最常用的就是梯度上升算法,而梯度上升算法有可以简化为随机梯度上升算法。
更多logistic回归的资料 :
logistic回归