利用sklern.datasets已有的load_iris()导入鸢尾花数据集。
这个数据集一共有150个样本,包含三种类型的花,各50个样本。
每个样本有四个属性值,一个标签值,三种类型的标签分别用0、1、2表示。因为本次实验我们只讨论二分类问题,所以只需要保留两类花的样本。为了方便,我直接截取前100个样本,也就是选取前两类花。
from sklearn.datasets import load_iris;
iris=load_iris();
attributes=iris.data[0:100];#导入数据集的属性列表,前100项,两类花
#print(attributes);
target=iris.target[0:100];#导入数据集的标签列表,前100项,两类花
#print(target);
1、利用sklearn.model_selection的train_test_split()可以进行数据集的划分。
2、train_test_split()需要四个参数,通过该函数可以返回划分好的训练集和测试集的属性数组和标签数组。
train_test_split(attributes,target,test_size=0.5,random_state=1)
attributes:数据集的属性数组
target:数据集的标签数组
test_size:测试集的规模。0.5表示测试集在数据集里占50%
random_state:取1表示在其他参数赋值相同的情况下,调用该函数划分数据集的得到的是相同的训练集和测试集,如果取的是0或者不填,则表示即使其他参数赋值相同,调用该函数划分出来的训练集和测试集是不同的。
对数几率回归模型的关键点在于要尽可能地求出最优的向量w和数值b。
这个尽可能最优指的是训练出来的模型可以让样本属于其真实标记的概率尽可能地最大。
教材上式子3.25是利用“极大似然法”估计这个尽可能最优的向量w,和数值b。
所以,最大化式子3.25即是我们的目标。
教材指的是周志华的西瓜书。具体公式大家可以自行翻阅。
教材上通过推导得到,最大化式子3.25即是最小化3.27。
于是通过梯度下降算法,可以迭代求得较优的向量w:
W=W-α*(式子3.27的一阶导)
其中α是精度,指的是真实权重和计算得到的w的偏差,一般人为指定,在本次实现过程中,我将α指定为0.0001。
def iterater(data,label):#梯度下降法求出最优的w向量
losslist=[];
dataMatrix_tmp=numpy.matrix(data);
#print(dataMatrix_tmp);
n=dataMatrix_tmp.shape[0];
a = numpy.ones(n).transpose();
dataMatrix=numpy.c_[a,dataMatrix_tmp];#给数据集属性矩阵添加一列全1,为了直接得出b值
labelMatrix=numpy.matrix(label).transpose();
alpha=0.00001;#精度,自己凭经验选择
maxCycles=2000;#迭代次数
w = numpy.ones((5,1));#初始化w向量,第一个元素为b值
p1 = sigmoid(numpy.matmul(dataMatrix, w));
for k in range(maxCycles):
error=(labelMatrix-p1);
w=w+numpy.dot(alpha,numpy.matmul(dataMatrix.transpose(),error));#迭代计算w向量
p1 = sigmoid(numpy.matmul(dataMatrix, w));
losslist.append(loss(label, p1));
#print(losslist);
#损失函数曲线图
my_x_ticks=numpy.arange(1,maxCycles+1,1);#横坐标的刻度
plt.figure("loss fuction");
ax=plt.gca();
ax.set_title("loss fuction");
ax.set_xlabel("times");
ax.set_ylabel("loss");
ax.plot(my_x_ticks,losslist,color='b',linewidth=1,alpha=0.6);
plt.show();
return w;
初始化W向量元素为全1。
注:在处理数据的时候将数值b加入到向量w中,
并且在训练集的属性矩阵添加一列全1。这样就不需要再额外去求数值b。
无论是计算p(y=1|x)时还是计算预测的y值时,sigmoid()函数需要传入的参数都是的z值。
因为花的属性是四维的,所以向量W有四个元素。
为了更简单地表示z值以及计算出b值,在向量W中增加一个w0元素,表示b值,同时也要在数据集的属性矩阵第一列增加一列,数值全为1。
即z=w0+w1x1+w2x2+w3x3+w4x4=X*W
n = dataMatrix_tmp.shape[0];
a = numpy.ones(n).transpose();
dataMatrix = numpy.c_[a, dataMatrix_tmp];#在属性矩阵第一列添加一列全1,为了便于与w向量相乘
y = sigmoid(numpy.matmul(dataMatrix, w)).tolist();#由学习到的w向量得出预测的y值
加工X属性矩阵这个操作是在训练模型的iterater()函数和计算正确率的函数accuracy()中进行的,前者对训练集的属性矩阵添加全1列,后者对测试集的属性矩阵添加全1列。
随着迭代次数增加,得到的向量W也在不断变化。
为了知晓迭代次数对模型的影响,引入了损失函数来描述这一过程。
刚开始很容易误以为对数几率回归模型的损失函数是平方损失,其实不然。
因为逻辑回归并没有求似然函数的极值,而是把极大化当作一种思想,
推导出最小化负的似然函数。从损失函数的视角来看,这是一种log损失函数。
形式:J=-( )/m
(p1=p(y=1|x))
当真实标签yi=1时,Ji=-(log p1)/m
当真实标签yi=0时,Ji=-(log (1-p1))/m
m为训练样本标签数量。
def loss(label,p):#损失函数
a=0;
for k in range(0,len(label)):
if label[k]==1:
a=a+numpy.log(numpy.array(p)[k]);
else:
a=a+numpy.log(1-numpy.array(p)[k]);
a=-a/len(label);
return float(a);
输出的W向量的值及正确率:
2.将数据集的 70%作为训练集,30%作为测试集,检验模型在测试集上的分类正确率。
向量W及其正确率:
3.将数据集的 90%作为训练集,10%作为测试集,检验模型在测试集上的分类正确率。
W向量及其正确率:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import numpy;
import matplotlib.pyplot as plt;
from sklearn.datasets import load_iris;
iris=load_iris();
attributes=iris.data[0:100];#导入数据集的属性列表,前100项,两类花
#print(attributes);
target=iris.target[0:100];#导入数据集的标签列表,前100项,两类花
#print(target);
def sigmoid(x):#对数几率函数(替代函数)
return 1. / (1+numpy.exp(-x));
def loss(label,p):#损失函数
a=0;
for k in range(0,len(label)):
if label[k]==1:
a=a+numpy.log(numpy.array(p)[k]);
else:
a=a+numpy.log(1-numpy.array(p)[k]);
a=-a/len(label);
return float(a);
def iterater(data,label):#梯度下降法求出最优的w向量
losslist=[];
dataMatrix_tmp=numpy.matrix(data);
#print(dataMatrix_tmp);
n=dataMatrix_tmp.shape[0];
a = numpy.ones(n).transpose();
dataMatrix=numpy.c_[a,dataMatrix_tmp];#给数据集属性矩阵添加一列全1,为了直接得出b值
labelMatrix=numpy.matrix(label).transpose();
alpha=0.00001;#精度,自己凭经验选择
maxCycles=2000;#迭代次数
w = numpy.ones((5,1));#初始化w向量,第一个元素为b值
p1 = sigmoid(numpy.matmul(dataMatrix, w));
for k in range(maxCycles):
error=(labelMatrix-p1);
w=w+numpy.dot(alpha,numpy.matmul(dataMatrix.transpose(),error));#迭代计算w向量
p1 = sigmoid(numpy.matmul(dataMatrix, w));
losslist.append(loss(label, p1));
#print(losslist);
#损失函数曲线图
my_x_ticks=numpy.arange(1,maxCycles+1,1);#横坐标的刻度
plt.figure("loss fuction");
ax=plt.gca();
ax.set_title("loss fuction");
ax.set_xlabel("times");
ax.set_ylabel("loss");
ax.plot(my_x_ticks,losslist,color='b',linewidth=1,alpha=0.6);
plt.show();
return w;
def accuracy(w,datatest,labeltest):#测试模型的正确率
count=0;
dataMatrix_tmp = numpy.matrix(datatest);
# print(dataMatrix_tmp);
n = dataMatrix_tmp.shape[0];
a = numpy.ones(n).transpose();
dataMatrix = numpy.c_[a, dataMatrix_tmp];#在属性矩阵第一列添加一列全1,为了便于与w向量相乘
y = sigmoid(numpy.matmul(dataMatrix, w)).tolist();#由学习到的w向量得出预测的y值
# print(y[1][0]);
for k in range(0, len(y)):
#因为通过sigmoid()得到的y值只是逼近0或1,所以这里需要对得到数据进行一次处理,
#将逼近1的值用1替换,逼近0的值用0替换,如果是0.5则0,1任意选择替换
if y[k][0] > 0.5:
y[k][0] = 1;
elif y[k][0] < 0.5:
y[k][0] = 0;
else:
y[k][0] = numpy.random.randint(0, 2);
#print(y);
for i in range(0,len(labeltest)):#将真实标签与模型得到的标签比较,计算正确率
if labeltest[i]==y[i]:
count=count+1;
print("accuracy:",count/len(labeltest));
from sklearn.model_selection import train_test_split;
print("~~~~~~~50%train,50%test");
x1_train,x1_test,y1_train,y1_test=train_test_split(attributes,target,test_size=0.5,random_state=1);#用python的第三方库sklearn来随机划分训练集、测试集
weights1=iterater(x1_train,y1_train);
print(weights1);
accuracy(weights1,x1_test,y1_test);
print("~~~~~~~70%train,30%test");
x2_train,x2_test,y2_train,y2_test=train_test_split(attributes,target,test_size=0.3,random_state=1);
weights2=iterater(x2_train,y2_train);
print(weights2);
accuracy(weights2,x2_test,y2_test);
print("~~~~~~~90%train,10%test");
x3_train,x3_test,y3_train,y3_test=train_test_split(attributes,target,test_size=0.1,random_state=1);
weights3=iterater(x3_train,y3_train);
print(weights3);
accuracy(weights3,x3_test,y3_test);