Питон Логистическая регрессия / Гессиан. Получение ошибки деления на ноль и ошибки особой матрицы - PullRequest
0 голосов
/ 26 октября 2019

код:

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

def cost(x,y,th):
    pro = sigmoid(np.dot(x,th))
    result = sum(-y * np.log(pro) - (1-y) * np.log(1-pro))   
    result = result/len(x) #len: number of feature rows
    return result

def gradient(x,y,th):
    xTrans = x.transpose()                                      
    sig = sigmoid(np.dot(x,th))                              
    grad = np.dot(xTrans, ( sig - y ))                          
    grad = grad / len(x) #len: number of feature rows  
    return grad
def hessian(x,y,th):
    xTrans = x.transpose()                                      
    sig = sigmoid(np.dot(x,th))                              
    result = (1.0/len(x) * np.dot(xTrans, x) * np.diag(sig) * np.diag(1 - sig) )   
    return result
def updateTh(x,y,th):
    hessianInv = np.linalg.inv(hessian(x,y,th))                         
    grad = gradient(x,y,th)                                  
    th = th - np.dot(hessianInv, grad)                     
    return th

m = 80 #number of x rows
x = np.ones([m,3])
y = np.empty([m,1], dtype = int)
th = np.zeros([3,1])
hessianResult = np.identity(3) #identity 3x3


with open('exam.csv','r') as csvfile:
            i = 0
            reader = csv.reader(csvfile)
            next(reader) #skip header            
            for line in reader:
                x[i][1] = line[0]
                x[i][2] = line[1]
                y[i][0] = line[2]
                i+=1

#m = x.shape[0] #number of x rows
for i in range(10):
    costResult = cost(x,y,th)
    hessianResult = hessian(x,y,th)
    grad = gradient(x,y,th)
    th = updateTh(x,y,th)  

Если я повторяю цикл более 28 раз, я получаю проблему деления на 0 с частью суммы моей функции стоимости, а также получаю сообщение об ошибке, говорящее о том, что матрица не можетбыть обратным, потому что это единственное число. Не уверен, что не так, следуя точному алгоритму, данному моим профессором. Набор данных представляет собой список из 80 записей о студентах, с двумя баллами по экзаменам для каждой записи и двоичным числом 1 или 0 в зависимости от того, был ли студент принят в колледж.

Ответы [ 2 ]

0 голосов
/ 26 октября 2019

Использовал это как пример данных для .csv (80 записей, не включая заголовок):

Grade 1,Grade 2,Admit
83,95,1
87,93,1
92,91,1
94,88,0
81,97,0
88.3,92.5,1
88.6,92.4,0
88.9,92.3,0
89.2,92.2,0
89.5,92.1,0
89.8,92,1
90.1,91.9,1
90.4,91.8,1
90.7,91.7,1
91,91.6,0
91.3,91.5,0
91.6,91.4,1
91.9,91.3,0
92.2,91.2,0
92.5,91.1,0
92.8,91,0
93.1,90.9,1
93.4,90.8,1
93.7,90.7,1
94,90.6,0
94.3,90.5,0
94.6,90.4,1
94.9,90.3,0
95.2,90.2,0
95.5,90.1,0
95.8,90,0
96.1,89.9,1
96.4,89.8,1
96.7,89.7,0
97,89.6,0
97.3,89.5,0
97.6,89.4,1
97.9,89.3,1
98.2,89.2,0
98.5,89.1,0
98.8,89,0
99.1,88.9,1
99.4,88.8,1
99.7,88.7,0
100,88.6,0
100.3,88.5,1
100.6,88.4,1
100.9,88.3,0
101.2,88.2,0
101.5,88.1,0
101.8,88,1
102.1,87.9,1
102.4,87.8,0
102.7,87.7,0
103,87.6,0
103.3,87.5,1
103.6,87.4,1
103.9,87.3,0
104.2,87.2,0
104.5,87.1,0
104.8,87,1
105.1,86.9,1
105.4,86.8,0
105.7,86.7,0
106,86.6,1
106.3,86.5,1
106.6,86.4,0
106.9,86.3,0
107.2,86.2,0
107.5,86.1,1
107.8,86,1
108.1,85.9,0
108.4,85.8,0
108.7,85.7,0
109,85.6,1
109.3,85.5,1
109.6,85.4,0
109.9,85.3,0
110.2,85.2,0
110.5,85.1,1

Редактировал ваш скрипт только для добавления необходимых импортов и вывода некоторых выводов:

import numpy as np
import csv

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

def cost(x,y,th):
    pro = sigmoid(np.dot(x,th))
    result = sum(-y * np.log(pro) - (1-y) * np.log(1-pro))   
    result = result/len(x) #len: number of feature rows
    return result

def gradient(x,y,th):
    xTrans = x.transpose()                                      
    sig = sigmoid(np.dot(x,th))                              
    grad = np.dot(xTrans, ( sig - y ))                          
    grad = grad / len(x) #len: number of feature rows  
    return grad
def hessian(x,y,th):
    xTrans = x.transpose()                                      
    sig = sigmoid(np.dot(x,th))                              
    result = (1.0/len(x) * np.dot(xTrans, x) * np.diag(sig) * np.diag(1 - sig) )   
    return result
def updateTh(x,y,th):
    hessianInv = np.linalg.inv(hessian(x,y,th))                         
    grad = gradient(x,y,th)                                  
    th = th - np.dot(hessianInv, grad)                     
    return th

m = 80 #number of x rows
x = np.ones([m,3])
y = np.empty([m,1], dtype = int)
th = np.zeros([3,1])
hessianResult = np.identity(3) #identity 3x3


with open('exam.csv','r') as csvfile:
            i = 0
            reader = csv.reader(csvfile)
            next(reader) #skip header            
            for line in reader:
                x[i][1] = line[0]
                x[i][2] = line[1]
                y[i][0] = line[2]
                i+=1

#m = x.shape[0] #number of x rows
for i in range(40):
    print("Entry #",i,": ",x[i][1],", ",x[i][2],", ",y[i][0], sep = '')
    costResult = cost(x,y,th)
    print(costResult)
    hessianResult = hessian(x,y,th)
    print(hessianResult)
    grad = gradient(x,y,th)
    print(grad)
    th = updateTh(x,y,th)
    print(th)

Он должен работать и выводиться нормально в командной строке (Windows), если вы просто скопируете мои данные csv и используете их в качестве тестового ввода. Поэтому единственное различие, которое я вижу между тем, что я сделал, и тем, что вы сделали (что может быть причиной ошибок), заключается в структурировании самого файла данных оценок.

0 голосов
/ 26 октября 2019

Прежде всего, вы можете удалить i=0 и i+=1 из строк, где вы читаете файл. Просто замените for line in reader: на for i, line in enumerate(reader):

перечисление заставит i начинать с 0 и увеличивать при каждой новой строке.

Однако я не могу определитьчто-то не так в вашем коде, поэтому я предполагаю, что есть некоторая проблема с инициализацией переменных.

В частности: вы запрашиваете x в виде массива (m,3), но инициализируете только два столбца,Кроме того, вы берете th в качестве матрицы нулей в начале. Затем первое, что вы делаете, это вычисляет стоимость, что означает, прежде всего, вычисление np.dot(x,th). Боюсь, что это не будет зависеть от данных, которые дал вам ваш профессор, потому что th полон нулей. Это также объясняет, почему вы всегда получаете ошибку на одной и той же итерации.

...