Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,29 @@ All notable changes to this project are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.6.1] - 2026-07-30

### Fixed

- **The package description on PyPI now describes the current package.** It had not been updated
since 0.3.0, so it listed none of the features added in 0.4.0, 0.5.0 or 0.6.0: not the drop to
NumPy as the only dependency, not `save_npz`/`load_npz`, not the training reports, and not the
scikit-learn estimator interface that 0.6.0 exists to add.

A PyPI description cannot be edited after upload, so correcting it takes a release. That is the
whole of this one: no code changed, and results are identical to 0.6.0.

The upgrade notes were also short of two things worth knowing. 0.4.0 changes
linear-initialization results for data far from the origin, where the previous PCA path was wrong
by up to 5.8%, and it removed pandas and scikit-learn as runtime dependencies, which matters to
anyone who was importing either transitively. Both are now in the README, alongside a note that 0.5.0's
string deprecation was withdrawn so anyone who saw the warning knows to stop migrating.

## [0.6.0] - 2026-07-30

A map can now be used as a scikit-learn estimator, and the plain-string deprecation from 0.5.0 is
withdrawn. Nothing breaks and no numerical results change: `train` is untouched, both option spellings
work, and scikit-learn remains optional.
withdrawn. Nothing breaks and no numerical results change: `train` is untouched, both option
spellings work, and scikit-learn remains optional.

### Added

Expand Down
50 changes: 44 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ arrays, pandas DataFrames, polars, pyarrow, and anything else implementing the `
## Install

```bash
pip install python-som # requires Python 3.10+
pip install "python-som[cli]" # adds tqdm progress bars
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
Expand All @@ -35,19 +37,36 @@ umatrix = som.distance_matrix()
winner = som.winner(data[0])
```

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

```python
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](https://github.com/andremsouza/python-som/blob/master/examples/iris.py) and in the
[getting-started guide](https://andremsouza.github.io/python-som/tutorial/first-map/).

![U-matrix of a SOM trained on Iris](https://raw.githubusercontent.com/andremsouza/python-som/master/docs/assets/iris.png)

## Features

* NumPy is the only runtime dependency; a fresh install is 69 MB across one package
* 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
Expand All @@ -73,10 +92,27 @@ the derivations, including why the Mexican hat is not an outer product of two 1-

## Upgrading

0.3.0 corrects several methodology defects, so numerical 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 figures
made with an older version, pin `python-som==0.2.0`.
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.

Each change and the passage of Kohonen (2013) behind it is in the
[changelog](https://github.com/andremsouza/python-som/blob/master/CHANGELOG.md).
Expand All @@ -89,6 +125,8 @@ 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
```
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "python-som"
version = "0.6.0"
version = "0.6.1"
authors = [{ name = "André Moreira Souza", email = "msouza.andre@hotmail.com" }]
description = "Python implementation of the Self-Organizing Map"
readme = "README.md"
Expand Down
2 changes: 1 addition & 1 deletion src/python_som/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@

__all__ = ["__version__"]

__version__ = "0.6.0"
__version__ = "0.6.1"
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading