Следующий код реализует многомерную линейную регрессию с нуля. Код строится с того места, где мы остановились в простой линейной регрессии (https://medium.com/@surajsubramanian2000/simple-linear-regression-from-scratch-9e073185cdab).

Представление нашей гипотезы в виде функции нескольких параметров является мощным и необходимым. Следовательно, многомерная линейная регрессия широко используется, и это действительно мощный алгоритм.

Импорт необходимых пакетов

  • numpy: для представления векторов,
  • pandas: для чтения CSV-файлов и
  • sklearn: мы используем его для разделения набора данных на обучение и тестирование, предварительной обработки, кодирования и вычисления ошибок.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import LabelEncoder
labelencoder = LabelEncoder()

Затем мы загружаем CSV-файл и удаляем ненужные столбцы. Набор данных можно загрузить с https://github.com/SurajSubramanian/MachineLearning/blob/master/ML-Programs/MultivariateLinearRegression/FuelConsumptionCo2.csv

df = pd.read_csv("FuelConsumptionCo2.csv")

Мы просмотрим набор данных

df['MODELYEAR'].unique() # returns array([2014])

Существует только 1 MODELYEAR, поэтому нет смысла включать его в качестве параметра. Так что бросаем

df = df.drop(['MODELYEAR'], axis=1)

Мы используем labelencoder для присвоения уникальных значений всем категориальным типам данных, поскольку мы не можем работать со строковыми переменными.

df['MAKE'], df['MODEL'], df['VEHICLECLASS'], df['TRANSMISSION'], df['FUELTYPE'] = \
labelencoder.fit_transform(df['MAKE']), labelencoder.fit_transform(df['MODEL']), labelencoder.fit_transform(df['VEHICLECLASS']), \
labelencoder.fit_transform(df['TRANSMISSION']), labelencoder.fit_transform(df['FUELTYPE'])

Далее мы отфильтровываем переменные, имеющие меньшую корреляцию с целевым параметром — CO2EMISSIONS.

cor = df.corr()
cor_target = abs(cor["CO2EMISSIONS"])
#Selecting highly correlated features
relevant_features = cor_target[cor_target>0.5]
relevant_features
# Output :
ENGINESIZE                  0.874154
CYLINDERS                   0.849685
FUELCONSUMPTION_CITY        0.898039
FUELCONSUMPTION_HWY         0.861748
FUELCONSUMPTION_COMB        0.892129
FUELCONSUMPTION_COMB_MPG    0.906394
CO2EMISSIONS                1.000000
Name: CO2EMISSIONS, dtype: float64

Удаление столбцов с низкой корреляцией, т. е.) столбцов с корреляцией ниже 0,5

df = df.drop(['MAKE', 'MODEL', 'VEHICLECLASS', 'FUELTYPE', 'TRANSMISSION'], axis=1)
df.head()

Мы используем минимальную нормализацию. Этот шаг действительно важен. Вы можете пропустить следующую ячейку и попробовать все остальные ячейки, чтобы получить какое-то абсурдное значение в качестве ошибки MSE.

y,x = df["CO2EMISSIONS"], df.drop(["CO2EMISSIONS"], axis=1)

Разделение набора данных на функции обучения и тестирования

x_, y_ = x.to_numpy(), y.to_numpy()
x_ = np.append(arr = np.ones((len(x_), 1)).astype(int), values = x, axis = 1) 

x_train,x_test,y_train,y_test = train_test_split(x_,y_, test_size = 0.2, random_state=21)

Реализация тренировочного цикла

a=0.01
X = []
for row in x_train:
    r = [1]
    for item in row:
        r.append(item)
    X.append(r)
    
X = np.asmatrix(X)
theta = np.zeros(((X[0].size), 1))
Y = y_train.reshape(-1,1)

h = np.dot(X, theta)
h.shape # returns (853, 1)
temp = np.zeros(theta.shape)
cost = np.sum (np.dot(np.transpose(h-Y), (h-Y)))*(1/(2*X.shape[0]))
temp = np.zeros(theta.shape)

Функция градиентного спуска и последующий код аналогичны тем, которые мы использовали для линейной регрессии, за исключением того, что здесь мы представляем тета в виде массива.

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

def gradientDescent(theta, X):
    h = np.dot(X, theta)
    cost = np.sum(np.sum((h-Y)**2))*(1/(2*X.shape[0]))
    temp = theta - np.dot(X.T, h-Y) * (a/X.shape[0])
    theta = temp
    return(theta, X, cost)
oldCost = 0
theta = np.ones(theta.shape)
X = np.ones(X.shape)
for i in range(0, 10000):
    (theta, X, cost) = gradientDescent(theta, X)
    if i%1000 == 0:
        print(cost)
        print(theta)

прогнозирование значений y для тестового набора данных и оценка нашей модели с помощью функции MSE

X_test = []
for row in x_test:
    r = [1]
    for item in row:
        r.append(item)
    X_test.append(r)
mean_squared_error(np.dot(X_test, theta), y_test) # returns 0.05530668773441035

Вы можете получить полный код из моего репозитория github https://github.com/SurajSubramanian/MachineLearning/tree/master/ML-Programs/MultivariateLinearRegression.

Вы можете добиться лучших результатов, используя встроенную функцию sklearn!

Спасибо за чтение :)