public double nFoldCrossValidation(Matrix features, Matrix labels, int n) {

        int rows = features.getNumRows();

        if (n > rows) {
            throw new MLException(String.format(
                    "n [%d] must be <= row size [%d]", n, features.getNumRows()));
        }

        if (rows != labels.getNumRows()) {
            throw new MLException("Features and labels rows mismatch");
        }

        int foldSize = rows % n == 0 ? rows / n : rows / n + 1;
        double sum = 0;
        for (int i = 0; i < n; i++) {
            int foldStart = i * foldSize;
            int foldEnd = (i + 1) * foldSize;
            if (foldEnd > rows) {
                foldEnd = rows;
            }

            Matrix toTrainFeatures = new Matrix(features);
            Matrix toTrainLabels = new Matrix(labels);

            Matrix toPredictFeatures = toTrainFeatures.removeFold(foldStart, foldEnd);
            Matrix toPredictLabels = toTrainLabels.removeFold(foldStart, foldEnd);

            train(toTrainFeatures, toTrainLabels);
            sum += this.getAccuracy(toPredictFeatures, toPredictLabels);
        }
        return sum / rows;
    }