pyfsda
Call FSDA — the MATLAB Flexible Statistics and Data
Analysis toolbox for robust statistics — from Python, using the MATLAB Engine as the
computational backend. FSDA runs unmodified in MATLAB; pyfsda is a thin, routine-agnostic bridge
that marshals data across the boundary.
Call any FSDA routine as a plain Python function — the MATLAB session starts on first use and is reused:
import pyfsda
d = pyfsda.mahalFS(Y, MU, SIGMA) # numeric array -> numpy ndarray
out = pyfsda.Score(y, X, la=la, intercept=True) # struct -> dict (MATLAB-style options)
RAW, REW = pyfsda.mcd(Y, nargout=2) # two outputs -> tuple
pyfsda.stop() # optional; also runs automatically at exit
pyfsda.<name> works for any FSDA function (from pyfsda import Score works too). Prefer managing
the session yourself? Use the explicit engine:
from pyfsda import FsdaEngine
eng = FsdaEngine.start("mahalFS")
d = eng.call("mahalFS", Y, MU, SIGMA)
eng.stop()
Requirements
pyfsda does not bundle MATLAB or FSDA — it drives your local install. You need:
- MATLAB with the FSDA Add-On installed and on the MATLAB path (verify
which mahalFSinside MATLAB). matlabenginematching your MATLAB release. This is the one version constraint that matters: thematlabenginepackage on PyPI is release-locked, so install the one that pairs with your MATLAB — e.g.pip install "matlabengine==26.1.*"for R2026a.pyfsdalistsmatlabengineas a dependency but deliberately does not pin it, so it will not clobber a matching version you already have.- Python 3.9–3.13 (whatever your MATLAB release's engine supports).
Install
pip install pyfsda
# then, if not already present, the matlabengine that matches YOUR MATLAB:
pip install "matlabengine==26.1.*" # example: MATLAB R2026a
Verify your install
Run examples/smoke_test.py — it starts MATLAB and checks a few real FSDA
routines against numpy oracles, printing RESULT: PASS when your MATLAB + FSDA + matlabengine setup
is good:
python smoke_test.py # or: python smoke_test.py /path/to/FSDA
For a worked, MATLAB-style example, see examples/score_example.py — the
Box-Cox Score test on the wool dataset, calling Score(y, X, 'la', ..., 'intercept', true) the same
way you would in MATLAB.
What crosses the boundary
call(name, *args, nargout=1, echo_output=False, options=None, **kwargs) marshals positional
arguments in order and keyword arguments (and any options dict) as MATLAB name/value pairs. It runs
through the MATLAB workspace so outputs the engine cannot return directly (tables, 2-D cells) are
decoded MATLAB-side.
| MATLAB value | crosses as |
|---|---|
| numeric / logical array | numpy.ndarray (natural shape, NaN/Inf preserved) |
struct |
dict (recursed) |
char / string scalar |
str |
cell |
list |
table / timetable |
dict {VariableNames, RowNames/RowTimes, data, height} |
2-D cell |
nested list |
nargout > 1 |
tuple of the above |
graphics handle (matlab.graphics.*) |
not marshalled — request only data outputs |
Conventions: a 1-D input crosses as a MATLAB row (pass an (n, 1) array for a column); outputs
keep MATLAB's natural shape (no silent reshape); MATLAB indices stay 1-based.
Reserved keywords consumed by the bridge are only nargout, echo_output, options, and frames;
every other keyword is forwarded to MATLAB (so FSDA's own msg option passes straight through).
echo_output=True tees MATLAB's stdout/stderr to your terminal.
Optional pandas view (pip install pyfsda[pandas])
pandas is an optional dependency — import pyfsda works without it. When it is installed you get a
DataFrame view over MATLAB tables, on the Python side only (the neutral dict stays the default and
remains the cross-language contract):
- Output: pass
frames=Trueto receivetable/timetableoutputs as apandas.DataFrame(index fromRowNames/RowTimes) — e.g.out = pyfsda.univariatems(y, X, frames=True). The public helperpyfsda.to_dataframe(table_dict)converts a dict you already have. - Input: pass a
pandas.DataFrameargument and it is marshalled to a MATLABtable(array2table, column names and any non-default index preserved). v1 covers numeric/logical columns; string/categorical/datetime columns raise a clearNotImplementedError.
Requesting frames=True (or passing a DataFrame) without pandas installed raises a clear
pip install pyfsda[pandas] error.
On the first pyfsda.<name>(...) call, pyfsda also prints (once, best-effort) the latest FSDA
release available on GitHub, so you can check your install is current. FsdaEngine.start()
additionally runs a MATLAB-side FSDA up-to-date check via FSDA's tuna utility (quiet unless an update
is available). Both are gated by check_version — silence them with
pyfsda.start(check_version=False) (or FsdaEngine.start(check_version=False)) before the first call.
Notes
- MATLAB engine startup is slow — start one
FsdaEngineand reuse it; alwaysstop()explicitly. - Struct-arrays and
datetime/durationscalars are out of scope for the generic converters.
License
EUPL-1.2 — consistent with FSDA's own licensing.
Metadata
Release files for pyfsda 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyfsda-0.4.0.tar.gz | 32.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyfsda-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 53.6 kB
Release files / pyfsda-0.4.0.tar.gz
| Download URL | pyfsda-0.4.0.tar.gz |
|---|---|
| Size | 32.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b5ea1fe30eddc0beedb29dac5e15c609f79a009ae268018538c7b8df48cbc0b4
|
|
BLAKE2b-256 checksum How to use checksums |
190e279b9e2ccff2b17597674b0973a530e2ba3824fdccf0164737d3eb5e71a9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|
Release files / pyfsda-0.4.0-py3-none-any.whl
| Download URL | pyfsda-0.4.0-py3-none-any.whl |
|---|---|
| Size | 21.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
98d94fe072ab428f58610ec3e0d31262623a5899f57c00a7dd77a52a9cb672b7
|
|
BLAKE2b-256 checksum How to use checksums |
6818060db8cdb395ccbe1471da349f8d915856bb199754c237e257389d1e6f39
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|