logistic static method
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'),
);
}