《机器学习》西瓜书课后习题3.3——python实现对率回归(梯度下降法)
《机器学习》西瓜书P69:
3.3 编程实现对率回归,并给出西瓜数据集3.0a上的结果
首先我们回归一下什么的是对率回归?
对数几率回归模型,是一个典型的二分类任务学习模型
书接上回,我们可以对一个数据集得到它的回归方程
我们是这样去解读回归方程的:在相关属性下对样例的某一特征的度量
我们根据回归方程得到的特征度量是一个连续值,我们可以根据这个度量值进行分类
例如:大学的绩点计算,当我们的绩点大于等于2.0才能拿到学位,否则拿不到学位,我们可以认为当度量值达到多少时将样例视为一类,而没达到的样例分为另一类。
但是问题就在于:
- 训练数据集中需要预测的特征是分类的标签(0, 1),而不是其度量值
- 若训练集给出了需要预测的特征的分类标签(0, 1)和度量值,但是我们无法知道两个分类的度量值的界限
根据我们的需求,提出以下假设:
我们的线性方程为:
设有一个函数g(x):
将我们的线性方程和这个g(x)合并可得
这样我们就可利用这个函数模型来对数据分类了。使用最多的就是对数几率函数,其标准形式为
我们将我们的线性回归方程与对数几率函数合并,得到我们的新模型如下:
我们依然使用差值来度量它的预测准确度,则我们的优化目标函数(代价函数)如下:
我们可以使用梯度下降算法来计算上述优化目标。
梯度下降法公式如下(梯度下降法的证明推导过程见https://blog.csdn.net/qq_41398808/article/details/90442685):
我们的优化目标函数的一阶导数为(计算过程参考:https://www.cnblogs.com/crackpotisback/p/5545708.html):
所以我们根据该公式对参数进行迭代,就可以得到我们想要的结果。
【数据集】
西瓜数据集3.0a.csv:
编号,密度,含糖率,好瓜
1,0.697,0.46,是
2,0.774,0.376,是
3,0.634,0.264,是
4,0.608,0.318,是
5,0.556,0.215,是
6,0.403,0.237,是
7,0.481,0.149,是
8,0.437,0.211,是
9,0.666,0.091,否
10,0.243,0.267,否
11,0.245,0.057,否
12,0.343,0.099,否
13,0.639,0.161,否
14,0.657,0.198,否
15,0.36,0.37,否
16,0.593,0.042,否
17,0.719,0.103,否
【数据读取和预处理函数——loadDataset】
首先我们需要读取数据并进行预处理,将属性矩阵和标记矩阵分开存储,同时在属性矩阵的最后增加全为1的一列。我在这里直接将最后一列全替换为1,并根据标记存放到label数组里面。
#读取西瓜数据集中的数据并进行预处理
def loadDataset(filename):
dataset=[]
labelset=[]
with open(filename,'r',encoding='utf-8') as csvfile:
csv_reader=csv.reader(csvfile)
header=next(csv_reader)
for row in csv_reader:
if row[3] == '是':
labelset.append(1)
elif row[3] == '否':
labelset.append(0)
row[3]=1
dataset.append(row)
data=[[float(x) for x in row]for row in dataset]
return dataset,labelset
【对数几率函数——sigmoid】
接下来我们定义对数几率函数sigmoid
#定义sigmoid函数
def sigmoid(z):
return 1.0 / (1 + np.exp(-z))
【迭代求w函数——training】
下面我们需要采用迭代的方式求w,根据上面的公式我们进行合并化简得到最终的梯度下降公式:
其中n为步长,最终我们得到的w是一个数组,每一个元素表示的是该属性前面的系数w,为了控制迭代次数,我们将”准确率高于90%“作为终止的条件;
#迭代求w
def training(dataset,labelset):
# np.dot(a,b) a和b矩阵点乘
# np.transpose() 转置
# np.ones((m,n)) 创建一个m行n列的多维数组
data=np.mat(dataset).astype(float)
label=np.mat(labelset).transpose()
w = np.ones((len(dataset[0]),1))
#步长
n=0.0001
# 每次迭代计算一次正确率(在测试集上的正确率)
# 达到0.90的正确率,停止迭代
rightrate=0.0
while rightrate<0.90:
c=sigmoid(np.dot(data,w))
b=c-label
change = np.dot(np.transpose(data),b)
w=w-change*n
#预测,更新准确率
rightrate = test(dataset,labelset,w)
return w
【计算准确率函数——test】
因此为了计算准确率我们定义了一个函数test,作用是将每次迭代取得的w作为参数代入公式和
并判断y是否大于或小于0.5,得到预测值;并与实际标记值是否相等,若相等则判断正确的个数+1,最终返回准确率。
def test(dataset,labelset,w):
data=np.mat(dataset).astype(float)
y=sigmoid(np.dot(data,w))
b,c=np.shape(y)#功能是查看矩阵或者数组的维数。
rightcount=0
for i in range(b):
flag=-1
if y[i,0]>0.5:
flag=1
elif y[i,0]<0.5:
flag=0
if labelset[i] == flag:
rightcount+=1
rightrate=rightcount/len(dataset)
return rightrate
【完整源代码】
#读取本地数据
import csv
import numpy as np
#读取西瓜数据集中的数据并进行预处理
def loadDataset(filename):
dataset=[]
labelset=[]
with open(filename,'r',encoding='utf-8') as csvfile:
csv_reader=csv.reader(csvfile)
header=next(csv_reader)
for row in csv_reader:
if row[3] == '是':
labelset.append(1)
elif row[3] == '否':
labelset.append(0)
row[3]=1
dataset.append(row)
data=[[float(x) for x in row]for row in dataset]
return dataset,labelset
#定义sigmoid函数
def sigmoid(z):
return 1.0 / (1 + np.exp(-z))
def test(dataset,labelset,w):
data=np.mat(dataset).astype(float)
y=sigmoid(np.dot(data,w))
b,c=np.shape(y)#功能是查看矩阵或者数组的维数。
rightcount=0
for i in range(b):
flag=-1
if y[i,0]>0.5:
flag=1
elif y[i,0]<0.5:
flag=0
if labelset[i] == flag:
rightcount+=1
rightrate=rightcount/len(dataset)
return rightrate
#迭代求w
def training(dataset,labelset):
# np.dot(a,b) a和b矩阵点乘
# np.transpose() 转置
# np.ones((m,n)) 创建一个m行n列的多维数组
data=np.mat(dataset).astype(float)
label=np.mat(labelset).transpose()
w = np.ones((len(dataset[0]),1))
#步长
n=0.0001
# 每次迭代计算一次正确率(在测试集上的正确率)
# 达到0.90的正确率,停止迭代
rightrate=0.0
while rightrate<0.90:
c=sigmoid(np.dot(data,w))
b=c-label
change = np.dot(np.transpose(data),b)
w=w-change*n
#预测,更新准确率
rightrate = test(dataset,labelset,w)
return w
dataset=[]
labelset=[]
filename = '西瓜数据集3.0a.csv'
dataset,labelset=loadDataset(filename)
w=training(dataset,labelset)
print("若使得准确率大于90%,则此时的w为:\n",w)
print("正确率:%f"%(test(dataset,labelset,w)*100)+"%")
【运算结果】
所以最终得到的西瓜模型为:
y
=
−
0.14505012
∗
编
号
+
0.95884929
∗
密
度
+
0.98789039
∗
含
糖
率
+
0.91625094
y=-0.14505012*编号+0.95884929*密度+0.98789039*含糖率+0.91625094
y=−0.14505012∗编号+0.95884929∗密度+0.98789039∗含糖率+0.91625094
参考博文:
机器学习 对数几率回归模型(Python实现)
上述解题过程如有错误 还请及时留言联系