Я пытаюсь реализовать линейную регрессию с нуля (как с точки зрения кода, так и математических знаний) для целей обучения.
Я перешел от циклов к NumPy, затем от вычисления градиента вручную до использования Autograd. Сейчас я пытаюсь преобразовать свой код для использования Pandas вместо NumPy. Но кажется, что Autograd не работает с DataFrame
s или Series
, потому что я продолжаю получать эту ошибку:
TypeError: Can't differentiate w.r.t. type <class 'pandas.core.series.Series'>
# or DataFrame
Я выполнил базовую реализацию двойных чисел, поэтому знаю, как работает автодифференцирование на базовом уровне, но autograd
слишком сложен, чтобы трассировка стека была для меня полезна.
Вот соответствующие части кода:
import autograd.numpy as np
import pandas as pd
from autograd import grad
raw_data = pd.read_csv('FiveCitiePMData/BeijingPM20100101_20151231.csv')
df = raw_data.filter(['HUMI','TEMP', 'PM_US Post'], axis=1).dropna()
class LinRegModel:
def __init__(self, dataset):
self.X = dataset.iloc[:,:-1].copy() # all but last column
self.X.insert(0, 'dummy', 1) # padding (w_0)
self.y = dataset.iloc[:,-1].copy() # last column
def __cost__(self, weights):
errors = self.X @ weights - self.y
return np.square(errors).mean() # no need to div by 2 because autodiff
def train(self, epsilon=0.001, learning_rate=0.01):
self.weights = pd.Series(0.0, index=list(self.X)) # np.zeros((self.X.shape[1], 1))
grad_cost = grad(self.__cost__)
last_cost = 0
while True:
self.weights -= learning_rate * grad_cost(self.weights)
this_cost = self.__cost__(self.weights)
if abs(this_cost - last_cost) < epsilon:
break
last_cost = this_cost
lrm = LinRegModel(df)
Функция __cost__(weights)
работает нормально, независимо от того, является ли weights
массивом NumPy, Pandas Series или Pandas DataFrame. Но это даст мне ошибку выше:
grad_cost(self.weights)
Если я сделаю это:
grad_cost(np.array(self.weights))
Затем он зависает, и в конце концов я получаю это:
TypeError: Could not convert Autograd ArrayBox with value 523236993.0 to numeric
Единственный способ заставить его работать - это сделать:
def __cost__(self, weights):
errors = np.array(self.X) @ np.array(weights) - np.array(self.y)
return np.square(errors).mean()
grad_cost(np.array(self.weights))
Но это не очень элегантное или удобочитаемое решение.
Я что-то упускаю из-за Автограда или Панд?