logistic static method

RegressionResult logistic(
  1. Matrix X,
  2. dynamic y, {
  3. int maxIter = 100,
  4. double learningRate = 0.01,
})

Logistic regression for binary classification.

Implementation

static RegressionResult logistic(
  Matrix X,
  dynamic y, {
  int maxIter = 100,
  double learningRate = 0.01,
}) {
  List<num> yList = _toNumList(y);
  int n = X.rowCount;
  int p = X.columnCount;

  // Initialize coefficients
  List<num> coefficients = List.filled(p + 1, 0.0);

  // Gradient descent
  for (int iter = 0; iter < maxIter; iter++) {
    List<num> predictions = [];
    for (int i = 0; i < n; i++) {
      num z = coefficients[0];
      for (int j = 0; j < p; j++) {
        z += coefficients[j + 1] * _toNum(X[i][j]);
      }
      predictions.add(_sigmoid(z));
    }

    // Calculate gradients
    List<num> gradients = List.filled(p + 1, 0.0);
    for (int i = 0; i < n; i++) {
      num error = predictions[i] - yList[i];
      gradients[0] += error;
      for (int j = 0; j < p; j++) {
        gradients[j + 1] += error * X[i][j].toDouble();
      }
    }

    // Update coefficients
    for (int j = 0; j < coefficients.length; j++) {
      coefficients[j] -= learningRate * gradients[j] / n;
    }
  }

  // Final predictions
  List<num> predictions = [];
  for (int i = 0; i < n; i++) {
    num z = coefficients[0];
    for (int j = 0; j < p; j++) {
      z += coefficients[j + 1] * _toNum(X[i][j]);
    }
    predictions.add(_sigmoid(z));
  }

  List<num> residuals = [];
  for (int i = 0; i < n; i++) {
    residuals.add(yList[i] - predictions[i]);
  }

  // Calculate pseudo R-squared (McFadden's)
  num yMean = yList.reduce((a, b) => a + b) / n;
  num nullDeviance = 0;
  for (int i = 0; i < n; i++) {
    if (yList[i] == 1) {
      nullDeviance -= 2 * math.log(yMean);
    } else {
      nullDeviance -= 2 * math.log(1 - yMean);
    }
  }

  num residualDeviance = 0;
  for (int i = 0; i < n; i++) {
    num p = predictions[i].clamp(1e-10, 1 - 1e-10);
    if (yList[i] == 1) {
      residualDeviance -= 2 * math.log(p);
    } else {
      residualDeviance -= 2 * math.log(1 - p);
    }
  }

  num pseudoR2 = 1 - residualDeviance / nullDeviance;

  return RegressionResult(
    coefficients: Series(coefficients, name: 'coefficients'),
    rSquared: pseudoR2,
    residuals: Series(residuals, name: 'residuals'),
    predictions: Series(predictions, name: 'predictions'),
  );
}