Skip to main content

python-som

CI PyPI Python versions License: MIT

Implementation of Kohonen's 2-D self-organizing map. NumPy is the only dependency. Accepts NumPy arrays, pandas DataFrames, polars, pyarrow, and anything else implementing the __array__ protocol.

Documentation · Changelog

Install

pip install python-som                  # requires Python 3.10+; NumPy is the only dependency
pip install "python-som[cli]"           # adds tqdm progress bars
pip install "python-som[sklearn]"       # adds the scikit-learn estimator adapter
pip install "python-som[examples]"      # adds matplotlib and seaborn, for the plots

Quick start

import numpy as np
import python_som

rng = np.random.default_rng(0)
data = rng.normal(size=(150, 4))

som = python_som.SOM(x=20, y=None, input_len=4, data=data, random_seed=42)
som.weight_initialization(mode="linear", data=data)
error = som.train(data, n_iteration=len(data), mode="batch")

umatrix = som.distance_matrix()
winner = som.winner(data[0])

The same map through the estimator interface, which Pipeline and GridSearchCV also understand:

som.fit(data, n_iteration=len(data), mode="batch")
labels = som.predict(data)  # (n_samples,) flat node index
distances = som.transform(data)  # (n_samples, x*y)

som.save_npz("map.npz")  # models plus provenance, no pickle
som = python_som.SOM.load_npz("map.npz")

A full worked example with plots is in examples/iris.py and in the getting-started guide.

U-matrix of a SOM trained on Iris

Features

  • NumPy is the only runtime dependency; a fresh install is 69 MB across one package
  • Batch training 23x to 31x faster than MiniSom and 26x to 94x faster than SOMPY, measured
  • Optional numba acceleration: pip install numba and it is used automatically
  • Stepwise and batch training
  • Random, random-sampling and linear (PCA) weight initialization
  • Automatic selection of the map size ratio, from PCA
  • Cyclic arrays, for toroidal maps
  • Gaussian, bubble and Mexican hat neighborhood functions
  • Custom decay functions
  • Save and load a trained map without pickle, so loading one cannot execute code
  • Provenance: every run records its seed, iteration count, error and library versions
  • Works as a scikit-learn estimator: fit, transform, predict, and an adapter for Pipeline, GridSearchCV and cross_val_score
  • Options accepted as plain strings or enums, with typos caught by a type checker
  • Visualization support: U-matrix, activation matrix
  • Supervised labelling, via the label map
  • Fully type-annotated, with a py.typed marker

Neighborhood functions

All three are functions of the distance between two nodes in the grid, sqdist(c, i) in Eq. (5) of Kohonen (2013).

Name Shape Notes
'gaussian' exp(-r² / 2σ²) Strictly positive, monotonically decreasing. The default.
'bubble' 1 for max(dx, dy) ≤ σ, else 0 The truncated inner lobe of the Mexican hat. Uses the Chebyshev metric, so the region is a square.
'mexicanhat' (1 - u)·exp(-u), u = r² / 2σ² Excitatory near the winner, inhibitory beyond it. Zero at r = √2·σ, minimum -e⁻² at r = 2σ.

The Mexican hat takes negative values, so it cannot be used with mode='batch': the batch update of Kohonen Eq. (8) is a weighted mean whose denominator is not sign-definite for a signed neighborhood function. Use mode='random' or mode='sequential'; mode='batch' raises a ValueError.

See Neighborhood functions for the derivations, including why the Mexican hat is not an outer product of two 1-D wavelets.

Upgrading

Two releases change numerical results. If you are reproducing a figure, pin the version that made it.

0.3.0 corrects several methodology defects, so results are not comparable with earlier versions. In particular random_seed no longer reproduces pre-0.3.0 maps: the generator is now per-instance rather than a call to np.random.seed on NumPy's global state. To reproduce older figures, pin python-som==0.2.0.

0.4.0 corrects linear initialization for data far from the origin. Its PCA previously went through scikit-learn's auto solver, which forms a covariance matrix and loses precision when the mean is large relative to the spread. On data offset by 1e7 the second explained variance was wrong by 5.8%. Near the origin the difference is floating-point noise. Timestamps, coordinates and absolute sensor readings are the cases that were affected.

