import numpy as np
import matplotlib.pyplot as plt
import scipy.io as sio
from scipy.optimize import minimize #注意这一行的格式
'''函数部分'''
'''图像化数据'''
def plot_100_image(X):
sample_index = np.random.choice(len(X), 100) # 从样本集中随机选取100个打印
images = X[sample_index, :] # 选取该行,所有列(即对应一个样本)
print('image:',images.shape)
# 创建绘图实例
fig, ax = plt.subplots(ncols=10, nrows=10, figsize=(5, 5), # 10×10共100张图,总窗口大小为5×5
sharex=True, sharey=True) # 所有图像共享x,y轴属性
plt.xticks([]) # 隐藏x,y轴坐标刻度
plt.yticks([])
for r in range(10): # 行
for c in range(10): # 列
ax[r, c].imshow(images[10 * r + c].reshape(20, 20).T, cmap='gray_r') #images[10 * r + c]意思是image中的第10r+c行(shape是1*400)
plt.show()
'''激活函数'''
def sigmoid(z):
return 1 / (1 + np.exp(-z))
'''代价函数(带正则)'''
def costReg(theta,X,y,lbd):
X = np.matrix(X)
y = np.matrix(y)
theta = np.matrix(theta)
first = np.multiply(-y, np.log(sigmoid(X @ theta.T)))
second = np.multiply(1 - y, np.log(1 - sigmoid(X @ theta.T)))
reg = (lbd / (2 * len(X))) * np.sum(np.power(theta[:, 1:], 2)) #不惩罚θ0,所以从1开始
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)
# STEP2:将theta矩阵拉直(转换为一个向量)
# parameters =int(theta.ravel().shape[1])
# STEP3:计算预测的误差
error = sigmoid(X * theta.T) - y #5000*1
# print('shape_X:',X.shape) #5000*401,仅作查看,不要打开
# print('shape_theta:',theta.shape) #1*401,仅作查看,不要打开
# STEP4:根据上面的公式计算梯度
grad = ((error.T @ X) / len(X)) + ((learningRate / len(X)) * theta) #1*401
# STEP5:由于j=0时不需要正则化,所以这里重置一下
grad[0, 0] = X[:,0].T @ error / len(X) #1*401
return grad
'''one vs all'''
def one_vs_all(X, y, num_labels, learning_rate):
rows = X.shape[0] #rows=5000
params = X.shape[1] #params=400
all_theta = np.zeros((num_labels, params + 1)) #创建10*401的数组,params需要+1是因为在X里加了”x0=1“列,对应θ0列
X = np.insert(X, 0, values=np.ones(rows), axis=1) #np.insert(原始数组 可一可多,插入元素位置,插入内容,按行按列插入(0:行、1:列))
for i in range(1, num_labels + 1): #在标签1,2,3,4...10中
theta = np.zeros(params + 1) #1*401个0,即all_theta的第一行
y_i = np.array([1 if label == i else 0 for label in y]) #for label in range(y)
y_i = np.reshape(y_i, (rows, 1)) #reshape成5000*1的数组,注意y里内容的数量一直是没变的,还是那么多
fmin = minimize(fun=costReg, x0=theta, args=(X, y_i, lbd), method='TNC', jac=gradient)
'''
fun:该参数就是costFunction你要去最小化的损失函数,将costFunction的名字传给fun
x0: 初始化的theta,其shape必须为shape(n,),即一维数组,不能是矩阵。所以才在one_vs_all里将theta定义成数组,在costReg和gradient里在升成矩阵
method:该参数代表采用的方式,默认是BFGS, L-BFGS-B, SLSQP中的一种,可选TNC
jac:该参数就是计算梯度的函数,和fun参数类似,第一个必须为theta且其shape必须为(n,)即一维数组,最后返回的梯度也必须为一个一维数组。
options:用来控制最大的迭代次数,以字典的形式来进行设置,例如:options={‘maxiter’:400}
'''
all_theta[i - 1, :] = fmin.x #代价最小化后取得的θ,横着放一行
return all_theta
'''预测'''
def predict_all(X, Theta):
rows = X.shape[0] #5000
params = X.shape[1] #400
X = np.insert(X, 0, values=np.ones(rows), axis=1)
X = np.matrix(X)
Theta = np.matrix(Theta)
h = sigmoid(X * Theta.T) #h属于R5000*10,竖向5000分别是每一个样本,横向10是此样本可能是1~10的分别的可能性。此值在0-1之间,越接近1说明越可能是对应的值
# print(h)
h_argmax = np.argmax(h, axis=1) #此函数可以决定出每个样本最近接哪个标签
h_argmax = h_argmax + 1 #+1就是标签,因为从零开始
return h_argmax
'''准确度'''
def predict(y_predict):
y_predict = predict_all(data['X'], Theta)
correct = [1 if a == b else 0 for (a, b) in zip(y_predict, data['y'])]
accuracy = (sum(map(int, correct)) / float(len(correct)))
return print ('accuracy = {0}%'.format(accuracy * 100))
'''计算部分'''
'''数据导入'''
data = sio.loadmat('D:\新大陆\吴恩达机器学习\ex3\ex3data1')
# print(type(data)) #类型是字典
X = data['X']
y = data['y']
print(X)
print('y:',y.shape)
# print(type(X)) #类型是数组!!!
'''数据图像化'''
plot_100_image(X)
'''用one_vs_all求θ'''
lbd = 1
Theta = one_vs_all(X, y, 10, lbd)
print(Theta)
print(type(Theta))
print(Theta.shape)
'''预测一个值,自己写的数字9'''
# data = sio.loadmat('D:\旧盘\hello_world\机器学习\ex3\s9.mat')
# a = data['data']
# b = np.full(400,255,dtype=int).reshape(1,400)
# aa = a.reshape(1,400)-b
# print('this:', predict_all(aa, Theta))
# #给aa加一个因子的事在函数里,不要总想着在这里加
'''用原始数据集预测'''
y_predict = predict_all(X,Theta)
'''算准确度'''
accuracy = predict(y_predict)
数据图像化:
Theta:
[[-2.38239050e+00 0.00000000e+00 0.00000000e+00 ... 1.30444822e-03
-7.57439323e-10 0.00000000e+00]
[-3.18286756e+00 0.00000000e+00 0.00000000e+00 ... 4.46041027e-03
-5.08538480e-04 0.00000000e+00]
[-4.79502812e+00 0.00000000e+00 0.00000000e+00 ... -2.87356345e-05
-2.47803760e-07 0.00000000e+00]
...
[-7.98625741e+00 0.00000000e+00 0.00000000e+00 ... -8.94755730e-05
7.21694604e-06 0.00000000e+00]
[-4.57280311e+00 0.00000000e+00 0.00000000e+00 ... -1.33633860e-03
9.99296681e-05 0.00000000e+00]
[-5.39763997e+00 0.00000000e+00 0.00000000e+00 ... -1.17092659e-04
8.00188737e-06 0.00000000e+00]]
accuracy:94.46%
部分代码参考大佬:顾道长生',部分批注来源网络。感谢所有在机器学习路上的引路人。