public RandomForest merge(RandomForest other) {
        if (!formula.equals(other.formula)) {
            throw new IllegalArgumentException("RandomForest have different model formula");
        }

        Model[] forest = new Model[models.length + other.models.length];
        System.arraycopy(models, 0, forest, 0, models.length);
        System.arraycopy(other.models, 0, forest, models.length, other.models.length);

        // rough estimation
        ClassificationMetrics mergedMetrics = new ClassificationMetrics(
                metrics.fitTime * other.metrics.fitTime,
                metrics.scoreTime * other.metrics.scoreTime,
                metrics.size,
                (metrics.error * other.metrics.error) / 2,
                (metrics.accuracy * other.metrics.accuracy) / 2,
                (metrics.sensitivity * other.metrics.sensitivity) / 2,
                (metrics.specificity * other.metrics.specificity) / 2,
                (metrics.precision * other.metrics.precision) / 2,
                (metrics.f1 * other.metrics.f1) / 2,
                (metrics.mcc * other.metrics.mcc) / 2,
                (metrics.auc * other.metrics.auc) / 2,
                (metrics.logloss * other.metrics.logloss) / 2,
                (metrics.crossentropy * other.metrics.crossentropy) / 2
        );

        double[] mergedImportance = importance.clone();
        for (int i = 0; i < importance.length; i++) {
            mergedImportance[i] += other.importance[i];
        }

        return new RandomForest(formula, k, forest, mergedMetrics, mergedImportance, classes);
    }
@Test
    public void testMerge() {
        System.out.println("merge");

        RandomForest forest1 = RandomForest.fit(Segment.formula, Segment.train, 100, 16, SplitRule.GINI, 20, 100, 5, 1.0, null, Arrays.stream(seeds));
        RandomForest forest2 = RandomForest.fit(Segment.formula, Segment.train, 100, 16, SplitRule.GINI, 20, 100, 5, 1.0, null, Arrays.stream(seeds));
        RandomForest forest = forest1.merge(forest2);

        int error1 = Error.of(Segment.testy, forest1.predict(Segment.test));
        int error2 = Error.of(Segment.testy, forest2.predict(Segment.test));
        int error  = Error.of(Segment.testy, forest.predict(Segment.test));
        System.out.format("Forest 1 Error = %d%n", error1);
        System.out.format("Forest 2 Error = %d%n", error2);
        System.out.format("Merged   Error = %d%n", error);
        assertEquals(33, error1);
        assertEquals(33, error2);
        assertEquals(33, error);
    }