Logistic回归与Sigmord函数

关于这两者的详细介绍我在以前整理的听课笔记中有写到,这里我就不做相关的详细叙述了

Machine Learning-3

本文分别使用python与matlab实现Logistic回归算法以及优化函数

源码以及数据集

Logistic回归

一般过程

  • 收集数据:采用任何方法收集数据
  • 准备数据:由于需要进行距离计算,因此要求数据类型为数值型。另外,结构化数据格式最佳
  • 分析数据:采用任何方法对数据进行分析
  • 训练算法:大部分时间将用与训练,训练的目的是为了找到最佳的分类回归函数
  • 测试算法:一旦训练步骤完成,分类将会很快
  • 使用算法:首先我们需要输入一些数据,并将其转换为结构化数值;接着,基于训练后的回归函数就可以对数值进行简单的回归计算,判定它们属于哪个类别;在这之后,我们就可以在输出类别上做一些其他分析工作

优点:计算代价不高,易于理解和实现

缺点:容易欠拟合,分类精度可能不高

试用数据类型:数值型和标称型数据

python实现

首先先导入数据

  • 打开文件读取数据
  • 每行前两个值分别为X1、X2,第三个值是数据对应的类别标签
  • 第0维特征X0 = 1
1
2
3
4
5
6
7
8
def loadDataSet():
dataMat = []; labelMat = []
fr = open('testSet.txt')
for line in fr.readlines():
lineArr = line.strip().split()
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
labelMat.append(int(lineArr[2]))
return dataMat, labelMat

Sigmord实现

Sigmord函数就一行代码,具体函数形式可以点击文章开始的链接,里面详细介绍了Sigmord函数以及Logistic函数的代价函数

1
2
def sigmoid(inX):
return 1.0/(1+exp(-inX))

梯度上升算法

梯度上升方法与梯度下降算法
两者不同在于只是将公式中的加号变为减号
前者求最大值,后者求最小值
使用梯度上升找到最佳参数

dataMatIn: 2维Numpy数组,每列分别代表每个不同的特征,每行代表每个训练样本
classLabels: 类别标签,一组一维行向量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def gradAscent(dataMatIn, classLabels):
# 转换为矩阵类型
dataMatrix = mat(dataMatIn)
# 为便于计算,将类别标签转置
labelMat = mat(classLabels).transpose()
m, n = shape(dataMatrix)
alpha = 0.001 # 目标移动的步长
maxCycles = 500 # 迭代次数
weights = ones((n,1))
for k in range(maxCycles):
# 矩阵相乘
h = sigmoid(dataMatrix * weights)
# 计算真实类别与预测类型的差值
error = (labelMat - h)
weights = weights + alpha * dataMatrix.transpose() * error
return weights

画出数据集合Logistic回归最佳拟合直线的函数

使用的还是matplotlib模块绘图,具体安装方法我在这篇文章里详细介绍了matplotlib安装,具体位置在这篇文章的中心部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def plotBestFit(weights):
import matplotlib.pyplot as plt
dataMat, labelMat = loadDataSet()
dataArr = array(dataMat)
n = shape(dataArr)[0]
xcord1 = []; ycord1 = []
xcord2 = []; ycord2 = []
for i in range(n):
if int(labelMat[i]) == 1:
xcord1.append(dataArr[i,1])
ycord1.append(dataArr[i,2])
else:
xcord2.append(dataArr[i,1])
ycord2.append(dataArr[i,2])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xcord1, ycord1, s=30, c = 'red', marker='s')
ax.scatter(xcord2, ycord2, s=10, c = 'green')
x = arange(-3.0, 3.0, 0.1)
# 最佳拟合直线
y = (-weights[0] - weights[1]*x)/weights[2]
ax.plot(x, y)
plt.xlabel('X1'); plt.ylabel('X2')
plt.show()

随机梯度上升算法

代码与前面的梯度上升很像,但是这里计算weights时是用的是向量,而非数值;而且前者没有使用矩阵转换,使用的是Numpy数组

随机梯度上升算法相较于梯度上升算法的好处:
两者效果相当但是前者会占用比较少的计算机资源
此外前者是一个在线算法,即可以在新数据到来时就完成数据的更新,而不用重新读取整个数据集重新进行批处理

1
2
3
4
5
6
7
8
9
def stocGradAscent0(dataMatrix, classLabels):
m,n = shape(dataMatrix)
alpha = 0.01
weights = ones(n)
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights))
error = classLabels[i] - h
weights = weights + alpha * error * dataMatrix[i]
return weights

随机梯度上升改进版

我在这里规定迭代次数为150次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def stocGradAscent1(dataMatrix, classLabels, numInter = 150):
m,n = shape(dataMatrix)
weights = ones(n)
for j in range(numInter):
dataIndex = range(m)
for i in range(m):
# alpha 在每次迭代时需要调整,一避免参数的严格下降
alpha = 4/(1.0 + j + i) + 0.01
# 随机选取更新,以减少周期性的波动
randIndex = int(random.uniform(0, len(dataIndex)))
h = sigmoid(sum(dataMatrix[randIndex] * weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
# 删除此次选取的随机值,方便下次迭代
del(dataIndex[randIndex])
return weights

Matlab实现

同样先是Sigmord函数,也是很简单的一行代码

1
2
3
4
5
6
7
function g = sigmoid(z)
%SIGMOID Compute sigmoid functoon
% J = SIGMOID(z) computes the sigmoid of z.

g = 1.0 ./ (1.0 + exp(-z));

end

然后是计算Logistic的cost函数,即上面的weights

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function [J, grad] = lrCostFunction(theta, X, y, lambda)
%LRCOSTFUNCTION Compute cost and gradient for logistic regression with
%regularization

% Initialize some useful values
m = length(y); % number of training examples

J = 0;
grad = zeros(size(theta));


htheta = sigmoid(X\*theta);
J = 1/m\*sum(-y .* log(htheta) - (1-y) .* log(1-htheta)) + lambda/(2\*m)* sum(theta(2:end) .^ 2);

temp = theta;
temp(1) = 0;
grad = 1/m\*(X' * (htheta - y) + lambda*temp);

grad = grad(:);

end

总结

说是总结其实不过是把在本文开头的那篇关于Logistic的听课笔记翻译为中文然后挑些有关Logistic的干货

Logistic回归是为了寻找一个非线性函数sigmord的最佳拟合函数,求解算法可使用最优化算法完成

最优化算法使用随机梯度上升算法

最后则是个补充

处理数据中的缺失值

想学好任何一门技能都要大量的练习,而机器学习的练习则需要大量的无误的数据作为基础

网上有很多开源的大型数据集,上网随便找一下就可以了,而且很多大学的数据集都是开源的,比如布朗大学的人脸数据库

除去寻找合适的数据集外,还需要注意的就是如何处理数据中缺失的值

coursera上斯坦福的机器学习课程我记得就在前几节的样子,告诉我们如何处理。可见如何处理数据中的缺失值也是很重要的过程

主要方法就是一下几种,选取处理方式时要根据使用的算法来决定。比如你使用本文介绍的Logistic算法最简单就是将缺失的那条数据丢弃,然而如果你使用我再前面几篇文章中介绍的k-means算法的话就不行了

  • 使用可用特征的均值来填补缺失值
  • 使用特殊值来填补空缺
  • 忽略有缺失的样本
  • 使用相似样本的均值填补缺失值
  • 使用另外的机器学习算法预测缺失值

如果你有一个很好的算法的话,最后一个方法则是最好的方法