小白入门 吴恩达机器学习作业(三) python实现 详细解析

本作业是实现十个逻辑回归的分类器。

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章