Table of Contents

1. Regresja liniowa

W niniejszym rozdziale przedstawiono implementację prostej i wielorakiej regresji liniowej w Delphi Object Pascalu.

Prosta regresja liniowa

Pełny kod znajduje się na GitHub.

program SimpleLinearRegression;

{$APPTYPE CONSOLE}

uses
  SysUtils, Windows;

const
  { 1. Set the hyperparameters for the model }
  LearningRate: Single = 0.0005;
  Iterations: Integer = 35000;
  PrintEvery: Integer = 1000;

type
  TSample = array[0..1] of Single;
  TDataset = array[0..4] of TSample;

var
  a, b: Single;
  i, j, n: Integer;
  error, squaredError, sumErrorValue, sumError, meanSquaredError: Single;
  x, y, prediction: Single;
  deltaA, deltaB: Single;

const
  { 2. Create dataset }
  { y = -2*x + 120 }
  data: TDataset = (
    (10, 100),
    (20, 80),
    (30, 60),
    (40, 40),
    (50, 20)
  );

begin
  SetConsoleOutputCP(CP_UTF8);

  { 3. Initialize model parameters }
  a := 0;
  b := 0;

  { Number of samples }
  n := Length(data);

  { 3. Training loop }
  for i := 0 to Iterations - 1 do
  begin
    { Initialize accumulators for errors }
    sumErrorValue := 0;
    sumError := 0;
    squaredError := 0;

    for j := 0 to n - 1 do
    begin
      x := data[j][0];
      y := data[j][1];

      { Prediction and error calculation }
      prediction := a * x + b;
      error := y - prediction;

      { Accumulate squared error and gradients }
      squaredError := squaredError + error * error;
      sumErrorValue := sumErrorValue + error * x;
      sumError := sumError + error;
    end;

    deltaA := -2.0 / n * sumErrorValue;
    deltaB := -2.0 / n * sumError;

    { Update regression parameters }
    a := a - LearningRate * deltaA;
    b := b - LearningRate * deltaB;

    if (i mod PrintEvery = 0) then
    begin
      meanSquaredError := squaredError / n;

      Writeln(Format('Iteration: %5d | MSE: %10.5f | ∂MSE/∂a: %10.4f | ∂MSE/∂b: %10.4f | a: %9.4f | b: %9.4f',
  [i, meanSquaredError, deltaA, deltaB, a, b]));
    end;
  end;

  { 5. Output learned parameters }
  Writeln;
  Writeln(Format('%-20s a = %9.4f | b = %9.4f', ['Learned parameters:', a, b]));
  Writeln(Format('%-20s a = %9.4f | b = %9.4f', ['Expected parameters:', -2.0, 120.0]));
  Readln;
end.

Wieloraka regresja liniowa z macierzami

Program główny

Poniższy kod jest portem z C# kodu umieszczonego w rozdziale nt. wielorakiej regresji liniowej. Program oblicza model wielorakiej regresji liniowej z wykorzystaniem rachunku macierzowego.

Pełny kod znajduje się na GitHub.

program MultiLinearRegression;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Windows,
  Math,
  MatrixUtility in 'MatrixUtility.pas';

const
  { 1. Set the hyperparameters for the model }
  LearningRate: Single = 0.0005;
  Iterations: Integer = 35000;
  PrintEvery: Integer = 1000;

type
  TSample = array[0..3] of Single; // [x1, x2, x3, y]
  TDataset = array[0..4] of TSample;

var
  XAnd1, Y, AB, Predictions, Errors, DeltaAB: TMatrix;
  i, j, k, n, numCoefficients: Integer;
  meanSquaredError, tempSum: Single;

const
  { 2. Create dataset }
  { y = 2*x1 + 3*x2 - 1*x3 + 5 }
  data: TDataset = (
    (1, 2, 1, 12),
    (2, 1, 2, 10),
    (3, 3, 1, 19),
    (4, 2, 3, 16),
    (1, 4, 2, 17)
  );

