本博客的理论细节在这里:机器学习入门-分类问题的拟合
本博客侧重于实现,细节理论不再过多赘述,只简单介绍。
线性模型理论分析
线性回归是一个处理二分类问题的常见分类算法,其得出的回归函数为线性模型回归函数。
1.确定拟合函数h(x)
要拟合的函数有两种,分别是线性回归函数和逻辑回归函数
对
于
超
平
面
来
说
,
线
性
回
归
的
模
型
是
h
(
x
)
=
k
x
+
b
这
个
k
,
x
,
b
都
可
以
是
多
维
的
,
只
需
要
满
足
k
x
线
性
相
乘
即
可
。
其
实
,
将
x
增
加
一
个
值
为
1
的
维
度
,
k
和
b
合
成
一
个
向
量
组
,
就
可
以
写
成
矩
阵
相
乘
的
形
式
:
即
:
θ
=
[
b
,
k
]
T
,
x
=
[
1
,
x
]
T
即
:
h
θ
(
x
)
=
θ
T
x
对于超平面来说,线性回归的模型是h(x)=kx+b\\ 这个k,x,b都可以是多维的,只需要满足kx线性相乘即可。\\ 其实,将x增加一个值为1的维度,k和b合成一个向量组,就可以写成矩阵相乘的形式:\\ 即:\theta=[b,k]^T,x=[1,x]^T\\ 即:h_\theta(x)=\theta^T x
对于超平面来说,线性回归的模型是h(x)=kx+b这个k,x,b都可以是多维的,只需要满足kx线性相乘即可。其实,将x增加一个值为1的维度,k和b合成一个向量组,就可以写成矩阵相乘的形式:即:θ=[b,k]T,x=[1,x]T即:hθ?(x)=θTx
对
于
非
线
性
回
归
,
通
常
使
用
h
(
x
)
=
1
1
+
e
?
(
k
x
+
b
)
来
表
示
同
理
,
k
,
x
,
b
都
可
以
是
多
维
的
,
用
向
量
组
来
表
示
:
h
θ
(
x
)
=
1
1
+
e
?
θ
T
x
y
=
1
i
f
?
h
θ
(
x
)
>
0.5
y
=
0
i
f
?
h
θ
(
x
)
<
0.5
y
=
0
?
o
r
?
1
i
f
?
h
θ
(
x
)
=
0.5
对于非线性回归,通常使用h(x)=\frac{1}{1+e^{-(kx+b)}}来表示\\ 同理,k,x,b都可以是多维的,用向量组来表示:\\ h_\theta(x)=\frac{1}{1+e^{-\theta^Tx}}\\ y=1\quad if\ h_\theta(x)>0.5\\ y=0\quad if\ h_\theta(x)<0.5\\ y=0\ or\ 1\quad if\ h_\theta(x)=0.5
对于非线性回归,通常使用h(x)=1+e?(kx+b)1?来表示同理,k,x,b都可以是多维的,用向量组来表示:hθ?(x)=1+e?θTx1?y=1if?hθ?(x)>0.5y=0if?hθ?(x)<0.5y=0?or?1if?hθ?(x)=0.5
其实本质仍是线性回归,只是它的h(x)的映射区间变为了非线性
2.确定损失函数J(θ)
损失函数也是较好确定的,计算拟合函数h(x)和真实值的距离即可。
//这里对于非线性回归使用了交叉熵损失函数优化,不细说了。
很
明
显
,
对
于
单
个
样
本
的
损
失
函
数
:
J
(
θ
)
=
C
o
s
t
(
h
θ
(
x
)
,
y
)
=
?
log
?
(
h
θ
(
x
)
)
i
f
?
k
=
1
J
(
θ
)
=
C
o
s
t
(
h
θ
(
x
)
,
y
)
=
?
log
?
(
1
?
h
θ
(
x
)
)
i
f
?
k
=
0
合
并
起
来
就
是
:
J
(
θ
)
=
C
o
s
t
(
h
θ
(
x
)
,
y
)
=
?
(
log
?
(
h
θ
(
x
)
)
y
+
log
?
(
1
?
h
θ
(
x
)
)
(
1
?
y
)
)
\begin{aligned} & 很明显,对于单个样本的损失函数:\\ & J(\theta)=Cost(h_\theta(x),y)=-\log (h_\theta(x))\qquad\qquad if\ k=1\\ & J(\theta)=Cost(h_\theta(x),y)=-\log(1-h_\theta(x))\qquad if\ k=0\\ & 合并起来就是:\\ & J(\theta)=Cost(h_\theta(x),y)=-(\log(h_\theta(x))y+\log(1-h_\theta(x))(1-y))\\ \end{aligned}
?很明显,对于单个样本的损失函数:J(θ)=Cost(hθ?(x),y)=?log(hθ?(x))if?k=1J(θ)=Cost(hθ?(x),y)=?log(1?hθ?(x))if?k=0合并起来就是:J(θ)=Cost(hθ?(x),y)=?(log(hθ?(x))y+log(1?hθ?(x))(1?y))?
从单样本推广到多样本:
极大似然估计法此处不详细说明
对
于
多
个
训
练
样
本
{
x
(
i
)
,
y
(
i
)
}
来
说
,
用
极
大
似
然
估
计
法
,
其
训
练
集
的
代
价
函
数
为
:
J
(
θ
)
=
?
1
m
∑
i
=
1
m
C
o
s
t
(
h
θ
(
x
(
i
)
)
,
y
(
i
)
)
=
?
1
m
∑
i
=
1
m
[
log
?
(
h
θ
(
x
(
i
)
)
)
y
(
i
)
+
log
?
(
1
?
h
θ
(
x
(
i
)
)
)
(
1
?
y
(
i
)
)
]
\begin{aligned} & 对于多个训练样本\{x^{(i)},y^{(i)}\}来说,用极大似然估计法,其训练集的代价函数为:\\ & J(\theta)=-\frac{1}{m}\sum_{i=1}^mCost(h_\theta(x^{(i)}),y^{(i)})=-\frac{1}{m}\sum_{i=1}^m[\log(h_\theta(x^{(i)}))y^{(i)}+\log(1-h_\theta(x^{(i)}))(1-y^{(i)})]\\ \end{aligned}
?对于多个训练样本{x(i),y(i)}来说,用极大似然估计法,其训练集的代价函数为:J(θ)=?m1?i=1∑m?Cost(hθ?(x(i)),y(i))=?m1?i=1∑m?[log(hθ?(x(i)))y(i)+log(1?hθ?(x(i)))(1?y(i))]?
我们求出合适的k,b来获得最小的损失函数J(θ)
3.使用梯度下降求解
梯度下降就是求导,通过找到求导找到损失函数最快下降的方向,逐渐逼近最优的L(k,b)。
(这里涉及到同步更新和异步更新的选择,一般来讲,我们选择同步更新)
根
据
梯
度
下
降
算
法
,
更
新
每
一
项
θ
,
使
其
延
代
价
函
数
对
θ
的
切
线
方
向
(
偏
导
数
)
下
降
θ
j
:
=
θ
j
?
α
?
?
θ
j
J
(
θ
)
求
导
:
θ
j
:
=
θ
j
?
α
?
(
1
m
[
∑
i
=
1
m
y
(
i
)
l
o
g
h
θ
(
x
(
i
)
)
+
(
1
?
y
(
i
)
)
l
o
g
(
1
?
h
θ
(
x
(
i
)
)
)
]
)
?
θ
j
θ
j
:
=
θ
j
?
α
(
y
(
i
)
?
h
θ
(
x
(
i
)
)
)
x
(
i
)
\begin{aligned} & 根据梯度下降算法,更新每一项\theta,使其延代价函数对\theta的切线方向(偏导数)下降\\ &\qquad \theta_j:=\theta_j-\alpha\frac{\partial}{\partial\theta_j}J(\theta)\\ & 求导:\\ &\qquad \theta_j:=\theta_j-\alpha\frac{\partial (\frac{1}{m}[\sum_{i=1}^my^{(i)}logh_{\theta}(x^{(i)})+(1-y^{(i)})log(1-h_{\theta}(x^{(i)}))])}{\partial\theta_j} \\ &\qquad\theta_j :=\theta_j-\alpha (y^{(i)}-h_\theta(x^{(i)})) x^{(i)} \end{aligned}
?根据梯度下降算法,更新每一项θ,使其延代价函数对θ的切线方向(偏导数)下降θj?:=θj??α?θj???J(θ)求导:θj?:=θj??α?θj??(m1?[∑i=1m?y(i)loghθ?(x(i))+(1?y(i))log(1?hθ?(x(i)))])?θj?:=θj??α(y(i)?hθ?(x(i)))x(i)? 详细化简步骤:
当取log的e为底时lne=1,可以忽略掉。
自此,我们已经基本明确了如何拟合,确定损失函数,使用梯度下降求取θ
4.确定算法执行过程
S
t
e
p
1
:
随
机
选
择
一
个
梯
度
θ
S
t
e
p
2
:
重
复
进
行
梯
度
下
降
求
取
θ
确
定
步
长
α
同
步
更
新
θ
j
:
=
θ
j
?
α
?
?
θ
j
J
(
θ
j
)
S
t
e
p
3
:
找
到
合
适
的
θ
终
止
循
环
\begin{aligned} & Step1:随机选择一个梯度\theta\\ & Step2:重复进行梯度下降求取\theta\\ &\qquad 确定步长\alpha\\ &\qquad 同步更新\theta_j:=\theta_j-\alpha\frac{\partial}{\partial\theta_j}J(\theta_j)\\ & Step3:找到合适的\theta终止循环 \end{aligned}
?Step1:随机选择一个梯度θStep2:重复进行梯度下降求取θ确定步长α同步更新θj?:=θj??α?θj???J(θj?)Step3:找到合适的θ终止循环?
逻辑回归python实践
根据以上的分析,我们依次进行实现。
1.拟合函数h(x)实现
我们只需要对着上面的h(x)进行编写即可。
新建一个文件:LogisticRegressionTrain.py,用作训练逻辑回归。
在其中先导入numpy库(用到了自然对数e和矩阵乘法),后写入拟合函数h(x)。
import numpy as np
def forecast(theta,x):
'''
forecast()函数,用来求x的预测值
输入:theta预测模型((n+1)*1表示n+1个特征)
x样本(m*(n+1)表示m行n+1列,m个样本,每个样本有n+1个特征,多出来的是作为常数项1)
输出:forecastValue预测值(m*1)的一个数组
'''
forecastValue=1.0/(1+np.exp(-(x*theta)))
return forecastValue
x=np.mat([[1],[-1]])
theta=np.mat([1])
y=np.mat([[0],[1]])
fc=forecast(theta,x)
print(fc)
'''输出结果
[[0.73105858]
[0.26894142]]
'''
- np.exp(x)表示e^x
- np.dot(a,b)表示a和b的点乘(即a点乘b),也可以用矩阵乘积表示如a*b表示矩阵a点乘矩阵b
- np.mat([])创建一个自定义的矩阵
2.损失函数J(θ)实现
在拟合函数下面继续写损失函数
def errorRate(y,fc):
'''
errorRate()函数,用来求损失函数
输入:y样本值(m*1的一个矩阵,表示m个样本的样本值)
fc预测值(m*1的一个矩阵,表示m个样本的预测值)
输出:损失函数值
'''
m=np.shape(y)[0]
sum_err=0.0
for i in range(m):
sum_err+=(np.log(fc[i,0])*y[i,0])+(np.log(1-fc[i,0])*(1-y[i,0]))
sum_err/=m
return sum_err
x=np.mat([[1],[-1]])
theta=np.mat([1])
y=np.mat([[0],[1]])
fc=forecast(theta,x)
print(fc)
errrate=errorRate(y,fc)
print(errrate)
'''输出
[[0.73105858]
[0.26894142]]
-1.3132616875182228
'''
- np.log(x)表示取x的对数,底数为e。
- for i in range(m)表示遍历从0到m-1.
- np.shape(x)返回一个元组(m,n)表示m行n列,可以用下表获取其值[0]表示获取m,[1]表示获取n
- a.reshape(m,n)表示将a数组变为m*n的数组
3.使用梯度下降求解
根据前文的理论分析(梯度下降求解和算法执行步骤)。写成算法执行代码。
继续在损失函数下写循环梯度下降的代码
def loopGradientDescent(alpha,y,x,cnt):
'''
loopGradientDescent()函数,用来循环梯度下降求最小的损失函数
输入:
alpha学习率,可以考虑采用动态步长
y样本值(m*1的一个数组,表示m个样本值)
x样本(m*(n+1)的一个数组,表示m个样本,n+1个特征)
cnt最大迭代次数
输出:模型theta((n+1)*1的一个数组,表示n+1个特征的值)
'''
n=np.shape(x)[1]
m=np.shape(x)[0]
theta=np.mat(np.ones((n,1)))
for i in range(cnt):
fc=forecast(theta,x)
theta=theta+alpha*((x.T)*(y-fc)).T
if i%100==0:
errrate=errorRate(y,fc)
print("第"+str(i)+"次循环,误差率:"+str(errrate))
print("theta:")
print(theta)
return theta
x=np.mat([[1],[-1]])
theta=np.mat([1])
y=np.mat([[0],[1]])
print(loopGradientDescent(0.01,y,x,1000))
'''输出
第0次循环,误差率:-1.3132616875182228
theta:
[[0.98537883]]
第100次循环,误差率:-0.6081473016504946
theta:
[[-0.18701442]]
第200次循环,误差率:-0.33968882966892394
theta:
[[-0.9108378]]
第300次循环,误差率:-0.22336178898792158
theta:
[[-1.38920714]]
第400次循环,误差率:-0.16291489229543835
theta:
[[-1.73497099]]
第500次循环,误差率:-0.12697105578355802
theta:
[[-2.00202377]]
第600次循环,误差率:-0.10348538022891132
theta:
[[-2.21810228]]
第700次循环,误差率:-0.0870689750980542
theta:
[[-2.39887204]]
第800次循环,误差率:-0.07500562145864893
theta:
[[-2.55390024]]
第900次循环,误差率:-0.0657951431074245
theta:
[[-2.68940486]]
[[-2.80849509]]
第1000次直接跳出循环了,因此没有输出。
'''
可见误差率在逐渐减小。
- np.mat()得到一个矩阵,自己定义
- np.ones(m,n)得到一个m*n的全1矩阵
- 矩阵相乘=点乘。矩阵加减=对应元素加减。常数*矩阵=常数*矩阵中的每个元素
- str(x)将x变为字符串
以上就是对逻辑回归的所有算法代码了。
接下来要实现的就是数据存取,模型存取,图表绘画等问题。
数据存取与模型存取
我们当然不能在python中手动一个个打进去样本,因此我们采用文件读取的方式来简化样本的输入输出。
使用python提供的io方法。
1.数据获取
随机生成数据
通过随机数据生成器,生成了一些数据,数据样本的格式为{x1,x2,y}
虽然是随机生成的数据,但是我们还要大概划分一下区域的,不能乱生成,否则也找不到线性可分的地方
同目录下新建一个randomData.py的文件,用来生成随机数据
import numpy as np
import random
def randomTrainData(m,n):
'''
randomData()函数生成随机数据,m组样本,每组样本n个特征值
输入:m表示m个样本
n表示n和特征
输出:(m*(n+1))的一个样本矩阵,m个样本,n个特征+1个样本值
'''
dataSet0=[]
dataSet1=[]
for i in range(n):
tmpData=np.random.normal(2,1.2,m)
dataSet0.append(tmpData)
tmpData=[]
for i in range(m):
tmpData.append(0)
dataSet0.append(tmpData)
for i in range(n):
tmpData=np.random.normal(8,1.2,m)
dataSet1.append(tmpData)
tmpData=[]
for i in range(m):
tmpData.append(1)
dataSet1.append(tmpData)
dataSet0=(np.mat(dataSet0)).T
dataSet1=(np.mat(dataSet1)).T
dataSet=[]
dataSet.append(dataSet0)
dataSet.append(dataSet1)
dataSet=np.concatenate(dataSet)
print(dataSet)
return dataSet
def saveTrainData(fileName,dataSet):
'''
saveTrainData()函数将随机到的训练数据存入本地
输入:fileName保存文件名
dataSet一个m*n的矩阵,就是我们得到的训练集
'''
f=open(fileName,"w")
m=np.shape(dataSet)[0]
n=np.shape(dataSet)[1]
for i in range(m):
tmp=[]
for j in range(n):
tmp.append(str(dataSet[i,j]))
f.write("\t".join(tmp))
f.write("\n")
f.close()
if __name__=="__main__":
dataSet=randomTrainData(5,2)
saveTrainData("trainData",dataSet)
这样我们就可以得到一个文件名为trainData的数据集了。
更直观上了解点集的分布
如果特征值较少,可以画出点集的分布,在python中做出散点图,这样可以更加直观的看出来我们的数据分布了
在同一目录下新建一个showPicture.py的文件。
读取数据+绘画
import numpy as np
import matplotlib.pyplot as plt
def loadData(fileName):
'''
loadData()从训练集中读出数据,并分类set0和set1
输入:fileName文件名
输出:两个m*n的矩阵,m个样本,n个特征
'''
f=open(fileName)
pointSet0=[]
pointSet1=[]
for line in f.readlines():
tmpPointX=[]
tmpPointY=[]
lines=line.strip().split("\t")
for i in range(len(lines)-1):
tmpPointX.append(float(lines[i]))
tmpPointY.append(float(lines[-1]))
if tmpPointY[0] == 0:
pointSet0.append(tmpPointX)
else:
pointSet1.append(tmpPointX)
return np.mat(pointSet0),np.mat(pointSet1)
def drawPicture(pointSet0,pointSet1,xlen,ylen):
'''
drawPicture()函数通过输入的点和长度,画出散点图
输入:pointSet0一个m*n的矩阵,表示m个样本,n个特征
pointSet1一个m*n的矩阵,表示m个样本,n个特征
xlen一个两个变量的列表,[最小值,最大值]
ylen一个两个变量的列表,[最小值,最大值]
'''
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.xlabel('X1')
plt.ylabel('X2')
plt.xlim(xmax=xlen[1],xmin=xlen[0])
plt.ylim(ymax=ylen[1],ymin=ylen[0])
colors1 = '#00CED1'
colors2 = '#DC143C'
area = np.pi * 2**2
m=np.shape(pointSet0)[0]
n=np.shape(pointSet0)[1]
for i in range(m):
if i==0:
plt.scatter(pointSet0[i,0],pointSet0[i,1],c=colors1,alpha=0.4,label='0')
else:
plt.scatter(pointSet0[i,0],pointSet0[i,1],c=colors1,alpha=0.4)
m=np.shape(pointSet1)[0]
for i in range(m):
if i==0:
plt.scatter(pointSet1[i,0],pointSet1[i,1],c=colors2,alpha=0.4,label='1')
else:
plt.scatter(pointSet1[i,0],pointSet1[i,1],c=colors2,alpha=0.4)
plt.legend()
plt.show()
if __name__=="__main__":
pointSet0,pointSet1=loadData("trainData.txt")
print(pointSet0)
print(pointSet1)
drawPicture(pointSet0,pointSet1,[-1,12],[-1,12])
可以看出来,我们的数据分布还是挺不错的
我随机出来的数据在文末的git仓库中,可以自行下载比较
2.数据存取
训练模型之前首先要获得数据,假设我的数据文件trainData.txt放在同目录下。
继续在上面的逻辑回归核心代码下面写文件存取
里面用到的文件io直接用python的内置库即可,无需再导入其他库
def dataLoad(fileName):
'''
dataLoad()函数用来通过文件名来获取其中的数据
输入:fileName样本集保存的文件名
输出:x矩阵(m*(n+1)),m个样本,n个x特征,1个常数项特征
y矩阵(m*1),m个样本,1个样本y
'''
f=open(fileName)
x=[]
y=[]
for line in f.readlines():
tmpx=[]
tmpy=[]
lines=line.strip().split("\t")
tmpx.append(1)
for i in range(len(lines)-1):
tmpx.append(float(lines[i]))
tmpy.append(float(lines[-1]))
x.append(tmpx)
y.append(tmpy)
f.close()
return np.mat(x),np.mat(y)
x,y=dataLoad("trainData.txt")
print(x)
print(y)
- f=open(string)默认只读的方式打开一个文件,之后通过f操作文件。可以在后面加入r,w等更改打开方式
- f.close()关闭文件io
- np.append(arr,x)表示向数组arr后插入x
- np.delete(arr,x)表示删除数组中下标为x的值
- strip([chars])在字符串上执行lstrip()和rstrip()
- lstrip()删除字符串左边的空格或指定字符
- rstrip()删除字符串末尾的空格或指定字符
- split(str="")以指定元素为分隔符分割字符串
- float(string)将字符串变为小数
3.模型存取
执行完回归学习后,需要将得到的回归模型持久化。
该模型只需要将参数θ保存在本地即可
def saveModel(fileName,theta):
'''
saveModel()将模型保存到fileName的文件中。
输入:fileName保存的文件名吗,一个字符串
theta模型(n*1)的一个矩阵
'''
n=np.shape(theta)[0]
f=open(fileName,"w")
theta_arr=[]
for i in range(n):
theta_arr.append(str(theta[i,0]))
f.write("\t".join(theta_arr))
f.close()
x,y=dataLoad("trainData.txt")
print(x)
print(y)
theta=loopGradientDescent(0.01,y,x,1000)
print("最终模型")
print(theta)
saveModel("thetaModel",theta)
'''结果根据随机出来的样本数据不同而不同,贴上我的数据结果
第0次循环,误差率:-6.350950611452785
theta:
[[ 0.00848196]
[-3.10447915]
[-6.56845783]]
第100次循环,误差率:-0.0011321139500724707
theta:
[[ 1.20088305]
[ 3.78880061]
[-4.02240082]]
第200次循环,误差率:-0.0009462363867263863
theta:
[[ 1.23612421]
[ 3.91943948]
[-4.15899666]]
第300次循环,误差率:-0.0008139309045824767
theta:
[[ 1.2655657 ]
[ 4.02977837]
[-4.27434446]]
第400次循环,误差率:-0.0007148124403139913
theta:
[[ 1.29081686]
[ 4.12536189]
[-4.37424773]]
第500次循环,误差率:-0.000637704584139752
theta:
[[ 1.31290003]
[ 4.20972465]
[-4.46240652]]
第600次循环,误差率:-0.0005759586544488722
theta:
[[ 1.3325051 ]
[ 4.28526073]
[-4.54132712]]
第700次循环,误差率:-0.00052536761251323
theta:
[[ 1.35011952]
[ 4.35366801]
[-4.61278704]]
第800次循环,误差率:-0.000483137353995138
theta:
[[ 1.3661004 ]
[ 4.416195 ]
[-4.67809338]]
第900次循环,误差率:-0.0004473383117375322
theta:
[[ 1.38071708]
[ 4.47378699]
[-4.73823573]]
最终模型
[[ 1.3940483 ]
[ 4.52666202]
[-4.79344382]]
最后,本地会产生一个文件名为thetaModel的文件,其中保存的内容就是最终模型
'''
自此,逻辑回归算法,从读入数据到训练数据再到保存模型已经全部完成,之后只需要考虑使用该模型即可。
模型的使用
另建一个文件,用来使用训练出来的逻辑回归模型。
同目录下新建一个文件test.py,用来测试我们的模型
1.使用流程分析
首先对测试步骤进行分析
S
t
e
p
1
:
导
入
我
们
训
练
好
的
逻
辑
回
归
模
型
(
之
前
保
存
在
本
地
的
t
h
e
t
a
M
o
d
e
l
文
件
)
S
t
e
p
2
:
导
入
测
试
集
数
据
,
我
们
要
拟
合
的
数
据
S
t
e
p
3
:
按
照
回
归
模
型
对
数
据
进
行
预
测
S
t
e
p
4
:
保
存
最
终
预
测
结
果
存
入
本
地
\begin{aligned} & Step1:导入我们训练好的逻辑回归模型(之前保存在本地的thetaModel文件)\\ & Step2:导入测试集数据,我们要拟合的数据\\ & Step3:按照回归模型对数据进行预测\\ & Step4:保存最终预测结果存入本地\\ \end{aligned}
?Step1:导入我们训练好的逻辑回归模型(之前保存在本地的thetaModel文件)Step2:导入测试集数据,我们要拟合的数据Step3:按照回归模型对数据进行预测Step4:保存最终预测结果存入本地? 执行完毕后,我们就可以查看预测效果了
2.导入训练好的逻辑回归模型和要预测的数据
这一步只需要从文件中读入数据就好了。
这里可以先导入之前我们写好的训练模块,方便使用模块中的方法(预测函数,误差分析等)
先导入模型,再导入数据
import numpy as np
import LogisticRegressionTrain as LRT
def loadModel(fileName):
'''
loadModel()函数,根据文件名提取出模型theta,并返回一个n*1的矩阵
输入:fileName文件名
输出:一个(m*n)的矩阵,作为模型
一般来说,线性回归的theta模型是n*1的矩阵。
我们训练后保存的是一个1*n的列表,因此需要读出来后转置一下
'''
f=open(fileName)
theta=[]
for line in f.readlines():
tmpt=[]
lines=line.strip().split("\t")
for x in lines:
tmpt.append(float(x))
theta.append(tmpt)
f.close()
return (np.mat(theta)).T
def loadData(fileName,n):
'''
loadData()函数,通过文件名获取文件的数据,最后输出一个m*n的矩阵,作为样本
输入:fileName文件名
输出:一个(m*n)的矩阵,作为样本
'''
f=open(fileName)
x=[]
for line in f.readlines():
tmpx=[]
lines=line.strip().split("\t")
if len(lines) != (n-1):
continue
tmpx.append(1)
for i in lines:
tmpx.append(float(i))
x.append(tmpx)
f.close()
return np.mat(x)
if __name__=="__main__":
theta=loadModel("thetaModel")
print(theta)
n=np.shape(theta)[0]
print(loadData("testData",n))
'''模型使用前面保存的模型
[[ 1.3940483 ]
[ 4.52666202]
[-4.79344382]]
数据随机生成吧
'''
模型取出后,数据导入,接下来就是利用模型和数据进行预测了
3.预测结果
直接使用拟合函数h(x)计算即可,调用训练模块中的函数可以让我们省的重复写.
在上面的代码下面继续写
def predictY(x,theta):
'''
predictY()函数,计算获得预测值,保存在(m*1)的的矩阵中
输入:x是一个(m*n)的矩阵
theta是一个(n*1)的矩阵
输出:y判断矩阵
'''
y=LRT.forecastFunction(theta,x);
m=np.shape(y)[0]
for i in range(m):
if y[i,0]<0.5:
y[i,0]=0
else:
y[i,0]=1
return y
if __name__=="__main__":
theta=loadModel("thetaModel")
print(theta)
n=np.shape(theta)[0]
x=loadData("testData",n)
print(x)
y=predictY(x,theta)
print(y)
4.结果保存与分析
将预测结果保存至本地。
通过python的io流即可。
def saveResult(fileName,y):
'''
saveResult()函数,将结果y(m*1)的矩阵保留到文件fileName中
输入:fileName文件名
y(m*1)的矩阵
'''
f=open(fileName,"w")
m=np.shape(y)[0]
res=[]
for i in range(m):
res.append(str(y[i,0]))
f.write("\t".join(res))
f.close()
if __name__=="__main__":
theta=loadModel("thetaModel")
print(theta)
n=np.shape(theta)[0]
x=loadData("testData",n)
print(x)
y=predictY(x,theta)
print(y)
saveResult("predictY",y)
'''
可以在本地中查看到输出文件,该文件就是我们预测的训练集结果
'''
自此,逻辑回归的实现已经基本完成
其实后续还有很多可以操作的空间,比如之前学到的模型评估和进一步优化问题:模型的效果评判及模型的进一步优化问题_永远鲜红の幼月的博客
- 将数据集分成训练集,交叉验证集,测试数据集。
- 精确度和召回率的计算
- 正则化
- 多项式的选择
- …
但是这些全都写在这一篇文章里显得过为臃肿了。
我们本篇文章的目标就是将之前的逻辑回归理论转化为代码实现。
现在这个目标已经基本完成了,剩下的就等以后再进行把。
总结
我们总共写了4个python文件
- LogisticRegressionTrain.py文件,用于训练逻辑回归θ模型。其中包含了:
- forecastFunction()函数作为拟合函数
- errorRate()函数作为代价计算
- loopGradientDescent()函数作为循环梯度下降的实现函数
- dataLoad()和saveModel()函数作为读取样本文件和保存θ模型。
- 生成了文件thetaModel用来保存训练好的θ模型
- test.py文件,用于测试我们的逻辑回归θ模型,其中包含了:
- loadModel(),loadData()和saveResult()三个函数分别用于读取训练好的θ模型,读取要预测的数据,和保存的预测结果
- predictY()函数作为预测函数,其实就i是调用了LogisticRegressionTrain.py中的拟合函数
- 生成了文件predictY用于保存预测的结果
- randomData.py文件,用于随机生成我们的训练数据,其中包含了:
- randomTrainData()函数,用来随机生成数据
- saveTrainData()函数,用来将我们生成的数据保存在本地
- 生成了文件trainData用于保存训练集
- 生成了文件testData用于保存测试数据集
- getPicture.py文件,用于直观的(散点图)查看我们生成的数据,其中包含了:
- drawPicture()函数,用来将点集画图
- loadData()函数,用来加载点集
共计4个python文件,4个数据文件
完整代码
在gitee中:分类算法-逻辑回归 · 15538382334/机器学习入门实践
|