1 Logistic 回归算法描述
工作原理:
为了实现 Logistic 回归分类器,可以在每个特征上都乘以一个回归系数,然后把所有结果的值相加,将这个总和带入 Sigmoid 函数中,进而得到一个范围在 0-1 之间的数值。任何大于0.5的数据被分入1类别,任何小于0.5的数据被分入0类别。Logistic 回归也可以被看成是一种概率估计。
2 梯度上升算法伪代码
(1)梯度上升算法伪代码:
每个回归系数初始化为1
重复R次:
计算整个数据集的梯度
使用 alpha*gradient 更新回归系数的向量
返回回归系数
(2)随机梯度上升算法伪代码:
梯度上升算法在每次更新回归系数时,都需要遍历整个数据集,计算的复杂度太高。一种改进方法是,一次仅用一个样本点来更新回归系数,该方法称为随机梯度上升算法。
由于可以在新样本到来时对分类器进行增量式更新,因而随机梯度上升算法是一个在线学习算法。一次处理所有数据被称为是“批处理”。
所有回归系数初始化为1
对数据集中的每个样本:
计算该样本的梯度
使用 alpha*gradient 更新回归系数值
返回回归系数
3 Wiki-最小二乘法、最大似然估计、Sigmoid函数、梯度上升法、梯度下降法、缺失值处理
(1)最小二乘法(LSE)
找到一个(组)估计值,使得实际值与估计值的距离最小。本来用两者差的绝对值汇总并使之最小是最理想的,但绝对值在数学上求最小值比较麻烦,因而替代做法是,找一个(组)估计值,使得实际值与估计值之差的平方加总之后的值最小,称为最小二乘。
“二乘”的英文为least square,其实英文的字面意思是“平方最小”。这时,将这个差的平方的和式对参数求导数,并取一阶导数为零,就是OLSE。
(2)最大似然估计(MLE)
现在已经拿到了很多个样本(数据集中所有因变量),这些样本值已经实现,最大似然估计就是去找到那个(组)参数估计值,使得前面已经实现的样本值发生概率最大。
因为你手头上的样本已经实现了,其发生概率最大才符合逻辑。这时是求样本所有观测的联合概率最大化,是个连乘积,只要取对数,就变成了线性加总。此时通过对参数求导数,并令一阶导数为零,就可以通过解方程(组),得到最大似然估计值。
利用已知的样本结果,反推最有可能(最大概率)导致这样结果的参数值。
(3)Sigmoid 函数
(4)梯度上升算法
最大化似然函数,就用梯度上升。
(5)梯度下降算法
最小化损失函数,就用梯度下降。
(6)缺失值处理
- 使用可用特征的均值来填补缺失值
- 使用特殊值来填补缺失值,例如-1
- 忽略有缺失值的样本
- 使用相似样本的均值填补缺失值
- 使用另外的机器学习算法预测缺失值
4 Logistic 回归的优点与缺点
(1)优点
计算代价不高,容易理解和实现
(2)缺点
容易欠拟合,分类精度可能不高
5 Python代码实现
(1)Logistic回归梯度上升优化算法
import numpy as np
def loadDataSet():
"""
打开文本文件,并逐行读取
:return:
"""
# 数据
dataMat = []
# 标签
labelMat = []
# 打开测试集文本
fr = open('testSet.txt')
# 逐行读取
for line in fr.readlines():
# 去掉 去读行 首尾 空格 ,并 以 空白 进行拆分
lineArr = line.strip().split()
# X0 X1 X2
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
# 标签
labelMat.append(int(lineArr[2]))
return dataMat, labelMat
def sigmoid(inX):
"""
sigmoid 函数
:param inX:
:return:
"""
return 1.0/(1 + np.exp(-inX))
# gradient 梯度
# ascent 上升
def gradAscent(dataMatIn, classLabels):
"""
:param dataMatIn:
:param classLabels:
:return:
"""
# 将 数据集 转换为 numpy 中的 matrix
dataMatrix = np.mat(dataMatIn)
# 将 分类标签 集 转换为 numpy 矩阵,并进行 转置(从 行向量 转换为 列向量)
labelMat = np.mat(classLabels).transpose()
# 获得 数据矩阵 的 形状
m, n = np.shape(dataMatrix)
# 向 目标 移动的步长
alpha = 0.001
# 迭代次数
maxCycles = 500
# 回归系数 矩阵(列向量) n*1
weights = np.ones((n, 1))
for k in range(maxCycles):
# h 为 列向量,列向量的元素个数为 样本个数
# m*n 矩阵【点乘】 n*1 矩阵,生成 m*1 矩阵
h = sigmoid(dataMatrix*weights)
# 计算 真是类别 与 预测类别 的 差值
# error 为 误差值的列向量
error = (labelMat - h)
# 按照 差值 方向 调整 回归系数
# dataMatrix.transpose()*error 为 n*m 矩阵 【点乘】 m*1 矩阵 结果为 n*1 矩阵
weights = weights + alpha*dataMatrix.transpose()*error
return weights
# result_weight = gradAscent(loadDataSet()[0], loadDataSet()[1])
# print(result_weight)
# print(type(result_weight))
(2)随机梯度上升算法
def stocGradAscent0(dataMatrix, classLabels):
m,n = shape(dataMatrix)
alpha = 0.01
# 1*n 的数组
weights = ones(n) #initialize to all ones
for i in range(m):
# dataMatrix[i]*weights 为 1*n 的数组 乘以 1*n 的数组,算术运算
# h 为一个数值
h = sigmoid(sum(dataMatrix[i]*weights))
error = classLabels[i] - h
weights = weights + alpha * error * dataMatrix[i]
return weights
(3)优化的随机梯度上升算法
# stochastic 随机的
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
import random
dataMatrix = np.array(dataMatrix)
m, n = np.shape(dataMatrix)
# 行向量
weights = np.ones(n)
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
# alpha 在每次迭代的时候都会调整,缓解数据波动或者高频波动
# 随着迭代次数不断减小,但永远不会减小到 0,以此保证新数据仍然具有一定影响
# 如果处理的问题是动态变化的,那么可以适当加大常数项,以此来确保新的值获得更大的回归系数
# j 是 迭代次数, i 是 样本点的下标
alpha = 4/(1.0 + j + i) + 0.01
# 从 数据集 中 随机选择样本
randIndex = int(random.uniform(0, len(dataIndex)))
# 数值
h = sigmoid(sum(dataMatrix[dataIndex[randIndex]]*weights))
# 数值
error = classLabels[dataIndex[randIndex]] - h
weights = weights + alpha * error * dataMatrix[dataIndex[randIndex]]
del(dataIndex[randIndex])
return weights
# result_weight = stocGradAscent1(loadDataSet()[0], loadDataSet()[1])
# print(result_weight)
# plotBestFit(result_weight)
6 示例:从疝气病症预测病马的死亡率
"""
使用 Logistic 回归估计 马伤病死亡率
1、收集数据:
给定数据文件
2、准备数据:
用 Python 解析文本并填充缺失值
3、分析数据:
可视化,并观察数据
4、训练算法:
使用优化算法,找到最佳的系数
5、测试算法:
为了量化回归的效果,需要观察错误率。
根据错误率决定是否回退到训练阶段,通过改变迭代的次数和步长等参数得到更好的回归系数
6、使用算法:
实现一个简单的命令行程序来收集马的症状并输出预测结果很容易
说明:
数据集中有 30% 的数据时缺失的
解决数据缺失的方法:
1、使用可用特征的均值来填补缺失值
2、使用特殊值来填补缺失值
3、忽略有缺失值的样本
4、使用相似样本的均值来填补缺失值
5、使用其他的机器学习算法来预测缺失值
"""
from LogisticRegres import *
def classifyVector(inX, weights):
"""
:param inX: 特征向量
:param weights: 回归系数
:return: 分类结果
"""
prob = sigmoid(sum(inX*weights))
if prob > 0.5:
return 1.0
else:
return 0.0
def colicTest():
frTrain = open('horseColicTraining.txt')
frTest = open('horseColicTest.txt')
traingingSet = []
traingingLabels = []
for line in frTrain.readlines():
currLine = line.strip().split()
lineArr = []
for i in range(21):
lineArr.append(float(currLine[i]))
traingingSet.append(lineArr)
traingingLabels.append(float(currLine[21]))
traingingWeights = stocGradAscent1(np.array(traingingSet), traingingLabels, 500)
errorCount = 0
numTestVec = 0.0
for line in frTest.readlines():
numTestVec += 1.0
currLine = line.strip().split()
lineArr = []
for i in range(21):
lineArr.append(float(currLine[i]))
if int(classifyVector(np.array(lineArr), traingingWeights)) != int(currLine[21]):
errorCount += 1
errorRate = float(errorCount)/numTestVec
print("the error rate is %f" % errorRate)
return errorRate
def multiTest():
numTests = 10
errorSum = 0.0
for k in range(numTests):
errorSum += colicTest()
print("after {} iterations the average error rate is : {}".format(numTests, errorSum/float(numTests)))
multiTest()
"""
Logistic 回归的目的是寻找一个非线性函数 Sigmoid 的最佳拟合参数,求解过程可以由最优化算法来完成
随机梯度上升算法 与 梯度上升算法 效果相当,但占用更少的计算资源
随机梯度上升算法是一个在线算法,可以在新数据到来时完成参数更新,而不需要重新读取整个数据集来进行运算
"""
7 使用 pandas 和 scikit-learn 实现书上的例子
import pandas as pd
import numpy as np
from pandas import Series, DataFrame
np.set_printoptions(precision=4)
col_names = []
for i in range(21):
col_names.append('feature_{}'.format(i))
# print(col_list)
train_dataSet_df = pd.read_table('horseColicTraining.txt', names=col_names+['label'])
train_dataSet_df
x
test_dataSet_df = pd.read_table('horseColicTest.txt', names=col_names+['label'])
test_dataSet_df
x
from sklearn.linear_model import LogisticRegression
logistic_reg = LogisticRegression()
x
logistic_reg.fit(train_dataSet_df.ix[:, :-1], train_dataSet_df.ix[:, -1])
xxxxxxxxxx
logistic_reg.predict(test_dataSet_df.ix[:, :-1])
logistic_reg.predict_proba(test_dataSet_df.ix[:, :-1])
logistic_reg.score(test_dataSet_df.ix[:, :-1], test_dataSet_df.ix[:, -1])