begin
  SetConsoleOutputCP(CP_UTF8);

  { Number of samples and coefficients }
  n := Length(data);
  numCoefficients := Length(data[0]) - 1;

  { Feature matrix XAnd1 with bias term, and target vector Y }
  XAnd1 := CreateMatrix(n, numCoefficients + 1);
  Y := CreateMatrix(n, 1);

  for i := 0 to n - 1 do
  begin
    for j := 0 to numCoefficients - 1 do
      XAnd1[i][j] := data[i][j];
    XAnd1[i][numCoefficients] := 1; // Bias term
    Y[i][0] := data[i][numCoefficients];
  end;

  { 3. Initialize model parameters (a1, a2, a3, b) }
  AB := CreateMatrix(numCoefficients + 1, 1);

  { 4. Training loop }
  for i := 1 to Iterations do
  begin
    { Predictions and errors }
    Predictions := MultiplyDot(XAnd1, AB);
    Errors := Subtract(Y, Predictions);

    { Gradient calculation: ∂MSE/∂AB = -2/n * X^T * Errors }
    DeltaAB := MultiplyScalar(MultiplyDot(Transpose(XAnd1), Errors), -2.0 / n);

    { Update parameters }
    AB := Subtract(AB, MultiplyScalar(DeltaAB, LearningRate));

    if (i mod PrintEvery = 0) then
    begin
      { Mean Squared Error }
      meanSquaredError := Mean(PowerMatrix(Errors, 2));

      Writeln(Format('Iteration: %6d | MSE: %8.5f | a1: %8.4f | a2: %8.4f | a3: %8.4f | b: %8.4f',
        [i, meanSquaredError, AB[0][0], AB[1][0], AB[2][0], AB[3][0]]));
    end;
  end;

  { 5. Output learned parameters }
  Writeln;
  Writeln('--- Training Complete (Matrices with Bias) ---');
  Writeln(Format('%-20s a1 = %9.4f | a2 = %9.4f | a3 = %9.4f | b = %9.4f',
    ['Learned parameters:', AB[0][0], AB[1][0], AB[2][0], AB[3][0]]));
  Writeln(Format('%-20s a1 = %9.4f | a2 = %9.4f | a3 = %9.4f | b = %9.4f',
    ['Expected parameters:', 2.0, 3.0, -1.0, 5.0]));

  Readln;
end.

Moduł pomocniczy do operacji macierzowych

Kod znajduje się na GitHub.

unit MatrixUtility;

interface

uses
  Math;

type
  TMatrix = array of array of Single;

{ --- Matrix utility functions --- }

function CreateMatrix(rows, cols: Integer): TMatrix;
function MultiplyDot(const A, B: TMatrix): TMatrix;
function Subtract(const A, B: TMatrix): TMatrix;
function Transpose(const A: TMatrix): TMatrix;
function MultiplyScalar(const A: TMatrix; s: Single): TMatrix;
function PowerMatrix(const A: TMatrix; p: Integer): TMatrix;
function Mean(const A: TMatrix): Single;

implementation

{ --- Matrix utility functions --- }

function CreateMatrix(rows, cols: Integer): TMatrix;
var
  rowIndex, rowSize: Integer;
begin
  SetLength(Result, rows, cols);
  rowSize := cols * SizeOf(Single);
  for rowIndex := 0 to rows - 1 do
    FillChar(Result[rowIndex][0], rowSize, 0);
end;

function MultiplyDot(const A, B: TMatrix): TMatrix;
var
  i, j, k, aRows, aCols, bCols: Integer;
  sum: Single;
begin
  aRows := Length(A);
  aCols := Length(A[0]);
  bCols := Length(B[0]);
  Result := CreateMatrix(aRows, bCols);

  for i := 0 to aRows - 1 do
    for j := 0 to bCols - 1 do
    begin
      sum := 0;
      for k := 0 to aCols - 1 do
        sum := sum + A[i][k] * B[k][j];
      Result[i][j] := sum;
    end;
end;

function Subtract(const A, B: TMatrix): TMatrix;
var
  i, j, aRows, aCols: Integer;
begin
  aRows := Length(A);
  aCols := Length(A[0]);
  Result := CreateMatrix(aRows, aCols);

  for i := 0 to aRows - 1 do
    for j := 0 to aCols - 1 do
      Result[i][j] := A[i][j] - B[i][j];
end;

function Transpose(const A: TMatrix): TMatrix;
var
  i, j, aRows, aCols: Integer;
begin
  aRows := Length(A);
  aCols := Length(A[0]);
  Result := CreateMatrix(aCols, aRows);
  for i := 0 to aRows - 1 do
    for j := 0 to aCols - 1 do
      Result[j][i] := A[i][j];
end;

function MultiplyScalar(const A: TMatrix; s: Single): TMatrix;
var
  i, j, aRows, aCols: Integer;
begin
  aRows := Length(A);
  aCols := Length(A[0]);
  Result := CreateMatrix(aRows, aCols);
  for i := 0 to aRows - 1 do
    for j := 0 to aCols - 1 do
      Result[i][j] := A[i][j] * s;
end;

function PowerMatrix(const A: TMatrix; p: Integer): TMatrix;
var
  i, j, aRows, aCols: Integer;
begin
  aRows := Length(A);
  aCols := Length(A[0]);
  Result := CreateMatrix(aRows, aCols);
  for i := 0 to aRows - 1 do
    for j := 0 to aCols - 1 do
      Result[i][j] := Power(A[i][j], p);
end;

function Mean(const A: TMatrix): Single;
var
  i, j, aRows, aCols: Integer;
  sum: Single;
begin
  aRows := Length(A);
  aCols := Length(A[0]);
  sum := 0;
  for i := 0 to aRows - 1 do
    for j := 0 to aCols - 1 do
      sum := sum + A[i][j];
  Result := sum / (aRows * aCols);
end;

end.


Created: 2025-06-23

Last modified: 2025-10-31

Title: 1. Regresja liniowa

Tags: [Delphi] [Pascal] [Object Pascal] [Sieci neuronowe] [Regresja liniowa]