fitTransform method

Map<String, dynamic> fitTransform(
  1. List<List<double>> X
)

Implementation

Map<String, dynamic> fitTransform(List<List<double>> X) {
  final n = X.length;
  if (n == 0) throw ArgumentError('Empty dataset');
  final m = X[0].length;
  // center
  final mean = List<double>.filled(m, 0.0);
  for (var i = 0; i < n; i++) {
    for (var j = 0; j < m; j++) {
      mean[j] += X[i][j];
    }
  }
  for (var j = 0; j < m; j++) {
    mean[j] /= n;
  }
  final xCentered = List.generate(n, (i) => List<double>.filled(m, 0.0));
  for (var i = 0; i < n; i++) {
    for (var j = 0; j < m; j++) {
      xCentered[i][j] = X[i][j] - mean[j];
    }
  }

  // covariance matrix
  final cov = List.generate(m, (_) => List<double>.filled(m, 0.0));
  for (var i = 0; i < n; i++) {
    for (var a = 0; a < m; a++) {
      for (var b = 0; b < m; b++) {
        cov[a][b] += xCentered[i][a] * xCentered[i][b];
      }
    }
  }
  for (var a = 0; a < m; a++) {
    for (var b = 0; b < m; b++) {
      cov[a][b] /= (n - 1);
    }
  }

  // power iteration for top components
  final comps = <List<double>>[];
  for (var k = 0; k < components; k++) {
    var v = List<double>.filled(m, 1.0);
    for (var iter = 0; iter < 1000; iter++) {
      final w = List<double>.filled(m, 0.0);
      for (var i = 0; i < m; i++) {
        for (var j = 0; j < m; j++) {
          w[i] += cov[i][j] * v[j];
        }
      }
      final nv = _normalize(w);
      // deflate
      if ((nv
              .asMap()
              .entries
              .map((e) => (nv[e.key] - v[e.key]) * (nv[e.key] - v[e.key]))
              .reduce((a, b) => a + b)).abs() <
          1e-9) {
        break;
      }
      v = nv;
    }
    comps.add(v);
    // deflate cov (simple subtraction)
    for (var i = 0; i < m; i++) {
      for (var j = 0; j < m; j++) {
        cov[i][j] -= v[i] * v[j];
      }
    }
  }

  final projected = List.generate(
    n,
    (_) => List<double>.filled(components, 0.0),
  );
  for (var i = 0; i < n; i++) {
    for (var k = 0; k < components; k++) {
      var s = 0.0;
      for (var j = 0; j < m; j++) {
        s += xCentered[i][j] * comps[k][j];
      }
      projected[i][k] = s;
    }
  }

  return {'projected': projected, 'components': comps, 'mean': mean};
}