本作业是实现十个逻辑回归的分类器。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.io import loadmat
mat数据格式是Matlab的数据存储的标准格式。在python中可以使用scipy.io中的函数loadmat()读取mat文件,函数savemat保存文件。
#加载数据
data = loadmat('ex3data1.mat')
data, data['X'].shape, data['y'].shape
({'__header__': b'MATLAB 5.0 MAT-file, Platform: GLNXA64, Created on: Sun Oct 16 13:09:09 2011',
'__version__': '1.0',
'__globals__': [],
'X': array([[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]]),
'y': array([[10],
[10],
[10],
...,
[ 9],
[ 9],
[ 9]], dtype=uint8)},
(5000, 400),
(5000, 1))
X表示五千个样本,一个400维。400维?:20*20的图像,排成一个行向量;
y表示从1到10的数字。
#sigmoid函数
def sigmoid(z):
return 1/(1+np.exp(-z))
y,np.log(sigmoid(X * theta.T))都是两个5000*1的矩阵
def cost(theta, X, y, learningRate):
#转换成矩阵
theta = np.matrix(theta)
X = np.matrix(X)
y = np.matrix(y)
#转换成numpy类型的矩阵
#np.multiply不是矩阵乘法,而是把这两个矩阵对应的位置直接相乘
#最后得到的还是一个5000*1的矩阵
first = np.multiply(-y, np.log(sigmoid(X * theta.T)))
second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T)))
#损失函数的正则化部分,第一位theta是偏置,我们加上的,所以这里不取
reg = (learningRate / (2 * len(X))) * np.sum(np.power(theta[:,1:theta.shape[1]], 2))
return np.sum(first - second) / len(X) + reg
向量化的梯度函数
def gradient(theta, X, y, learningRate):
theta = np.matrix(theta)
X = np.matrix(X)
y = np.matrix(y)
parameters = int(theta.ravel().shape[1])
error = sigmoid(X * theta.T) - y
grad = ((X.T * error) / len(X)).T + ((learningRate / len(X)) * theta)
#theta的第一维不需要正则化,所以重置
grad[0, 0] = np.sum(np.multiply(error, X[:,0])) / len(X)
#把10*400压缩成40000
return np.array(grad).ravel()
all_theta在循环中每次处理一行,就是每次处理一个分类器,得到一个最优的theta
from scipy.optimize import minimize
def one_vs_all(X, y, num_labels, learning_rate):
#10个lable, 1到10
rows = X.shape[0] #行数,样本个数
params = X.shape[1] #列数,一个图片的维度
# k X (n + 1) array for the parameters of each of the k classifiers
all_theta = np.zeros((num_labels, params + 1))
#行。列:10, 401, 1是偏置
# insert a column of ones at the beginning for the intercept term
X = np.insert(X, 0, values=np.ones(rows), axis=1)
#插一列,五千个样本 。np.ones值为1.在0的维度,按列的方向
# labels are 1-indexed instead of 0-indexed
for i in range(1, num_labels + 1):
theta = np.zeros(params + 1) #401维的向量
y_i = np.array([1 if label == i else 0 for label in y])
#在构建第一个分类器,当标签为1的就是1,别的都置为0
y_i = np.reshape(y_i, (rows, 1)) #把他reshape成一个列向量
# minimize the objective function
fmin = minimize(fun=cost, x0=theta, args=(X, y_i, learning_rate), method='TNC', jac=gradient)
all_theta[i-1,:] = fmin.x
#i=1时就是第0行, 遍历了每一行每一个逻辑回归的分类器
return all_theta
得到我们想要的参数
all_theta = one_vs_all(data['X'], data['y'], 10, 1)
type(all_theta),all_theta.shape
(numpy.ndarray, (10, 401))
用训练好的模型进行预测。
def predict_all(X, all_theta):
rows = X.shape[0]
params = X.shape[1]
num_labels = all_theta.shape[0]
X = np.insert(X, 0, values=np.ones(rows), axis=1)
X = np.matrix(X)
all_theta = np.matrix(all_theta)
# 计算每个样本的分类
h = sigmoid(X * all_theta.T)
#变成了一个5000*10的矩阵,一行一个矩阵
#这一行里,第一列是分成1的概率,最大的就是应该取哪个lable
h_argmax = np.argmax(h, axis=1)
#沿着行找最大值, 5000*1,就是当前行最大概率的是哪个lable
h_argmax = h_argmax + 1
#第0列是lable1,so +1
return h_argmax
输入数据和模型,预测,计算精确度
y_pred = predict_all(data['X'], all_theta)
correct = [1 if a == b else 0 for (a, b) in zip(y_pred, data['y'])]
accuracy = (sum(correct) / float(len(correct)))
accuracy
0.9446