有监督学习里面的两个问题,一个是线性回归,一个是逻辑回归。
线性回归问题
指的是:能够预测的值是连续的,比如房子的大小和价格的关系。
问题是预测750平方英尺的时候,价格是多少?
逻辑回归问题
指的是分类问题,也就是预测的结果是离散的。
预测一个乳腺癌是否是恶性的,假设乳腺癌是否恶性与年龄和肿瘤的尺寸的关系如下:
那么,问题是给出一个人,告诉他的年龄和肿瘤的大小,判断是否是恶性的。这个问题是一个分类问题(逻辑回归),因为它预测的结果是一个离散的值,只有恶性与非恶性的两种情况。
1. 逻辑回归
从网上找到一个数据集,做一个简单的逻辑回归的实验。因为是初学者,所有就没有调用第三方进行逻辑回归的库函数。自己写函数实现一下。
数据的格式:
将点显示在图上面:
问题:给绿色的点和红色的点做一个分类。
2. 数学推理过程
这是源数据的格式:
手写的推理过程:
import matplotlib.pyplot as plt
import numpy as np
import math
alpha=0.01
def loadDataSet():
dataMat = []; labelMat = []
fr = open('testSet-LR.txt')
for line in fr.readlines():
lineArr = line.strip().split()
dataMat.append([float(lineArr[0]), float(lineArr[1])])
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
def plot_point(dataMat,labelMat):
length=len(dataMat)
xcord1=[]
ycord1=[]
xcord2=[]
ycord2=[]
for i in range(length):
if labelMat[i]==1:
xcord1.append(dataMat[i][0])
ycord1.append(dataMat[i][1])
else:
xcord2.append(dataMat[i][0])
ycord2.append(dataMat[i][1])
plt.scatter(xcord1,ycord1,c='r')
plt.scatter(xcord2,ycord2,c='g')
def sigmoid(inX):
return 1.0/(1+np.exp(-inX))
def fun_z(th0,th1,th2,x1,x2):
return th0+ th1*x1+th2*x2
def fun_h(z):
return 1.0/(1+math.exp(-z))
def plot_line(theta0,theta1,theta2):
x=np.arange(-5,5,0.1)
#y=theta0+theta1*x
y= (theta0+theta1*x)/(-theta2)
plt.plot(x,y)
plt.show()
def gradAscent(dataMat,labelMat):
theta0=np.random.normal()
theta1=np.random.normal()
theta2=np.random.normal()
m=len(dataMat)
for times in range(3000):
sum1=0.0
sum2=0.0
sum3=0.0
for i in range(m):
z=fun_z(theta0,theta1,theta2,dataMat[i][0],dataMat[i][1])
sum1=sum1+(fun_h(z)-labelMat[i])
sum2=sum2+(fun_h(z)-labelMat[i])*dataMat[i][0]
sum3=sum3+(fun_h(z)-labelMat[i])*dataMat[i][1]
theta0=theta0-(alpha*sum1)
theta1=theta1-(alpha*sum2)
theta2=theta2-(alpha*sum3)
return theta0,theta1,theta2
d,l=loadDataSet()
th0,th1,th2=gradAscent(d,l)
print (th0," , ",th1," , ",th2)
plot_point(d,l)
plot_line(th0,th1,th2)
运行结果:
PS: 关于梯度下降的一种更好的写法(直接用矩阵的乘法去写,这样更简介)
def gradAscent(dataMatIn, classLabels):
dataMatrix = mat(dataMatIn) #convert to NumPy matrix
labelMat = mat(classLabels).transpose() #convert to NumPy matrix
m,n = shape(dataMatrix)
alpha = 0.001
maxCycles = 500
#wight就是表示的是theta0,theta1,theta2
weights = ones((n,1))
for k in range(maxCycles): #heavy on matrix operations
h = sigmoid(dataMatrix*weights) #matrix mult
error = (labelMat - h) #vector subtraction
weights = weights + alpha * dataMatrix.transpose()* error #matrix mult
return weights
源代码和数据集:
https://github.com/zhaozhengcoder/Machine-Learning/tree/master/LogisticRegression
2017年 9月12日 更新 (看了吴恩达 最近新出的deeplearning 的视频)
这个问题,也可以从逻辑回归的本身去理解。
"""
实现一个逻辑回归
1. 数据集是testSet,机器学习实战里面的一个数据集,格式如下:
x1 x2 y
-0.017612 14.053064 0
....
"""
import numpy as np
from numpy import random
import matplotlib.pyplot as plt
alpha=0.01
#加载数据集,原来的数据在文件排列是按行排列
#为了计算需要,将原来的数据加载到了矩阵之后,给矩阵装置了,是数据变成按列排列
def loadDataset():
data=[]
label=[]
f=open("textSet.txt")
for line in f:
lineArr=line.strip().split()
data.append( [float(lineArr[0]),float(lineArr[1]) ] )
label.append(float(lineArr[2]))
mdata=np.array(data)
mlabel=np.array(label)
return mdata.T,mlabel.T
def sigmod(inX):
return 1.0/(1+np.exp(-inX))
#计算error,也就是dz,这个error 是为了计算梯度下降
def forward(mdata,mlabel,weight,b):
z=np.dot(weight,mdata)+b
a=sigmod(z)
error= a - mlabel
return error
#梯度下降,计算出dw,db,然后更新w和b
def gradDesc(mdata,error,weight,b):
nx,m=mdata.shape
dw=(1/m)*np.dot(mdata,error.T)
db=(1/m)*np.sum(error)
weight_transpose = weight.T - alpha*dw
b=b-alpha*db
return weight_transpose.T,b
#代价函数,写这个函数的目的是,在迭代的时候,输出每一次迭代后的cost,判断cost是否是在下降
def cost(mdata,mlabel,weight,b):
nx,m=mdata.shape
z=np.dot(weight,mdata)+b
a=sigmod(z)
cost=-mlabel*np.log(a)-(a-mlabel)*np.log(1-a)
return np.sum(cost)/m
#show result
def show1(mdata,mlabel,weight,b):
nx,m=mdata.shape
z=np.dot(weight,mdata)+b
a=sigmod(z)
for i,j in zip(a[0],mlabel):
print (i,' , ',j)
#将原始的数据和计算之后得到的数据对比,以折线图的方式显示
def show2(mdata,mlabel,weight,b):
nx,m=mdata.shape
z=np.dot(weight,mdata)+b
a=sigmod(z)
plt.plot(a[0])
plt.plot(mlabel)
plt.show()
#将计算得到的数据二值化,小于0.5的变成0,大于0.5的变成1
#由于绝大多数的点都是相同的,所以很多点会被覆盖
def show3(mdata,mlabel,weight,b):
nx,m=mdata.shape
z=np.dot(weight,mdata)+b
a=sigmod(z)
a2=[]
for i in a[0]:
if i >0.5:
a2.append(1)
if i<=0.5:
a2.append(0)
plt.plot(a2,'.')
plt.plot(mlabel,'.')
plt.show()
def regress(maxcycle=100):
mdata,mlabel=loadDataset()
nx,m=mdata.shape
#w和b 随机初始化,代码的目的就是求w和b
weight=random.random(size=(1,nx))
b=random.random(size=(1,m))
#迭代
for i in range(maxcycle):
error=forward(mdata,mlabel,weight,b)
weight,b=gradDesc(mdata,error,weight,b)
print (cost(mdata,mlabel,weight,b))
show1(mdata,mlabel,weight,b)
show2(mdata,mlabel,weight,b)
show3(mdata,mlabel,weight,b)
if __name__=='__main__':
regress(3000)
源码 : https://github.com/zhaozhengcoder/Machine-Learning/tree/master/LogisticRegression