0.4.0 also removed pandas and scikit-learn as runtime dependencies. If you imported either transitively through this package, depend on them directly, or install python-som[examples].

0.5.0 briefly made plain-string options emit a DeprecationWarning. 0.6.0 withdrew that: strings are permanent and 1.0.0 will not remove them. If you saw that warning, you can stop migrating.

0.7.0 makes batch training 20x to 40x faster by reorganising the same arithmetic. Because the sums happen in a different order, trained weights differ from 0.6.1 by about 1e-15 relative. That is far below anything a result depends on, and it does break an exact-equality check against a stored map: pin python-som==0.6.1 if you need one to match bit for bit. It also removes the neighborhood kernel helpers from the private python_som._core, which had no callers outside the package.

Each change and the passage of Kohonen (2013) behind it is in the changelog.

Development

uv sync --all-extras
uv run pytest --cov          # tests and coverage
uv run ruff check .          # lint
uv run ruff format --check . # formatting
uv run mypy                  # type-check
uv run bandit -c pyproject.toml -r src/   # security checks
uv run pip-audit             # known vulnerabilities in the resolved set
uv run mkdocs serve          # docs, locally
pre-commit install           # optional, run the gates on commit

numba is not a declared extra: uv resolves every extra into one lockfile, so declaring it would cap NumPy below 2.5 for the whole project. Install it alongside when working on the accelerated path, with uv run --with numba pytest tests/test_numba_kernel.py.

If you use the SonarQube for IDE (SonarLint) VS Code extension, it will also apply Sonar's Python rules locally; the ruff configuration is set up to cover most of the same ground.

Benchmarks

Hand-run, never part of the test suite: a timing assertion on shared hardware measures noise.

uv run python benchmarks/bench_vs_minisom.py   # vs MiniSom, agreement verified before timing
cd asv_benchmarks && uv run --extra bench asv continuous master HEAD   # this package across commits

Results and the method behind them are in Comparison with MiniSom and SOMPY. The SOMPY comparison needs an interpreter of its own, since SOMPY cannot be imported on NumPy 2; benchmarks/bench_vs_sompy.py prints the setup command and installs nothing.

References

Based on:

Teuvo Kohonen, Essentials of the self-organizing map, Neural Networks, Volume 37, 2013, Pages 52-65, ISSN 0893-6080, https://doi.org/10.1016/j.neunet.2012.09.018

The Mexican hat neighborhood follows the lateral-interaction formulation in:

O. J. Vrieze, Kohonen network, in: Artificial Neural Networks: An Introduction to ANN Theory and Practice, Lecture Notes in Computer Science, Volume 931, Springer, Berlin, Heidelberg, 1995, Pages 83-100, https://doi.org/10.1007/BFb0027024

License

MIT. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_som-0.7.0.tar.gz (193.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

python_som-0.7.0-py3-none-any.whl (53.2 kB view details)

Uploaded Python 3

File details

Details for the file python_som-0.7.0.tar.gz.

File metadata

  • Download URL: python_som-0.7.0.tar.gz
  • Upload date:
  • Size: 193.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for python_som-0.7.0.tar.gz
Algorithm Hash digest
SHA256 6a555c79e7a4b119065e42cb03d002fa464abae67ca87f5ebeccd8097773b806
MD5 0874f9b5b9eb649353a4ae8b26cc983e
BLAKE2b-256 1af0736885ed797a4130ca4fd33496b783a72d31c740096a7f8cae196ca9340a

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_som-0.7.0.tar.gz:

Publisher: release.yml on andremsouza/python-som

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_som-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: python_som-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 53.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for python_som-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cdb1dabca5e6675f3adb3df0ef9b91f90cd25141ac32893fff387469fc6960bd
MD5 ac8929b1957b6ab6895d134ce568ba35
BLAKE2b-256 0a719de5330ccf8df1b2a20ffc7747c237fbd94d82ac50fd88f80cfe8c34b49f

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_som-0.7.0-py3-none-any.whl:

Publisher: release.yml on andremsouza/python-som

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.8.0

2 files

This release

0.7.0 This release

2 files

0.6.1

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.0

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page