public Formula(Term response, Term... predictors) {
        if (response instanceof Dot || response instanceof FactorCrossing) {
            throw new IllegalArgumentException("The response variable cannot be '.' or FactorCrossing.");
        }

        this.response = response;
        this.predictors = predictors;
    }
@Test
    public void testFormula() {
        System.out.println("formula");
        Formula formula = Formula.of("salary", $("age"));
        assertEquals("salary ~ age", formula.toString());

        DataFrame output = formula.frame(df);
        System.out.println(output);
        assertEquals(df.size(), output.size());
        assertEquals(2, output.ncol());

        smile.data.type.StructType schema = DataTypes.struct(
                new StructField("salary", DataTypes.object(Double.class)),
                new StructField("age", DataTypes.IntegerType)
        );
        assertEquals(schema, output.schema());

        DataFrame x = formula.x(df);
        System.out.println(x);
        assertEquals(df.size(), x.size());
        assertEquals(1, x.ncol());

        smile.data.type.StructType xschema = DataTypes.struct(
                new StructField("age", DataTypes.IntegerType)
        );
        assertEquals(xschema, x.schema());

        assertEquals(10000.0, formula.y(df.get(0)), 1E-7);
        assertEquals(Double.NaN, formula.y(df.get(1)), 1E-7);

        Matrix matrix = formula.matrix(df);
        assertEquals(df.size(), matrix.nrow());
        assertEquals(2, matrix.ncol());
    }