Fuzzy Regression#

The ex_fuzzy.evolutionary_fit_regression module learns interpretable Type-1 fuzzy rules for continuous targets. During optimization it precomputes the fixed input-partition memberships and scores candidate rule bases through a vectorized NumPy inference path with PyMoo, or a batched PyTorch path with the optional EvoX backend.

Two consequent styles are available, selected with consequent_type:

crisp (default)

Zero-order Takagi-Sugeno. Each rule carries a number, and a prediction is the firing-strength-weighted average of those numbers. Best numeric resolution.

fuzzy

Mamdani. Each rule names an output fuzzy set whose trapezoid is evolved alongside the rules; predictions are the centroid of the clipped and max-aggregated consequents. Rules read fully linguistically, at some cost in resolution.

rule_mode controls how many rules speak per sample. additive (default) lets every rule contribute. sufficient keeps only each sample’s strongest rule, and falls back to the training-target mean when even that rule fires at or below tolerance – giving piecewise-constant, winner-takes-all output.

BaseFuzzyRulesRegressor#

FitRuleBaseRegression#

RuleBaseT1Regression#

RuleBaseT1MamdaniRegression#

Example#

from ex_fuzzy import BaseFuzzyRulesRegressor
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split

X, y = make_regression(n_samples=200, n_features=4, random_state=0)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=0
)

regressor = BaseFuzzyRulesRegressor(nRules=20, nAnts=3)
regressor.fit(X_train, y_train, n_gen=50, pop_size=50)

predictions = regressor.predict(X_test)
print(regressor.score(X_test, y_test))
regressor.print_rules()
# Rule 1: IF x0 IS Low AND x2 IS High THEN output = 41.8203

GPU optimization#

Install ex-fuzzy[evox] and select the EvoX backend to evaluate complete populations on CUDA. If CUDA is unavailable, EvoX runs the same PyTorch path on the CPU.

regressor = BaseFuzzyRulesRegressor(
    nRules=30, nAnts=4, backend="evox", verbose=True
)
regressor.fit(X_train, y_train, n_gen=50, pop_size=100)
print(regressor.optimization_device_)
print(regressor.gpu_accelerated_)

Linguistic consequents#

Switch to Mamdani inference when a rule should name an output label rather than a number:

regressor = BaseFuzzyRulesRegressor(
    nRules=20,
    nAnts=3,
    consequent_type="fuzzy",
    n_output_lvs=4,          # how many output sets to evolve
    n_universe_points=101,   # centroid integration grid
)
regressor.fit(X_train, y_train, n_gen=50, pop_size=50)
regressor.print_rules()
# Rule 1: IF x0 IS Low AND x2 IS High THEN output IS Output_3

Every chromosome decodes to a valid trapezoid because each output set’s four breakpoints are sorted before being scaled into the target range.

Winner-takes-all rules#

regressor = BaseFuzzyRulesRegressor(
    nRules=20, nAnts=3, rule_mode="sufficient", tolerance=0.05
)

With sufficient only the strongest rule fires per sample, so a crisp- consequent model becomes piecewise constant: every prediction is one rule’s consequent, or the target mean where nothing clears the tolerance.

The genetic search optimizes training-set \(R^2\). To estimate generalization with cross-validation, evaluate the complete estimator through scikit-learn’s cross_val_score or cross_validate; the estimator must be refitted independently inside each fold.