Skip to main content

seminr (Python)

A Python port of the seminr R package for structural equation modeling: PLS-SEM (partial least squares) and CBSEM/CFA (covariance-based SEM / confirmatory factor analysis).

The goal is numerical parity with seminr on the bundled mobi dataset — 1e-5 against R-generated golden fixtures for PLS quantities, and tiered tolerances for CBSEM (which reimplements lavaan's ML/MLR estimator from scratch, matching lavaan 0.6-21). The public API mirrors seminr's R names.

Built one vertical slice at a time; the port is now functionally complete.

Installation

pip install seminr          # or: uv add seminr
pip install "seminr[pandas]"  # optional: pandas DataFrame input + .to_dataframe()

Requires Python 3.11+. Runtime dependencies are NumPy and SciPy only.

Status

Functionally complete. The full non-plotting seminr surface is implemented and matches seminr on the bundled mobi dataset (1e-5 for PLS quantities; tiered tolerances for CBSEM):

  • Specification DSL — constructs, composite/reflective/higher-order composites, all three interaction methods (product-indicator, orthogonal, two-stage) and quadratic terms, item-error associations, as_reflective / higher_reflective, and csem2seminr / lavaan2seminr syntax import.

  • PLS-SEMestimate_pls (PLSc for reflective constructs, two-stage higher-order constructs, interactions), bootstrap_model (with t-values, percentile CIs, mediation helpers), and rerun.

  • Assessmentsummarize() for every model kind, reliability (alpha / rhoA / rhoC / AVE), validity (HTMT, Fornell-Larcker, cross-loadings, VIFs), f², AIC/BIC, and descriptives.

  • PLSpredict (predict_pls, direct predict) and PLS-MGA (estimate_pls_mga).

  • CBSEM / CFAestimate_cbsem / estimate_cfa, a from-scratch ML/MLR estimator matching lavaan::sem/cfa(std.lv=TRUE): LISREL model, analytic gradient, ~21 fit measures, Huber-White robust SEs, Yuan-Bentler-Mplus scaled test, and ten Berge factor scores.

  • Plottingplot(model) path diagrams (Graphviz DOT, string-identical to seminr's) for specified/estimated/bootstrapped PLS models, net-new CBSEM/CFA diagrams, plot_htmt, themes, save_plot, and the matplotlib statistical plots (plot_scores, plot_reliability_table, plot_interaction / slope_analysis, plot_predict_error).

Bootstrap, PLSpredict, and MGA accept an opt-in cores= argument for multiprocess parallelism. See .claude/plans/PLAN.port-seminr.md for the full slice-by-slice history and .claude/FUTURE.md for deferred items.

Usage

from seminr import (
    constructs, composite, multi_items,
    relationships, paths, interaction_term,
    estimate_pls, bootstrap_model,
)

# The ECSI mobi dataset ships with the package:
from seminr.datasets import load_mobi
mobi = load_mobi()
# ...or bring your own as a pandas DataFrame or a (column_names, 2-D array) pair.

measurement_model = constructs(
    composite("Image", multi_items("IMAG", [1, 2, 3, 4, 5])),
    composite("Expectation", multi_items("CUEX", [1, 2, 3])),
    composite("Satisfaction", multi_items("CUSA", [1, 2, 3])),
    interaction_term("Image", "Expectation"),  # a product-indicator moderation
)

structural_model = relationships(
    paths(["Image", "Expectation", "Image*Expectation"], "Satisfaction"),
)

model = estimate_pls(mobi, measurement_model, structural_model)
image_path = model.path_coef.get("Image", "Satisfaction")   # path coefficient
r2 = model.r_squared.get("Rsq", "Satisfaction")             # structural R-squared

# Bootstrap for standard errors and t-values (see the reproducibility note below).
boot = bootstrap_model(model, nboot=200, seed=123)
boot_sd = boot.paths_descriptives.get("Image", "Satisfaction Boot SD")
t_value = image_path / boot_sd

Result matrices are NamedMatrix values: index them by row/column name with .get(row, col), or reach the underlying float64 array via .values.

Plotting

Install the plotting extra for batteries-included rendering (pygraphviz wheels bundle Graphviz; matplotlib powers the statistical plots):

pip install "seminr[plot]"
from seminr import plot, plot_htmt, save_plot, seminr_theme_dark

p = plot(model)             # a SeminrPlot: displays inline in Jupyter
p.dot                       # the raw Graphviz DOT source (no renderer needed)
p.save("model.png")         # or .svg / .pdf / .dot / ...
save_plot("model.pdf")      # saves the last plot, as in R

plot(boot, alpha=0.05)                    # bootstrapped: stars + CIs on edges
plot(measurement_model)                   # specification-only preview
plot(model, theme=seminr_theme_dark())    # themed (default/academic/smart/dark)
plot_htmt(boot)                           # HTMT discriminant-validity network

The generated DOT is string-identical to R seminr's dot_graph() (verified against R-generated fixtures), so diagrams render exactly like seminr's. CBSEM/CFA diagrams are a net-new design on the same engine (R delegates those to semPlot): standardized loadings/paths plus dashed covariance arcs. Without a renderer, plot() still works — the .dot source is always available.

The matplotlib set mirrors seminr's base-R statistical plots and returns matplotlib figures: plot_scores(model), plot_reliability_table(...), plot_interaction(model, "Image*Expectation", "Satisfaction") / slope_analysis(...), and plot_predict_error(summarize(prediction), "CUSA1").

Examples

  • notebooks/getting-started.ipynb — a rendered walkthrough of the full PLS workflow on the ECSI mobi dataset (specify → estimate → inspect → plot, plus bootstrapping and HTMT). It renders inline on GitHub, so you can read it without running anything. Start here.
  • demos/ — runnable scripts for each model family (PLS, PLSc, higher-order, interactions, MGA, PLSpredict, CBSEM/CFA, and plotting).

Attribution

  • seminr (R, GPL-3.0) by Soumya Ray, Nicholas Danks, and contributors — the authoritative reference for behavior and the source of every golden fixture in this repository.
  • seminr-ts (TypeScript, GPL-3.0) — a completed, fixture-verified port of the same package. Its module layout, algorithm digests, and fixtures are reused directly here.

Bootstrap reproducibility

bootstrap_model(model, nboot=..., seed=...) uses a default resampler backed by NumPy's Generator(PCG64(seed)). It is deterministic within Python for a given seed, but it is not identical to seminr's R Mersenne-Twister resampling, so its replication indices — and therefore the resulting bootstrap descriptives — differ from R even at the same nominal seed. For exact parity with a specific R run, inject the resample indices directly: bootstrap_model(model, nboot=n, indices=matrix), where matrix is an nboot x n array of 0-based row indices (the parity tests feed R's exported index matrix this way). A custom resampler can also be supplied. This mirrors the seminr-ts port's decision (its plan Q3/Q5).

Performance

The numerical kernel is backed by NumPy/SciPy (BLAS), so estimation, bootstrap, PLSpredict, and MGA run faster than seminr's R implementation on the mobi benchmarks — including seminr's own optimized branch — with no hand-tuned Python. bootstrap_model, predict_pls, and estimate_pls_mga accept an opt-in cores=N argument that fans replications/folds/groups out across processes; results are bit-identical to the sequential path. Note that on small models (like mobi, where a single estimation is sub-millisecond) the process pool's start-up and pickling overhead can make cores= slower than the default sequential path — reach for it when nboot, the sample size, or the per-replication cost is large enough to amortize that overhead. The measurement harness lives in benchmark/.

License

GPL-3.0-only, as a derivative work of the GPL-3 seminr package.

Download files

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

Source Distribution

seminr-0.2.1.tar.gz (1.4 MB view details)

Uploaded Source

Built Distribution

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

seminr-0.2.1-py3-none-any.whl (168.0 kB view details)

Uploaded Python 3

File details

Details for the file seminr-0.2.1.tar.gz.

File metadata

  • Download URL: seminr-0.2.1.tar.gz
  • Upload date:
  • Size: 1.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for seminr-0.2.1.tar.gz
Algorithm Hash digest
SHA256 68fc863c03db7aef2dce1f3accdcc9ed87cc130c3fb28d6f3ed755a1bb668d63
MD5 bc8d7fa610d099576a0042630f137420
BLAKE2b-256 82f8fb5fe8d34ad9adf80f2c558f508368876a2e27224b5150347dacd9b6daf3

See more details on using hashes here.

Provenance

The following attestation bundles were made for seminr-0.2.1.tar.gz:

Publisher: release.yml on sem-in-r/seminr-py

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

File details

Details for the file seminr-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: seminr-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 168.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for seminr-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 8ce37113ddaa7792822c23d3c8346309c3af2df3cd0cd055627f02a64d265454
MD5 1361e2d2fea1123803a235fe4c5df1de
BLAKE2b-256 bb19f1cdbbad2a5094285ea711a787b6451d9e46ddde25e9d3f71c1bf12245a2

See more details on using hashes here.

Provenance

The following attestation bundles were made for seminr-0.2.1-py3-none-any.whl:

Publisher: release.yml on sem-in-r/seminr-py

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

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 files

0.2.0

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page