A Python port of the R package sensR for Thurstonian models in sensory discrimination analysis.
sensPy provides a comprehensive Python implementation of sensR, the R package for sensory discrimination methods. This project ensures:
- Numerical parity with sensR (validated against R outputs)
- Modern Python practices (type hints, dataclasses, NumPy/SciPy integration)
- Full test coverage with 500+ tests
# Install with pip
pip install senspy
# Or install from source
git clone https://github.com/aigorahub/sensPy.git
cd sensPy
pip install -e .All standard protocols with single and double variants:
| Protocol | Single | Double |
|---|---|---|
| Triangle | ✅ | ✅ |
| Duo-Trio | ✅ | ✅ |
| 2-AFC | ✅ | ✅ |
| 3-AFC | ✅ | ✅ |
| Tetrad | ✅ | ✅ |
| Hexad | ✅ | - |
| 2-out-of-5 | ✅ | - |
discrim()- D-prime estimation with confidence intervals and p-valuesbetabin()- Beta-binomial model for overdispersed datatwoac()- 2-Alternative Certainty modelsamediff()- Same-different modeldod()- Degree-of-difference modelanota()- A-not-A signal detection model
discrim_power(),dprime_power()- Power analysisdiscrim_sample_size(),dprime_sample_size()- Sample size calculationsamediff_power()- Same-different power (simulation-based)twoac_power()- 2-AC exact powerdod_power()- DOD power analysis
dprime_test()- Test d-prime hypothesesdprime_compare()- Compare d-primes across groupsposthoc()- Post-hoc pairwise comparisons
roc()- ROC curve computationauc()- Area under the ROC curvesdt()- Signal detection theory transforms
discrim_sim()- Simulate discrimination experimentssamediff_sim()- Simulate same-different datadod_sim()- Simulate DOD data
plot_psychometric()- Psychometric functionsplot_roc()- ROC curvesplot_power_curve()- Power curvesplot_profile_likelihood()- Profile likelihood
from senspy import discrim, discrim_power
# Analyze a Triangle test result (80 correct out of 100)
result = discrim(correct=80, total=100, method="triangle")
print(f"d-prime: {result.d_prime:.3f}")
print(f"95% CI: [{result.ci_lower:.3f}, {result.ci_upper:.3f}]")
print(f"p-value: {result.p_value:.4g}")
# Calculate power for a future test
power = discrim_power(d_prime=1.5, sample_size=100, method="triangle")
print(f"Power: {power:.1%}")from senspy import samediff, dprime_compare
# Same-different analysis
sd = samediff(nsamesame=45, ndiffsame=5, nsamediff=20, ndiffdiff=30)
print(f"delta: {sd.delta:.3f}, tau: {sd.tau:.3f}")
# Compare d-primes across products
result = dprime_compare(
correct=[80, 65, 90],
total=[100, 100, 100],
method="triangle"
)
print(f"Chi-square: {result.statistic:.2f}, p={result.p_value:.4f}")This project is licensed under the GNU General Public License version 2.0 or later. See LICENSE for details.
If you use sensPy in your research, please cite:
@software{senspy,
title = {sensPy: Python port of sensR for Thurstonian models},
author = {Aigora},
year = {2025},
url = {https://github.com/aigorahub/sensPy}
}This package is a port of sensR by Per Bruun Brockhoff and Rune Haubo Bojesen Christensen.