features.SinX1(),
        features.SinX2(),
        features.SinX3(),
        features.SinX4(),
        # features.X1Cube(), features.X2Cube(),
        # features.X3Cube(), features.X4Cube(),
        # features.TanX1(), features.TanX2(),
        # features.TanX3(), features.TanX4(),
        # features.X1OverX2(), features.X1OverX3(),
        # features.X1OverX4(), features.X2OverX3(),
        # features.X2OverX4(), features.X3OverX4(),
        features.CrossTermX1X2(),
        features.CrossTermX1X3(),
        features.CrossTermX1X4(),
        features.CrossTermX2X3(),
        features.CrossTermX2X4(),
        features.CrossTermX3X4(),
        features.Identity()
    ])
    lm[part].fit(training_input[part], training_output[part])

    # Validation
    mse_part[part] = lm[part].validate(validation_input[part],
                                       validation_output[part])

    print('MSE for part {}: {}'.format(part, mse_part[part]))
    print(' ')
    print('feature weights for part {} \n{}'.format(part, lm[part].beta))

mse = np.sum(mse_part) / n_parts
print('MSE combined: {}'.format(mse))