Daniel notes
you@here:~/articles/anfis-toolbox$ cat first-model.md

#anfis #fuzzy #tutorial

A first model with ANFIS Toolbox

Every block on this page can be run here: press [run]. They share one Python session, so run them in order. On your own machine the only difference is how the library gets installed:

pip install anfis-toolbox

Regression

The target is a bowl, y=x12+x22, sampled at 200 random points. It is a good first test because no single linear model fits it, but a handful of local linear models, blended smoothly, do.

import micropip
await micropip.install("anfis-toolbox")  # browser only

import numpy as np
from anfis_toolbox import ANFISRegressor

rng = np.random.default_rng(0)
X = rng.uniform(-2, 2, (200, 2))
y = X[:, 0] ** 2 + X[:, 1] ** 2

model = ANFISRegressor()
model.fit(X, y)

print("R2 on the training data:", round(model.score(X, y), 4))
print("f(1, 1) and f(0, 0):", model.predict(np.array([[1.0, 1.0], [0.0, 0.0]])).round(3))

The true values at those two points are 2 and 0. With the defaults the model gets close to both, and an R2 near 1.

That is the whole workflow: build the estimator, fit, then predict or score. The names and the shapes of the arrays are the ones scikit-learn uses.

Classification

Two clouds of points, one around (−1,−1) and one around (1,1):

import micropip
await micropip.install("anfis-toolbox")  # browser only

import numpy as np
from anfis_toolbox import ANFISClassifier

rng = np.random.default_rng(0)
X = np.r_[rng.normal(-1, 0.3, (50, 2)), rng.normal(1, 0.3, (50, 2))]
y = np.r_[np.zeros(50, int), np.ones(50, int)]

clf = ANFISClassifier(epochs=200, learning_rate=0.05, random_state=0)
clf.fit(X, y)

print("accuracy:", clf.score(X, y))
print("class of (-1, -1) and (1, 1):", clf.predict(np.array([[-1.0, -1.0], [1.0, 1.0]])))

The classifier is trained by gradient descent alone, so it is more sensitive to its settings than the regressor. Three arguments do the work here:

Argument Why it is set
epochs more passes over the data than the default
learning_rate a larger step, so those passes get somewhere
random_state fixes the random starting point, so the run is repeatable

Warning

With every argument left at its default, this same example sometimes ends far from a good answer, depending on the random start. If a classifier scores poorly, raise epochs and learning_rate before concluding that the model does not fit the data.

What you can change

The fuzzy sets. The library has thirteen membership function families. Smooth ones, such as Gaussian and bell shapes, are the usual choice because their gradients are well behaved. Triangular and trapezoidal shapes are easier to explain to someone outside the field.

Family Class
Gaussian, two-sided Gaussian GaussianMF, Gaussian2MF
Bell BellMF
Triangular, trapezoidal TriangularMF, TrapezoidalMF
Sigmoidal and combinations SigmoidalMF, DiffSigmoidalMF, ProdSigmoidalMF
S and Z shapes SShapedMF, LinSShapedMF, ZShapedMF, LinZShapedMF
Pi shape PiMF

The trainer. Training is separate from the model, so the same network can be fitted in different ways.

Trainer In short
Hybrid SGD + OLS gradient descent on the premises, least squares on the consequents
Hybrid Adam + OLS the same, with Adam doing the gradient part
SGD, Adam, RMSProp gradient descent on every parameter
PSO particle swarm: a population-based search, no gradients

Why the hybrid versions are the default choice is explained in How ANFIS works.

Where the fuzzy sets start. They can be placed on a grid, at random, or by fuzzy c-means clustering of the data.

The exact arguments for all three are in the documentation.

When to reach for something else

ANFIS builds its rules from combinations of fuzzy sets, one membership per input in every rule. That scales well to a handful of inputs and badly to hundreds. For wide data, see highFIS.