本作業是實現十個邏輯迴歸的分類器。
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