吴恩达机器学习第三章作业答案 part1:多类别逻辑回归

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.io import loadmat
from sklearn.metrics import classification_report
from scipy.optimize import minimize


def sigmoid(z):
    return 1 / (1 + np.exp(-z))


#  向量化计算代价函数
def cost(theta, X, y, learnRate):
    # print('here 1')
    theta = np.mat(theta)
    X = np.mat(X)
    y = np.mat(y)

    first = np.multiply(-y, np.log(sigmoid(X * theta.T)))

    # 当theta = np.ones((1, X.shape[1]))的时候,要采用下列代码,即加上1e-5
    # 这里是因为sigmoid(X*theta.T)得到的接近于1,则如果不带1e-5的话,log得到的结果接近于无穷,造成计算错误
    # second = np.multiply(1 - y, np.log(1 - sigmoid(X * theta.T) + 1e-5))

    second = np.multiply(1 - y, np.log(1 - sigmoid(X * theta.T)))
    reg = np.sum(np.power(theta[:, 1:], 2)) * (learnRate / (2 * X.shape[0]))
    return np.sum(first - second) / X.shape[0] + reg


#  向量化计算梯度
def gradient(theta, X, y, learnRate):
    # theta, X, y均是np.mat
    # print('here 2')
    # 这里theta必须强制转换为np.mat不管是行向量还是列向量,因为minimize里的x0是(n,)的ndarray行向量
    theta = np.mat(theta)
    X = np.mat(X)
    y = np.mat(y)

    g = (X.T * (sigmoid(X * theta.T) - y) + (learnRate * theta.T)) / X.shape[0]
    g[0, 0] = np.sum(sigmoid(X * theta.T) - y) / X.shape[0]
    # 返回的梯度向量是一个行向量或者列向量都可以正常运行
    # 猜测minimize函数内部对向量进行加减法的话是对应位置元素进行,所以不管是行向量还是列向量都是一样的
    return g.T


#  计算每一个类别的theta
def one_vs_all(X, y, num_labels, learnRate):
    all_theta = np.zeros((num_labels, X.shape[1]))
    # print(type(all_theta))
    for i in range(1, num_labels + 1):
        y_i = np.mat([1 if a == i else 0 for a in y]).T

        # theta如果采用全1的矩阵,可能会出现log计算得到无穷的情况,需要对cost函数进行一定的修正
        # 因此一般采用全零作为theta的初始值
        # theta = np.ones((1, X.shape[1]))
        theta = np.zeros((1, X.shape[1]))

        # 如果有X * theta行列数不对应的错误是因为minimize函数里的x0的类型是np.ndarray而且其shape是(n, ),
        # 所以在自己的cost和gradient函数中必须对theta进行矩阵的转换
        all_theta[i - 1] = minimize(fun=cost, x0=theta, args=(X, y_i, learnRate), method='TNC', jac=gradient).x
    return all_theta


def predict_all(X, all_theta):
    X = np.mat(X)
    all_theta = np.mat(all_theta)
    # 这里其实有没有激活函数sigmoid都是一样的,因为激活函数时单调增的,找最大值所在的序号其实有没有激活函数没区别
    predict = sigmoid(X * all_theta.T)
    # predict = X * all_theta.T
    h_argmax = np.argmax(predict, axis=1)
    return h_argmax + 1


data = loadmat('ex3data1.mat')

# the type of X and y is np.array
X = np.mat(np.insert(data['X'], 0, 1, axis=1))
y = np.mat(data['y'])
# print(y)
# print(X[0])
# 从X的行数中随机取得100个行号,进行后续展示, replace=False代表无放回选取
sample_index = np.random.choice(np.arange(X.shape[0]), 100, replace=False)
# 获得100个随机得到的样本的参数
sample = X[sample_index, :]
# print(sample.shape)

# 生成10*10的图片矩阵
# fig, ax = plt.subplots(nrows=10, ncols=10, sharex=True, sharey=True, figsize=(12,12))
# 用样本写入到图片矩阵里的每个小图片
# for i in range(10):
#     for j in range(10):
#         ax[i, j].matshow(sample[10*i+j].reshape(20, 20).T, cmap=plt.cm.binary)
#         plt.xticks(np.array([]))
#         plt.yticks(np.array([]))
# plt.show()
all_theta = one_vs_all(X, y, 10, 1)
predict = predict_all(X, all_theta)

print(classification_report(y, predict))


代码是参考黄博士的答案写的,还有两个自己遇到的问题也进行了查找整理,如下所示。


1. 进行矩阵乘法的两个矩阵行列数不对应

报错信息如下:

ValueError: shapes (5000,401) and (1,401) not aligned: 401 (dim 1) != 1 (dim 0)

这个是因为minimize函数里的x0的类型是np.ndarray且其shape是(n, )。而且其转置的shape也是(n, ),这就会导致X * theta.T得不到我们希望的结果,所以在自己的cost和gradient函数中对theta进行类型转换即可

theta = np.mat(theta)

2. 对theta进行初始化的时候采用np.ones()会产生溢出

报错信息如下:

RuntimeWarning: divide by zero encountered in log

这个产生的原因是在求解代价函数的时候:

second = np.multiply(1 - y, np.log(1 - sigmoid(X * theta.T)))

这里sigmoid(X * theta.T)会得到一个约等于1的值,导致产生np.log(0)的计算,这会产生一个无穷的值,即溢出。解决办法就是给他一个精度就可以了,类似于下面:

second = np.multiply(1 - y, np.log(1 - sigmoid(X * theta.T) + 1e-5 ))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值