1

Я пытаюсь реализовать многоклассовый логистический регрессионный классификатор, который различает k разных классов.деление python на ноль встречается в лог-логистической регрессии

Это мой код.

import numpy as np 
from scipy.special import expit 


def cost(X,y,theta,regTerm): 
    (m,n) = X.shape 
    J = (np.dot(-(y.T),np.log(expit(np.dot(X,theta))))-np.dot((np.ones((m,1))-y).T,np.log(np.ones((m,1)) - (expit(np.dot(X,theta))).reshape((m,1)))))/m + (regTerm/(2 * m)) * np.linalg.norm(theta[1:]) 
    return J 

def gradient(X,y,theta,regTerm): 
    (m,n) = X.shape 
    grad = np.dot(((expit(np.dot(X,theta))).reshape(m,1) - y).T,X)/m + (np.concatenate(([0],theta[1:].T),axis=0)).reshape(1,n) 
    return np.asarray(grad) 

def train(X,y,regTerm,learnRate,epsilon,k): 
    (m,n) = X.shape 
    theta = np.zeros((k,n)) 
    for i in range(0,k): 
     previousCost = 0; 
     currentCost = cost(X,y,theta[i,:],regTerm) 
     while(np.abs(currentCost-previousCost) > epsilon): 
      print(theta[i,:]) 
      theta[i,:] = theta[i,:] - learnRate*gradient(X,y,theta[i,:],regTerm) 
      print(theta[i,:]) 
      previousCost = currentCost 
      currentCost = cost(X,y,theta[i,:],regTerm) 
    return theta 

trX = np.load('trX.npy') 
trY = np.load('trY.npy') 
theta = train(trX,trY,2,0.1,0.1,4) 

можно проверить, что стоимость и градиент возврата значений, которые находятся в правильном измерении (стоимость возвращает скаляр, и градиент возвращает 1 по п вектора-строки), но я получаю ошибку

RuntimeWarning: divide by zero encountered in log 
    J = (np.dot(-(y.T),np.log(expit(np.dot(X,theta))))-np.dot((np.ones((m,1))-y).T,np.log(np.ones((m,1)) - (expit(np.dot(X,theta))).reshape((m,1)))))/m + (regTerm/(2 * m)) * np.linalg.norm(theta[1:]) 

Почему это происходит и как я могу избежать этого?

+0

Глядя на вашу формулу, я бы предпочел бы, что 'm' равно 0 so' (regTerm/(2 * m)) ', а'/m' станет делением на 0. – Munir

+0

m не равно 0, это 4104 в моем случае. –

ответ

3

Вы можете очистить формулу надлежащего использования вещания, оператор * для точечных произведений векторов, и оператора @ для умножения матриц — и ломко, как предложено в комментариях.

Вот ваша функция стоимость:

def cost(X, y, theta, regTerm): 
    m = X.shape[0] # or y.shape, or even p.shape after the next line, number of training set 
    p = expit(X @ theta) 
    log_loss = -np.average(y*np.log(p) + (1-y)*np.log(1-p)) 
    J = log_loss + regTerm * np.linalg.norm(theta[1:])/(2*m) 
    return J 

Вы можете очистить вашу функцию градиента по той же схеме.

Кстати, вы уверены, что хотите np.linalg.norm(theta[1:]). Если вы пытаетесь сделать L2-регуляризацию, этот термин должен быть np.linalg.norm(theta[1:]) ** 2.

0

Я предполагаю, что ваши данные имеют отрицательные значения. Вы не можете зарегистрировать отрицательный результат.

import numpy as np 
np.log(2) 
> 0.69314718055994529 
np.log(-2) 
> nan 

Существует множество способов преобразования данных, которые должны помочь, если это так.

+0

Нет. Я просто проверил. Никаких отрицательных значений в данных нет. –

+0

В этом случае вы делаете и вычитание, и разделение внутри той огромной линии, в которой возникает ошибка, поэтому я буду смотреть дальше. Также было бы гораздо более понятным разделить эту линию на несколько шагов, которые я думаю. Это также облегчило бы отладку. – Jeff

+1

Например, вычислите знаменатель отдельно и назначьте его переменной, а затем разделите на эту строку переменной. Но перед этим поставьте некоторый промежуточный вывод, который печатает знаменатель для вас, так что вы можете увидеть, действительно ли он равен нулю. Если это так, вы можете разделить его больше, чтобы определить, как он туда попадает. – Jeff

Смежные вопросы