Skip to main content

psienced

Small in-house helpers for experimental data — the pieces that otherwise get rewritten at the top of every analysis script.

  • Robust statistics — MAD, standard error, CV, t-based confidence intervals, one-call summaries.
  • Outlier detection — MAD, Tukey/IQR and z-score, with masking that keeps plate positions intact.
  • Rescaling — z-score, robust scale, min–max, percent-of-control, log.
  • Units — case-sensitive conversion across seven dimensions, plus the C1V1 = C2V2 dilution arithmetic.
  • Significant figures — rounding and value ± uncertainty reporting.
  • Uncertainty propagation — a Measurement type that carries error bars through ordinary Python arithmetic.

Everything is NaN-tolerant by default, because missing wells and failed reads are the normal state of bench data rather than an error condition.

Install

pip install -e .

The only runtime dependency is NumPy. For the test suite:

pip install -e ".[test]"

Use

import psienced as ps

readings = [10.1, 9.8, 10.0, 10.3, 45.0, float("nan"), 9.9, 10.2]

ps.outliers_mad(readings)          # -> [F, F, F, F, True, F, F, F]
clean = ps.mask_outliers(readings) # spike becomes NaN, positions preserved

ps.summary(clean)["mean"]          # 10.05  (the 45.0 never reaches it)
ps.confidence_interval(clean)      # (9.85, 10.25)

Outliers

outliers_mad is the default for a reason. The classic mean/SD z-score is included for compatibility with existing protocols, but on the small n typical of replicate sets a single extreme value inflates the SD enough to hide itself:

spiked = [10.0, 10.1, 9.9, 10.2, 9.8, 10.05, 45.0]

ps.outliers_mad(spiked)[-1]      # True  — caught
ps.outliers_zscore(spiked)[-1]   # False — masked by its own effect on the SD

One caveat in the other direction: if more than half the values are identical the MAD is exactly zero and outliers_mad flags nothing at all, even against an obvious spike. outliers_iqr still catches that case.

Use mask_outliers (NaN in place) when position carries meaning — plate wells, time points, paired conditions — and drop_outliers when it does not. outlier_report returns the indices and values for a QC log.

Units

Names are case-sensitive on purpose: mm is millimetres, mM is millimolar, and folding those together is precisely the mistake this module exists to catch. Both micro signs (U+00B5 and U+03BC) are accepted, since which one a file contains depends on the instrument that wrote it.

ps.convert(1.0, "mM", "uM")     # 1000.0
ps.convert(37.0, "C", "F")      # 98.6   (affine, not scaled)
ps.convert(1.0, "mm", "mM")     # ValueError: different physical dimensions

ps.dilution_volume(c1=100.0, c2=5.0, v2=20.0)   # 1.0 mL of stock
ps.molarity_to_mass(0.1, molar_mass=58.44)      # 5.844 g/L NaCl

Uncertainty

absorbance  = ps.Measurement.from_replicates([0.412, 0.408, 0.415])
extinction  = ps.Measurement(6220.0, 30.0)
path_length = ps.Measurement(1.0, 0.005)

concentration = absorbance / (extinction * path_length)
print(concentration.format(unit="M"))       # '0.0000662 +/- 0.0000006 M'

Rendering is fixed-point, so results far from unity read better after rescaling. Multiplying by a plain number scales the error bar with the value:

print((concentration * 1e6).format(unit="uM"))   # '66.2 +/- 0.6 uM'

Two assumptions are built in, and both matter:

  • Independence. Operands are treated as uncorrelated, so m - m reports a nonzero uncertainty even though the answer is exactly zero. Simplify algebraically before wrapping.
  • Linearity. The usual first-order approximation, which degrades once the relative uncertainty passes roughly 10%. Reach for Monte Carlo beyond that.

Reporting

ps.format_measurement(10.14159, 0.523, unit="mM")   # '10.1 +/- 0.5 mM'
ps.format_sig(1.5, 4)                               # '1.500'  (keeps the zeros)

Layout

Module Contents
psienced.stats mad, sem, cv, robust_zscore, confidence_interval, summary
psienced.outliers outliers_mad, outliers_iqr, outliers_zscore, flag_outliers, mask_outliers, drop_outliers, outlier_report
psienced.normalize zscore, robust_scale, minmax, percent_of_control, log_transform
psienced.units convert, known_units, dilution_volume, dilution_factor, molarity_to_mass, mass_to_molarity
psienced.sigfig round_sig, format_sig, round_to_uncertainty, format_measurement
psienced.propagation Measurement, sqrt, log, log10, exp

Every name is re-exported at the top level, so import psienced as ps is enough.

Conventions

  • NaN is ignored, never silently dropped. summary reports n and n_missing separately, and no detector flags a NaN as an outlier — a missing well is an absence, not an anomaly.
  • Sample statistics use ddof=1. A set of replicates is a sample from a process, not a population. Override per call where that is wrong.
  • Shape is preserved. Transforms and masks return arrays shaped like their input, so results can be written back over the raw data.
  • Errors are raised, not guessed at. Mismatched dimensions, impossible dilutions and negative uncertainties fail loudly.

Tests

pytest

The suite covers each module plus doctests, and checks the t-distribution implementation against published critical-value tables.

License

MIT — see LICENSE.

Download files

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

Source Distribution

psienced-0.1.0.tar.gz (26.8 kB view details)

Uploaded Source

Built Distribution

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

psienced-0.1.0-py3-none-any.whl (22.1 kB view details)

Uploaded Python 3

File details

Details for the file psienced-0.1.0.tar.gz.

File metadata

  • Download URL: psienced-0.1.0.tar.gz
  • Upload date:
  • Size: 26.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for psienced-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b48029dca5fcbde5902a39533d30adede1d015d7d15334a0c6f3a60ee1240786
MD5 b31bbd17c24b842e70481d760093e27e
BLAKE2b-256 bb0d353337559fb23e72d9507005dcbd508a43d8349cf0d65d0d3a13e00f1d51

See more details on using hashes here.

File details

Details for the file psienced-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: psienced-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 22.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for psienced-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 43923a8b99b3b4949f51466ffc4158b0aeb00e7fda15c1de9865931a246c8074
MD5 97e170a611e7356f0732f237a8675dea
BLAKE2b-256 8843e9b4e291bd9e165b0d58fb657655f6d3438d5a1ec989fe6d2dccd0cd20f1

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page