python-3.x - 如何在逻辑回归的 numpy 实现中避免 NaN?
问题描述
编辑:我已经取得了重大进展。我当前的问题是在我最后一次编辑之后写的,可以在没有上下文的情况下回答。
我目前在 Coursera 上关注 Andrew Ng 的机器学习课程,今天尝试实现逻辑回归。
符号:
X
是一个(m x n)
以输入变量向量为行的矩阵(变量的m
训练样本,n-1
第一列的条目在任何地方都等于 1 以表示一个常数)。y
是预期输出样本的对应向量(m
条目等于0
或的列向量1
)theta
是模型系数的向量(带有n
条目的行向量)
对于输入行向量x
,模型将预测sigmoid(x * theta.T)
积极结果的概率。
这是我的 Python3/numpy 实现:
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
vec_sigmoid = np.vectorize(sigmoid)
def logistic_cost(X, y, theta):
summands = np.multiply(y, np.log(vec_sigmoid(X*theta.T))) + np.multiply(1 - y, np.log(1 - vec_sigmoid(X*theta.T)))
return - np.sum(summands) / len(y)
def gradient_descent(X, y, learning_rate, num_iterations):
num_parameters = X.shape[1] # dim theta
theta = np.matrix([0.0 for i in range(num_parameters)]) # init theta
cost = [0.0 for i in range(num_iterations)]
for it in range(num_iterations):
error = np.repeat(vec_sigmoid(X * theta.T) - y, num_parameters, axis=1)
error_derivative = np.sum(np.multiply(error, X), axis=0)
theta = theta - (learning_rate / len(y)) * error_derivative
cost[it] = logistic_cost(X, y, theta)
return theta, cost
这个实现似乎工作正常,但我在计算后勤成本时遇到了问题。在某些时候,梯度下降算法收敛到一个非常好的拟合theta
,并发生以下情况:
对于某些X_i
具有预期结果的输入行,1
X * theta.T
将变为正数并具有良好的边距(例如23.207
)。这将导致sigmoid(X_i * theta)
变得精确 1.0000
(我认为这是因为失去了精度)。这是一个很好的预测(因为预期结果等于1
),但这会破坏后勤成本的计算,因为np.log(1 - vec_sigmoid(X*theta.T))
将评估为NaN
。这应该不是问题,因为该项与 相乘1 - y = 0
,但是一旦出现 的值NaN
,整个计算就会中断(0 * NaN = NaN
)。
我应该如何在矢量化实现中处理这个问题,因为是在(不仅是 where )np.multiply(1 - y, np.log(1 - vec_sigmoid(X*theta.T)))
的每一行中计算的?X
y = 0
示例输入:
X = np.matrix([[1. , 0. , 0. ],
[1. , 1. , 0. ],
[1. , 0. , 1. ],
[1. , 0.5, 0.3],
[1. , 1. , 0.2]])
y = np.matrix([[0],
[1],
[1],
[0],
[1]])
然后(是的,在这种情况下我们可以设置这么theta, _ = gradient_descent(X, y, 10000, 10000)
大的学习率)将设置为:theta
theta = np.matrix([[-3000.04008972, 3499.97995514, 4099.98797308]])
这将导致vec_sigmoid(X * theta.T)
非常好的预测:
np.matrix([[0.00000000e+00], # 0
[1.00000000e+00], # 1
[1.00000000e+00], # 1
[1.95334953e-09], # nearly zero
[1.00000000e+00]]) # 1
但logistic_cost(X, y, theta)
评估为NaN
.
编辑:
我想出了以下解决方案。我只是用以下功能替换了该logistic_cost
功能:
def new_logistic_cost(X, y, theta):
term1 = vec_sigmoid(X*theta.T)
term1[y == 0] = 1
term2 = 1 - vec_sigmoid(X*theta.T)
term2[y == 1] = 1
summands = np.multiply(y, np.log(term1)) + np.multiply(1 - y, np.log(term2))
return - np.sum(summands) / len(y)
通过使用掩码,我只是log(1)
在结果将乘以零的地方进行计算。现在log(0)
只会在梯度下降的错误实现中发生。
开放式问题:我怎样才能使这个解决方案更干净?是否有可能以更清洁的方式达到类似的效果?
解决方案
推荐阅读
- amazon-web-services - AWS - 在 SNS 订阅或 Lambda 函数上设置死信队列有什么区别?
- javascript - Bootstrap 3 折叠块 - 显示方向
- javascript - 为什么 GSAP 在连续快速点击时冻结动画?
- coq - coq中的反转策略
- ios - 登录后如何存储用户数据以在整个应用程序中使用?
- ansible - 使用自定义消息结束 playbook 的执行
- python-3.x - 如何使用来自指定列索引的值将列附加到数据框
- gensim - gensim vocab index 是对应的 1-hot-vector 中的索引吗?
- python - Pandas 如何对整个数据框进行通配符搜索?
- c# - 设置 NetTcpBinding