About this Project
This repository is an updated version of the open-source Factor Snob program for Mixture modelling by Minimum Message Length (MML) written in C. The original source code was obtained from Lloyd Allison's website at: http://www.allisons.org/ll/MML/Notes/SNOB-factor/. The goal of this project is to make the program more accessible by providing a Python interface to the program. The original program was written in C and compiled to a binary executable.
I have made many changes to the code mainly to improve readability, and to fix some minor bugs I discovered. The current version produces the same output as the original, except for a couple of display bugs present in the original version (see below). Here is a summary of the changes:
- Refactored function declarations into a central "snob.h" include file.
- Previous version included "glob.c" within other files. "glob.c" now contains some generic and exported functions.
- Replaced Old-style C-function prototypes with moder C function prototypes.
- Removed as many global variables as possible and eliminated many side effects. The previous version relied too much on
side effects and global variables. The current version has made variable passing more explicit. In some cases where global variables are still used, they have been grouped into global structures instead. This should make it easier to eliminate them entirely in the future. There is still plenty of room for improvement. - Refactored many functions to replace
gotostatements with more modern control structures. - Replaced many print statements with a logging facility that can be dialed down using a debug level.
- Added functions for printing a summary of the existing sample data
- Added functions for generating a JSON representation of the classification result equivalent to the data produced by
the
prclasscommand. - Added functions for generating class assignments to the sample items. Also, useful for classification through Python.
- Fixed a bug in which during printing of Class information, the wrong class pointer was used to calculate one of the Factor costs. This is why the total costs for the Factor model did not match the sum of the parameter, data and variable costs. It also affected the display of the boost character on the class header information.
- Added functions to allow loading
vsetand Sample data through function calls rather than from file. This allowsvsetand sample information to be supplied through Python ctypes calls. - Added functions to allow saving and loading of the population model to and from file. This allows the population model to be saved and loaded through Python ctypes calls.
- Added a Scikit-learn style interface for fitting and predicting using the Factor Snob model. This allows the model to be used in a similar way to other Scikit-learn classification models. The features include the ability to save fitted models and to predict on new data based on previously saved models.
- Added a python module that can provide the data, run the Factor Snob routines and extract the results within Python,
using
ctypes.
The original documentation file is included in the docs folder. It contains a lot of useful information about the
original SNOB programs and may be useful for understanding some of the input and output parameters.
Any published work using this software should cite the original author's work as well as this repository. See the
The MML Book
[1] C. S. Wallace, Statistical and Inductive Inference by Minimum Message Length, Springer, isbn-13:978-0-387-23795-4, 2005.
Using the Python Module
The Python module can be installed using pip as follows:
pip install snob-factor
The module can be used in a similar way to other Scikit-learn classification models. The following example shows how to use the module to fit a Factor Snob model to some sample data and then use the model to predict the class of some new data.
import pandas as pd
import snob
# Load the sample data
train = pd.read_csv('train.csv')
sfc = snob.SNOBClassifier(
name='sst',
attrs={ # these are the features of the data
'distance': 'real', # a real-valued attribute
'theta': 'radians', # an angle in radians angles are treated specially
'phi': 'radians', # another angle in radians
},
cycles=3, # maximum number of cycles to run
steps=40, # maximum number of estimation/assignment steps to run
moves=2, # maximum number of failed class shuffles before giving up each cycle
tol=0.01, # minimum percentage improvement in cost to indicate convergence
seed=1234567 # random number seed
)
# Fit the model to the sample data
sfc.fit(train)
sfc.save_model('sst.mod') # save the model to a file for use later
classes = sfc.get_classes() # get the class parameters for the fitted model
snob.show_classes(classes) # display the classification summary
# get class assignments for training data
train_pred = sfc.predict() # assignments the training data, note that predict is called without arguments
print(train_pred) # train_pred is a pandas DataFrame with the class assignments
# Load some new data to predict
test = pd.read_csv('test.csv')
# Predict the class of the new data
test_pred = sfc.predict(test)
print(test_pred)
The SNOBClassifier class has a number of parameters that can be used to control the behaviour of the model. The
attrs parameter is a dictionary that defines the features of the data. The keys are the names of the features and the
values are the types of the features. The types can be one of the following:
- 'real' - a real-valued feature
- 'radians' - an angle in radians
- 'degrees' - an angle in degrees
- 'multi-state' - a categorical feature with more than two but preferably fewer than 20 states
- 'binary' - a boolean or two-valued feature
Since SNOBClassifier is an unsupervised learning model, the fit() method does not require a target variable. The
fit() method takes a pandas DataFrame as input. The DataFrame must contain columns for each of the features defined in
the attrs parameter. The fit() method will run the Factor Snob algorithm on the data and produce a classification
model for the data. After fitting, the classifier will be fully parameterized and can be used to predict the classes of
new data.
The get_classes() method of a fully parameterized classifier can be used to get the class parameters for the fitted
model. This returns a list of dictionaries with each dictionary representing one class. The show_classes() function from
the snob package can be used to display a summary of the class parameters. The show_classes() function takes the list
of class dictionaries as returned by the get_classes() method.
The model can be saved to a file using the save_model(). This method takes a single argument which is the name of the
file to save the model to. A previously saved model, can be used by specifying a from_file parameter during
initialization of the classifier. The from_file parameter should be set to the name of the file containing the saved
model. The attrs parameter is always required even when a from_file parameter is provided. The attrs parameter
should be the same as the one used to create the saved model.
The predict() method can then be used to predict the class of new data. The first time a restored model is used to
for prediction, the model will be loaded into memory and used to fully parameterize the classifer before prections
are performed. Details of class parameters will only be available after the classifer is fully parameterized.
The predict() method takes a pandas DataFrame as input. The DataFrame must contain columns for each of the features.
For example, the model above can be loaded from the saved model file and used as follows:
sfc = snob.SNOBClassifier(
name='sst',
attrs={ # these are the features of the data
'distance': 'real', # a real-valued attribute
'theta': 'radians', # an angle in radians angles are treated specially
'phi': 'radians', # another angle in radians
},
from_file='sst.mod' # load the model from the file
)
new_data = pd.read_csv('new_data.csv')
new_pred = sfc.predict(new_data) # No need to run fit again, the model will be loaded from the file
class_info = sfc.get_classes() # must run predict first to fully parameterize the model
snob.show_classes(class_info)
print(new_pred)
Description:
This program implements an unsupervised classification (or clustering) algorithm based on the Minimum Message Length (MML) principle. The fundamental goal is to find the best model to explain the structure of your data, where "best" means the model that allows for the most compact description of the data.
The total "message length" is the sum of two parts:
- Part 1: The Model Cost: The length of the message required to describe the classification model itself (i.e., the number of classes and all their parameters).
- Part 2: The Data Cost: The length of the message required to describe the data, given the model.
The algorithm works as a two-level iterative process to find the model that minimizes this total message length.
- The Outer Loop: Model Discovery ("Surgery")
This is the high-level search for the optimal number of classes and their relationships. The algorithm starts with an initial set of classes and then iteratively tries to improve the model by performing "surgical" operations:
- Splitting: A single class is split into two.
- Merging: Two classes are merged into one.
- Deleting: An entire class is removed.
After each operation, the algorithm re-evaluates the total message length. The change is only kept if it results in a shorter, more efficient explanation of the data.
- The Inner Loop: Parameter Estimation (like E-M)
For any given set of classes, the algorithm must find the optimal parameters for them. This inner loop is very similar to the well-known Expectation-Maximization (E-M) algorithm:
- Assignment Step (like "E-Step"): For each data point, the algorithm calculates the probability that it belongs to each of the current classes. This is a "soft" assignment.
- Update Step (like "M-Step"): The parameters of each class (e.g., the mean and standard deviation for a Gaussian attribute, or the probabilities for a categorical attribute) are recalculated based on the weighted collection of data points assigned to them in the previous step.
This inner loop repeats until the class parameters and assignments stabilize.
The "Factor" in Snob Factor
This is not just a simple mixture model. Within each class, it can also model the covariance between attributes using a latent factor. This is a hidden, continuous variable that can influence multiple attributes simultaneously. By using a factor, the model can explain correlations between variables within a class, leading to a more powerful and compact model (i.e., a shorter message length) than if all attributes were assumed to be independent.
Metadata
Release files for snob-factor 2026.4.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| snob_factor-2026.4.5.tar.gz | 1.0 MB | With provenance | Details for snob_factor-2026.4.5.tar.gz |
Built distributions (wheels)
Total release size: 2.0 MB
Release files / snob_factor-2026.4.5.tar.gz
| Download URL | snob_factor-2026.4.5.tar.gz |
|---|---|
| Size | 1.0 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
243cf01ddc081b3da0952e86ba44f79f7fe6b11982d3689854b4717f9d9b87fd
|
|
BLAKE2b-256 checksum How to use checksums |
5cb9ca720afa065e20e6c9bc33c679631b3fb236305327faffa4eea35bc5dc91
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 19, 2026.
Transparency logRelease files / snob_factor-2026.4.5-cp314-cp314-win_amd64.whl
| Download URL | snob_factor-2026.4.5-cp314-cp314-win_amd64.whl |
|---|---|
| Size | 138.6 kB |
| Tags | CPython 3.14 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
c13147499f7f60aa8aed87ca585b0370eab08ecf566f200fda553519520f1b0b
|
|
BLAKE2b-256 checksum How to use checksums |
67c0d3145444838a542ec049c611d4b3b5b4b05f3b9b5cb1cf2c121ce6f2789e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 19, 2026.
Transparency logRelease files / snob_factor-2026.4.5-cp314-cp314-macosx_15_0_arm64.whl
| Download URL | snob_factor-2026.4.5-cp314-cp314-macosx_15_0_arm64.whl |
|---|---|
| Size | 119.9 kB |
| Tags | CPython 3.14 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
8bd647868a199ecb7c4a71ee3d1a575aaacdf122a3d0f0d40c3cc88f336e3df0
|
|
BLAKE2b-256 checksum How to use checksums |
7799c2932b9371e1781b80535a8c805ee1f7e17f9d5cc1bd9e85769de55d4713
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 19, 2026.
Transparency logRelease files / snob_factor-2026.4.5-cp313-cp313-win_amd64.whl
| Download URL | snob_factor-2026.4.5-cp313-cp313-win_amd64.whl |
|---|---|
| Size | 133.3 kB |
| Tags | CPython 3.13 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
5daa04ab471626c46e3290d212685083498317af91bf74cf4d27c52e813ef588
|
|
BLAKE2b-256 checksum How to use checksums |
ac0e12d92fa07c37a39fffc2c546f45e9007bd785a6703086a5eb0931bb3f433
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 19, 2026.
Transparency logRelease files / snob_factor-2026.4.5-cp313-cp313-macosx_15_0_arm64.whl
| Download URL | snob_factor-2026.4.5-cp313-cp313-macosx_15_0_arm64.whl |
|---|---|
| Size | 119.9 kB |
| Tags | CPython 3.13 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
29cca2fcc2678448fdae30d3c0a7b4a5f9fa704aa820cda38e5b953782a75125
|
|
BLAKE2b-256 checksum How to use checksums |
5958779535d7b97dfa9b43135d0f27ce96faebeda55cdb00253c1ffa13b4856c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 19, 2026.
Transparency logRelease files / snob_factor-2026.4.5-cp312-cp312-win_amd64.whl
| Download URL | snob_factor-2026.4.5-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 133.3 kB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
51a43bfb092ad956706bc08a02c0c7d96ccb36af18184577cced3e92eb22a3dd
|
|
BLAKE2b-256 checksum How to use checksums |
d7b8550f5072cf99c74de09f30bac2b08894edfe0cc7c3bb173d4486fe75a7f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 19, 2026.
Transparency logRelease files / snob_factor-2026.4.5-cp312-cp312-macosx_15_0_arm64.whl
| Download URL | snob_factor-2026.4.5-cp312-cp312-macosx_15_0_arm64.whl |
|---|---|
| Size | 119.9 kB |
| Tags | CPython 3.12 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
364ea251ce2aec371c30c132f55c525afe700ed22ba0ea9ac7053fdbaf94df8d
|
|
BLAKE2b-256 checksum How to use checksums |
016863d44a544ede91bc7c6a0eb6a2acc19ed659c64d764834d86d2a46a8e3dd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 19, 2026.
Transparency logRelease files / snob_factor-2026.4.5-cp311-cp311-win_amd64.whl
| Download URL | snob_factor-2026.4.5-cp311-cp311-win_amd64.whl |
|---|---|
| Size | 133.3 kB |
| Tags | CPython 3.11 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
dd2bb7ca87a279bcb66475bfe51e9c32d3ea17e2beacdeb44c346769c2159e15
|
|
BLAKE2b-256 checksum How to use checksums |
2411a1729d420d53a8fa992393e9a9c454b30b2617825d05469de5a283cff32e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 19, 2026.
Transparency logRelease files / snob_factor-2026.4.5-cp311-cp311-macosx_15_0_arm64.whl
| Download URL | snob_factor-2026.4.5-cp311-cp311-macosx_15_0_arm64.whl |
|---|---|
| Size | 119.9 kB |
| Tags | CPython 3.11 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
2ca4e7af376a2241feebc914e31f84f0be88b2b1903b1bf810db899b61b69122
|
|
BLAKE2b-256 checksum How to use checksums |
0e94eada7af41061adcbc0cc6e4f293a428a0f4517a5e3ca35b11ca4c03da02a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 19, 2026.
Transparency logSecurity for snob-factor 2026.4.5
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 9 files in this release have been uploaded with provenance metadata.
Attestation for snob_factor-2026.4.5.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 19, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.