Эта статья представляет собой реализацию линейной регрессии с использованием решения в закрытой форме для заданного набора данных D.
Программа принимает набор данных D в качестве входных данных, применяет функцию преобразования признаков, определяет функцию гипотезы и функцию среднеквадратичной ошибки (MSE), а также вычисляет вектор весов, используя линейную регрессию решения в закрытой форме.
Затем определяется функция преобразования признаков для преобразования каждого входного примера x в пространство более высокой размерности. Функция преобразования сопоставляет каждый вход x с вектором из трех элементов [1, x, x²] и возвращает его в виде массива NumPy.
import numpy as np # Define the dataset D D = np.array([[1.0, 2.0], [2.0, 1.0], [3.0, 3.0]]) [[1. 2.] [2. 1.] [3. 3.]]
Входной объект x преобразуется в двумерный, и функция преобразования применяется к каждому входному примеру в D с использованием функции apply_along_axis. Результирующий преобразованный набор данных затем преобразуется в три столбца, соответствующие трем функциям [1, x, x²].
# Define the feature transformation function def transform(x): return np.array([1, x, x**2], dtype=np.float64) # Reshape the input array to be two-dimensional D_reshaped = D[:, 0].reshape(-1, 1) # Apply the transformation to each input example in D D_transformed = np.apply_along_axis(transform, 1, D_reshaped).reshape(-1, 3) Transformed dataset: [[1. 1. 1.] [1. 2. 4.] [1. 3. 9.]]
Функция гипотезы hw(x) определена
который принимает входной пример x и весовой вектор w в качестве входных данных и возвращает скалярное произведение весового вектора и преобразованного входного примера x.
Обратная матрица Мура-Пенроуза (также известная как псевдообратная) представляет собой обобщение обратной матрицы для неквадратных матриц. Он обозначается A⁺ и может быть определен как:
A⁺ = (AᵀA)⁻¹Aᵀ
где Aᵀ - это транспонированный A, а (AᵀA)⁻¹ - обратный AᵀA, если он существует.
Псевдоинверсия имеет ряд полезных свойств, например позволяет решать переопределенные системы линейных уравнений (т. е. когда уравнений больше, чем неизвестных). В частности, если у нас есть система линейных уравнений вида Ax = b, где A — неквадратная матрица, а b — вектор, мы можем использовать псевдообратное уравнение, чтобы найти решение x:
x = A⁺b
Обратите внимание, что если A является квадратной матрицей и имеет обратную, то A⁺ = A⁻¹. Однако в целом псевдоинверсия — это более общее понятие, применимое к неквадратным матрицам.
Чтобы найти весовой вектор w, который минимизирует функцию потерь MSE, мы можем решить нормальные уравнения:
Решение для w определяется следующим образом:
Вычисляя w по приведенной выше формуле, получаем:
Затем весовой вектор вычисляется с использованием решения в закрытой форме для линейной регрессии, которое включает в себя вычисление обратного произведения транспонирования преобразованного набора данных и самого набора данных, умноженного на транспонирование преобразованного набора данных и целевой выходной вектор y .
# Define the hypothesis function hw(x) def hw(x, w): return np.dot(w, x) # Define the mean squared error (MSE) function def mse(X, y, w): m = len(y) y_pred = np.apply_along_axis(lambda x: hw(x, w), 1, X) return (1/m) * np.sum((y_pred - y)**2) # Define the inputs and targets X = D_transformed y = D[:, 1] # Calculate the weight vector using the closed-form solution for linear regression w = np.linalg.inv(X.T @ X) @ X.T @ y Weight vector: [ 6. -5.5 1.5]
Затем программа применяет функцию преобразования к входным примерам hw(1), hw(2) и hw(3) и вычисляет соответствующие им прогнозируемые выходные значения, используя изученный вектор весов и функцию гипотезы. Вот функция гипотезы.
# Define the hypothesis function hw(x) def hw(x, w): return np.dot(w, x) # Define the mean squared error (MSE) function def mse(X, y, w): m = len(y) y_pred = np.apply_along_axis(lambda x: hw(x, w), 1, X) return (1/m) * np.sum((y_pred - y)**2) # Define the inputs and targets X = D_transformed y = D[:, 1] # Calculate the weight vector using the closed-form solution for linear regression w = np.linalg.inv(X.T @ X) @ X.T @ y # Apply the transformation function to hw(1), hw(2), hw(3) hwtransform
transformed = transform(1) hwD_transformed
transformed = transform(2) hwX
transformed = transform(3) # Calculate the predicted values of hw(1), hw(2), hw(3)) using the learned weight vector w and hypothesis function hw(x) hwtransform
predicted = hw(hwtransform
transformed, w) hwD_transformed
predicted = hw(hwD_transformed
transformed, w) hwX
predicted = hw(hwX
transformed, w) # Print the predicted values of hw(1), hw(2), hw(3) print("Predicted values for hw(1), hw(2), hw(3):") print(hwtransform
predicted, hwD_transformed
predicted, hwX
predicted) Predicted values for hw(1), hw(2), hw(3): 2.0000000000000235 0.999999999999976 2.999999999999947
Наконец, программа вычисляет MSE, используя прогнозируемые выходные значения и фактические целевые значения, и выводит преобразованный набор данных, вектор весов и MSE на консоль.
# Calculate the MSE using the predicted values of hw(1), hw(2), hw(3) and the targets mse_value = mse(np.array([hwtransform
transformed, hwD_transformed
transformed, hwX
transformed]), np.array([2.0, 1.0, 3.0]), w) print("Mean squared error:", mse_value) Mean squared error: 1.3072739967687533e-27
Таким образом, эта программа демонстрирует простую реализацию квадратичной линейной регрессии с использованием решения в закрытой форме и функции преобразования признаков, которая может быть полезна для прогнозирования выходных значений для новых входных примеров. Это же уравнение можно повторить для простой линейной регрессии.
import numpy as np # Define the dataset D D = np.array([[1.0, 2.0], [2.0, 1.0], [3.0, 3.0]]) # Define the feature transformation function def transform(x): return np.array([1, x], dtype=np.float64) # Reshape the input array to be two-dimensional D_reshaped = D[:, 0].reshape(-1, 1) # Apply the transformation to each input example in D D_transformed = np.apply_along_axis(transform, 1, D_reshaped).reshape(-1, 2) # Define the hypothesis function hw(x) def hw(x, w): return np.dot(w, x) # Define the mean squared error (MSE) function def mse(X, y, w): m = len(y) y_pred = np.apply_along_axis(lambda x: hw(x, w), 1, X) return (1/m) * np.sum((y_pred - y)**2) # Define the inputs and targets X = D_transformed y = D[:, 1] # Calculate the weight vector using the closed-form solution for linear regression w = np.linalg.inv(X.T @ X) @ X.T @ y # Apply the transformation function to hw(1), hw(2), hw(3) hwtransform
transformed = transform(1) hwD_transformed
transformed = transform(2) hwX
transformed = transform(3) # Calculate the predicted values of hw(1), hw(2), hw(3)) using the learned weight vector w and hypothesis function hw(x) hwtransform
predicted = hw(hwtransform
transformed, w) hwD_transformed
predicted = hw(hwD_transformed
transformed, w) hwX
predicted = hw(hwX
transformed, w) # Print the predicted values of hw(1), hw(2), hw(3) print("Predicted values for hw(1), hw(2), hw(3):") print(hwtransform
predicted, hwD_transformed
predicted, hwX
predicted) Predicted values for hw(1), hw(2), hw(3): 1.4999999999999982 1.9999999999999982 2.4999999999999982 # Calculate the MSE using the predicted values of hw(1), hw(2), hw(3) and the targets mse_value = mse(np.array([hwtransform
transformed, hwD_transformed
transformed, hwX
transformed]), np.array([2.0, 1.0, 3.0]), w) # Print the transformed dataset, weight vector, and MSE print("Transformed dataset:") print(D_transformed) Transformed dataset: [[1. 1.] [1. 2.] [1. 3.]] print("Weight vector:", w) Weight vector: [1. 0.5] print("Mean squared error:", mse_value) Mean squared error: 0.5
Единственная разница между программой квадратичной и линейной регрессии заключается в следующем.
- Функция
transform
была упрощена и теперь включает только постоянный термин и один признак. - Массив
D_transformed
изменен, чтобы иметь два столбца вместо трех. - Массив
X
в модели линейной регрессии имеет значениеD_transformed
. - Переменные
hw_1_transformed
,hw_2_transformed
иhw_3_transformed
вычисляются с использованием упрощенной функцииtransform
. - Функция
mse
остается прежней, поскольку она может обрабатывать любое количество признаков во входных данных.
import numpy as np import matplotlib.pyplot as plt # Define the dataset D D = np.array([[1.0, 2.0], [2.0, 1.0], [3.0, 3.0]]) # Define the feature transformation functions for linear and quadratic regression def transform_linear(x): return np.array([1, x], dtype=np.float64) def transform_quadratic(x): return np.array([1, x, x**2], dtype=np.float64) # Reshape the input array to be two-dimensional D_reshaped = D[:, 0].reshape(-1, 1) # Apply the transformations to each input example in D D_transformed_linear = np.apply_along_axis(transform_linear, 1, D_reshaped).reshape(-1, 2) D_transformed_quadratic = np.apply_along_axis(transform_quadratic, 1, D_reshaped).reshape(-1, 3) # Define the hypothesis functions for linear and quadratic regression def hw_linear(x, w): return np.dot(w, x) def hw_quadratic(x, w): return np.dot(w, x) # Define the mean squared error (MSE) function for both models def mse_linear(X, y, w): m = len(y) y_pred = np.apply_along_axis(lambda x: hw_linear(x, w), 1, X) return (1/m) * np.sum((y_pred - y)**2) def mse_quadratic(X, y, w): m = len(y) y_pred = np.apply_along_axis(lambda x: hw_quadratic(x, w), 1, X) return (1/m) * np.sum((y_pred - y)**2) # Define the inputs and targets X = D_transformed_linear y = D[:, 1] # Calculate the weight vector using the closed-form solution for linear regression w_linear = np.linalg.inv(X.T @ X) @ X.T @ y # Calculate the MSE using the linear regression model mse_linear_values = [] for i in range(1, 101): w = np.array([0, i/10]) mse_linear_values.append(mse_linear(X, y, w)) # Define the inputs and targets X = D_transformed_quadratic y = D[:, 1] # Calculate the weight vector using the closed-form solution for quadratic regression w_quadratic = np.linalg.inv(X.T @ X) @ X.T @ y # Calculate the MSE using the quadratic regression model mse_quadratic_values = [] for i in range(1, 101): w = np.array([0, i/10, 0.5]) mse_quadratic_values.append(mse_quadratic(X, y, w)) # Plot the MSE values for both models plt.rcParams['figure.figsize'] = [10, 10] x = np.arange(1, 101, 1)/10 plt.plot(x, mse_linear_values, label="Linear Regression") plt.plot(x, mse_quadratic_values, label="Quadratic Regression") plt.xlabel("Weight") plt.ylabel("Mean Squared Error (MSE)") plt.title("Comparison of MSE for Linear and Quadratic Regression") plt.legend() plt.show()
Как видно из сравнения значения mse
линейной регрессии и квадратичной регрессии составляет 0,5 против 1,3072739967687533e-27. MSE квадратичной модели ниже, чем у модели линейной регрессии, а это означает, что линейная модель не может соответствовать данным, а также квадратичная модель. Это может быть связано с тем, что взаимосвязь между независимыми и зависимыми переменными более сложна, чем может отразить линейная функция, и квадратичная модель лучше способна отразить эту сложность.