monopoly-polysome 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- monopoly_polysome-0.1.0/.gitignore +16 -0
- monopoly_polysome-0.1.0/CHANGELOG.md +11 -0
- monopoly_polysome-0.1.0/CITATION.cff +12 -0
- monopoly_polysome-0.1.0/CONTRIBUTING.md +21 -0
- monopoly_polysome-0.1.0/LICENSE +21 -0
- monopoly_polysome-0.1.0/PKG-INFO +188 -0
- monopoly_polysome-0.1.0/README.md +155 -0
- monopoly_polysome-0.1.0/STYLE.md +45 -0
- monopoly_polysome-0.1.0/benchmarks/README.md +73 -0
- monopoly_polysome-0.1.0/benchmarks/__init__.py +2 -0
- monopoly_polysome-0.1.0/benchmarks/configs/preflight.json +68 -0
- monopoly_polysome-0.1.0/benchmarks/configs/publication_count_models.json +162 -0
- monopoly_polysome-0.1.0/benchmarks/configs/publication_equal_n20.json +32 -0
- monopoly_polysome-0.1.0/benchmarks/configs/publication_fracfixr.json +96 -0
- monopoly_polysome-0.1.0/benchmarks/configs/smoke.json +55 -0
- monopoly_polysome-0.1.0/benchmarks/methods.py +349 -0
- monopoly_polysome-0.1.0/benchmarks/metrics.py +499 -0
- monopoly_polysome-0.1.0/benchmarks/r/install.R +132 -0
- monopoly_polysome-0.1.0/benchmarks/r/requirements.tsv +6 -0
- monopoly_polysome-0.1.0/benchmarks/r/run_comparators.R +449 -0
- monopoly_polysome-0.1.0/benchmarks/results/README.md +31 -0
- monopoly_polysome-0.1.0/benchmarks/run.py +820 -0
- monopoly_polysome-0.1.0/benchmarks/simulate.py +482 -0
- monopoly_polysome-0.1.0/docs/BENCHMARKS.md +114 -0
- monopoly_polysome-0.1.0/docs/DATA_CONTRACT.md +41 -0
- monopoly_polysome-0.1.0/docs/HPC_BENCHMARKS.md +121 -0
- monopoly_polysome-0.1.0/docs/METHODS.md +99 -0
- monopoly_polysome-0.1.0/docs/RELEASING.md +42 -0
- monopoly_polysome-0.1.0/docs/VALIDATION.md +33 -0
- monopoly_polysome-0.1.0/pyproject.toml +101 -0
- monopoly_polysome-0.1.0/src/monopoly/__init__.py +24 -0
- monopoly_polysome-0.1.0/src/monopoly/_design.py +364 -0
- monopoly_polysome-0.1.0/src/monopoly/_normalization.py +132 -0
- monopoly_polysome-0.1.0/src/monopoly/_provenance.py +87 -0
- monopoly_polysome-0.1.0/src/monopoly/_validation.py +38 -0
- monopoly_polysome-0.1.0/src/monopoly/dataset.py +412 -0
- monopoly_polysome-0.1.0/src/monopoly/exceptions.py +19 -0
- monopoly_polysome-0.1.0/src/monopoly/model.py +605 -0
- monopoly_polysome-0.1.0/src/monopoly/py.typed +1 -0
- monopoly_polysome-0.1.0/src/monopoly/results.py +136 -0
- monopoly_polysome-0.1.0/tests/conftest.py +51 -0
- monopoly_polysome-0.1.0/tests/test_api_contract.py +60 -0
- monopoly_polysome-0.1.0/tests/test_benchmark_methods.py +208 -0
- monopoly_polysome-0.1.0/tests/test_benchmark_metrics.py +190 -0
- monopoly_polysome-0.1.0/tests/test_benchmark_run.py +174 -0
- monopoly_polysome-0.1.0/tests/test_benchmark_simulate.py +109 -0
- monopoly_polysome-0.1.0/tests/test_dataset.py +413 -0
- monopoly_polysome-0.1.0/tests/test_design.py +339 -0
- monopoly_polysome-0.1.0/tests/test_model.py +590 -0
- monopoly_polysome-0.1.0/tests/test_normalization.py +184 -0
- monopoly_polysome-0.1.0/tests/test_provenance.py +25 -0
- monopoly_polysome-0.1.0/tests/test_results.py +105 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
- Added validated three-fraction datasets and paired condition-by-fraction models.
|
|
6
|
+
- Made within-fraction median-of-ratios normalization the default.
|
|
7
|
+
- Added explicit polysome, monosome, and input contrasts with stable effect direction.
|
|
8
|
+
- Added gene-level diagnostics, input fingerprints, and provenance sidecars.
|
|
9
|
+
- Defined the shared-dispersion Wald model as a transparent working model.
|
|
10
|
+
- Added a frozen, resumable simulation benchmark against R DESeq2, edgeR,
|
|
11
|
+
a log-ratio baseline, and FracFixR's native tests and fraction reconstruction.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: 'If you use Monopoly, please cite the software and associated manuscript.'
|
|
3
|
+
title: 'Monopoly: paired differential analysis of polysome profiling RNA-seq data'
|
|
4
|
+
type: software
|
|
5
|
+
authors:
|
|
6
|
+
- family-names: 'DeGroat'
|
|
7
|
+
given-names: 'William'
|
|
8
|
+
- family-names: 'Kreimer'
|
|
9
|
+
given-names: 'Anat'
|
|
10
|
+
version: 0.1.0
|
|
11
|
+
license: MIT
|
|
12
|
+
repository-code: 'https://github.com/WillDeGroat/monopoly'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Create an isolated Python 3.11 or later environment and install the development
|
|
4
|
+
dependencies:
|
|
5
|
+
|
|
6
|
+
```console
|
|
7
|
+
python -m pip install -e ".[dev]"
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Before submitting a change, run:
|
|
11
|
+
|
|
12
|
+
```console
|
|
13
|
+
python -m ruff check .
|
|
14
|
+
python -m pytest --cov=monopoly
|
|
15
|
+
python -m build
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Public API changes require tests and corresponding updates to the README and method
|
|
19
|
+
documentation. Statistical changes must define their estimand, assumptions, failure
|
|
20
|
+
modes, and validation criteria before implementation. Do not promote a method based
|
|
21
|
+
only on additional discoveries in one biological dataset.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 William DeGroat and Anat Kreimer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: monopoly-polysome
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Paired differential analysis of polysome profiling RNA-seq data.
|
|
5
|
+
Project-URL: Repository, https://github.com/WillDeGroat/monopoly
|
|
6
|
+
Project-URL: Documentation, https://github.com/WillDeGroat/monopoly#readme
|
|
7
|
+
Project-URL: Changelog, https://github.com/WillDeGroat/monopoly/blob/main/CHANGELOG.md
|
|
8
|
+
Project-URL: Issues, https://github.com/WillDeGroat/monopoly/issues
|
|
9
|
+
Author: William DeGroat, Anat Kreimer
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: RNA-seq,bioinformatics,polysome profiling,translation
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: formulaic<2,>=1.0
|
|
23
|
+
Requires-Dist: numpy<3,>=1.26
|
|
24
|
+
Requires-Dist: pandas<4,>=2.2
|
|
25
|
+
Requires-Dist: pydeseq2<0.6,>=0.5.4
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: build<2,>=1; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-cov<8,>=5; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest<10,>=8; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff<1,>=0.9; extra == 'dev'
|
|
31
|
+
Requires-Dist: scipy<2,>=1.12; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# Monopoly
|
|
35
|
+
|
|
36
|
+
Monopoly is a Python package for paired differential analysis of input, monosome,
|
|
37
|
+
and polysome RNA-seq count data. It estimates condition-associated changes in RNA
|
|
38
|
+
distribution between experimental fractions while accounting for the matched
|
|
39
|
+
participant design.
|
|
40
|
+
|
|
41
|
+
Monopoly is designed for experiments in which every participant contributes all
|
|
42
|
+
three fractions. It supports larger two-condition studies with unequal condition
|
|
43
|
+
sizes; no study-specific sample size is hardcoded.
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
```console
|
|
48
|
+
python -m pip install monopoly-polysome
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The distribution is named `monopoly-polysome`; the Python import is `monopoly`.
|
|
52
|
+
Python 3.11 or later is required.
|
|
53
|
+
|
|
54
|
+
## Input
|
|
55
|
+
|
|
56
|
+
Provide one participant-by-gene count matrix for each fraction and a participant
|
|
57
|
+
metadata table containing a lowercase `condition` column. The three matrices must
|
|
58
|
+
contain identical participant and gene identifiers.
|
|
59
|
+
|
|
60
|
+
Counts must be finite, nonnegative whole numbers. For Salmon gene quantification,
|
|
61
|
+
round `lengthScaledTPM` count-scale values once before constructing the dataset. Do
|
|
62
|
+
not use TPM as counts. Filtering and transcript aggregation remain upstream analysis
|
|
63
|
+
decisions; see the
|
|
64
|
+
[data contract](https://github.com/WillDeGroat/monopoly/blob/main/docs/DATA_CONTRACT.md).
|
|
65
|
+
|
|
66
|
+
## Workflow
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from monopoly import MonopolyDataset, MonopolyModel
|
|
70
|
+
|
|
71
|
+
dataset = MonopolyDataset(
|
|
72
|
+
input = input_counts,
|
|
73
|
+
monosome = monosome_counts,
|
|
74
|
+
polysome = polysome_counts,
|
|
75
|
+
metadata = metadata,
|
|
76
|
+
gene_metadata = gene_metadata,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
model = MonopolyModel(
|
|
80
|
+
dataset = dataset,
|
|
81
|
+
reference = 'Control',
|
|
82
|
+
).fit(
|
|
83
|
+
normalization = 'fraction',
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
results = model.contrast('poly', 'mono')
|
|
87
|
+
results.write('polyVsMono.tsv')
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`poly` and `mono` are accepted contrast aliases for `polysome` and `monosome`.
|
|
91
|
+
`input` is used without an alias. Version 0.1 requires exactly two conditions and
|
|
92
|
+
infers the test condition as the level other than `reference`.
|
|
93
|
+
|
|
94
|
+
A positive polysome-versus-monosome `log2FoldChange` means that the normalized
|
|
95
|
+
polysome-to-monosome ratio is higher in the test condition than in the reference
|
|
96
|
+
condition. `poly` versus `input` and `mono` versus `input` provide secondary
|
|
97
|
+
decompositions.
|
|
98
|
+
|
|
99
|
+
## Model
|
|
100
|
+
|
|
101
|
+
Monopoly fits a negative-binomial generalized linear model with participant fixed
|
|
102
|
+
effects, fraction effects, and condition-by-fraction interactions. Participant fixed
|
|
103
|
+
effects make each contrast a within-participant fraction comparison. The released
|
|
104
|
+
model uses one moderated dispersion per gene across fractions and asymptotic Wald
|
|
105
|
+
tests through PyDESeq2.
|
|
106
|
+
|
|
107
|
+
Fraction-wise median-of-ratios normalization is the default. It avoids treating
|
|
108
|
+
input, monosome, and polysome libraries as one compositionally homogeneous source.
|
|
109
|
+
Joint normalization remains available as an explicit sensitivity analysis:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
model.fit(normalization = 'joint')
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The complete mathematical specification and assumptions are in
|
|
116
|
+
[method specification](https://github.com/WillDeGroat/monopoly/blob/main/docs/METHODS.md).
|
|
117
|
+
|
|
118
|
+
## Interpretation boundary
|
|
119
|
+
|
|
120
|
+
Monopoly estimates relative redistribution among sequenced RNA pools. It does not
|
|
121
|
+
measure absolute protein synthesis, absolute RNA allocation, or ribosome number per
|
|
122
|
+
transcript. Monosome fractions may contain actively translated RNA and must not be
|
|
123
|
+
described as untranslated RNA.
|
|
124
|
+
|
|
125
|
+
The Wald test assumes that one moderated dispersion per gene adequately represents
|
|
126
|
+
all modeled fractions. Strong fraction-specific mean-variance differences can
|
|
127
|
+
invalidate that assumption. Small studies can still use Monopoly for effect
|
|
128
|
+
estimation, ranking, diagnostics, and sensitivity analyses, but the package does not
|
|
129
|
+
claim that gene-level false-discovery rates are calibrated merely because a model
|
|
130
|
+
can be fit. Larger studies should also inspect fraction-specific variability and
|
|
131
|
+
perform design-appropriate sensitivity analyses.
|
|
132
|
+
|
|
133
|
+
Participant fixed effects leave each modeled library cell unique, so automatic
|
|
134
|
+
Cook's filtering and outlier replacement are disabled. Cook's distances and explicit
|
|
135
|
+
fit statuses remain available as diagnostics.
|
|
136
|
+
|
|
137
|
+
## Results
|
|
138
|
+
|
|
139
|
+
`MonopolyResults.table` contains stable camelCase columns:
|
|
140
|
+
|
|
141
|
+
- `geneId` and optional `geneName`;
|
|
142
|
+
- `baseMean`, `log2FoldChange`, and `log2FoldChangeSE`;
|
|
143
|
+
- `statistic`, `pValue`, and `adjustedPValue`.
|
|
144
|
+
|
|
145
|
+
`MonopolyResults.diagnostics` reports fit status, dispersion, maximum Cook's
|
|
146
|
+
distance, Cook's-outlier status, and independent-filter status for every gene.
|
|
147
|
+
`MonopolyResults.provenance` records package versions, input fingerprints, design,
|
|
148
|
+
normalization, fit settings, contrast direction, and inferential scope.
|
|
149
|
+
|
|
150
|
+
`results.write('polyVsMono.tsv')` writes three files:
|
|
151
|
+
|
|
152
|
+
- `polyVsMono.tsv`;
|
|
153
|
+
- `polyVsMono.diagnostics.tsv`; and
|
|
154
|
+
- `polyVsMono.provenance.json`.
|
|
155
|
+
|
|
156
|
+
Existing files are replaced.
|
|
157
|
+
|
|
158
|
+
## Development
|
|
159
|
+
|
|
160
|
+
```console
|
|
161
|
+
python -m pip install -e ".[dev]"
|
|
162
|
+
python -m ruff check .
|
|
163
|
+
python -m pytest --cov=monopoly
|
|
164
|
+
python -m build
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The release test suite covers validation, design identifiability, normalization,
|
|
168
|
+
contrast direction, invariance, diagnostics, output schemas, provenance, and package
|
|
169
|
+
construction. See the
|
|
170
|
+
[validation scope](https://github.com/WillDeGroat/monopoly/blob/main/docs/VALIDATION.md).
|
|
171
|
+
|
|
172
|
+
The public simulation benchmark independently compares Monopoly with R DESeq2,
|
|
173
|
+
edgeR, a log-ratio test, and FracFixR. Its estimands, frozen configurations, and run
|
|
174
|
+
instructions are in the
|
|
175
|
+
[benchmark README](https://github.com/WillDeGroat/monopoly/blob/main/benchmarks/README.md);
|
|
176
|
+
the [HPC guide](https://github.com/WillDeGroat/monopoly/blob/main/docs/HPC_BENCHMARKS.md)
|
|
177
|
+
covers publication-scale execution. FracFixR
|
|
178
|
+
results are not presented as the same contrast when its native test targets a
|
|
179
|
+
different single-fraction proportion.
|
|
180
|
+
|
|
181
|
+
Monopoly is developed by William DeGroat and Anat Kreimer and released under the
|
|
182
|
+
[MIT License](https://github.com/WillDeGroat/monopoly/blob/main/LICENSE).
|
|
183
|
+
|
|
184
|
+
## Publication benchmark
|
|
185
|
+
|
|
186
|
+
The complete frozen study benchmarks and the additional equal-dispersion run
|
|
187
|
+
are linked from [benchmark results](benchmarks/results/README.md).
|
|
188
|
+
See [release instructions](docs/RELEASING.md) for PyPI Trusted Publishing.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Monopoly
|
|
2
|
+
|
|
3
|
+
Monopoly is a Python package for paired differential analysis of input, monosome,
|
|
4
|
+
and polysome RNA-seq count data. It estimates condition-associated changes in RNA
|
|
5
|
+
distribution between experimental fractions while accounting for the matched
|
|
6
|
+
participant design.
|
|
7
|
+
|
|
8
|
+
Monopoly is designed for experiments in which every participant contributes all
|
|
9
|
+
three fractions. It supports larger two-condition studies with unequal condition
|
|
10
|
+
sizes; no study-specific sample size is hardcoded.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```console
|
|
15
|
+
python -m pip install monopoly-polysome
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The distribution is named `monopoly-polysome`; the Python import is `monopoly`.
|
|
19
|
+
Python 3.11 or later is required.
|
|
20
|
+
|
|
21
|
+
## Input
|
|
22
|
+
|
|
23
|
+
Provide one participant-by-gene count matrix for each fraction and a participant
|
|
24
|
+
metadata table containing a lowercase `condition` column. The three matrices must
|
|
25
|
+
contain identical participant and gene identifiers.
|
|
26
|
+
|
|
27
|
+
Counts must be finite, nonnegative whole numbers. For Salmon gene quantification,
|
|
28
|
+
round `lengthScaledTPM` count-scale values once before constructing the dataset. Do
|
|
29
|
+
not use TPM as counts. Filtering and transcript aggregation remain upstream analysis
|
|
30
|
+
decisions; see the
|
|
31
|
+
[data contract](https://github.com/WillDeGroat/monopoly/blob/main/docs/DATA_CONTRACT.md).
|
|
32
|
+
|
|
33
|
+
## Workflow
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from monopoly import MonopolyDataset, MonopolyModel
|
|
37
|
+
|
|
38
|
+
dataset = MonopolyDataset(
|
|
39
|
+
input = input_counts,
|
|
40
|
+
monosome = monosome_counts,
|
|
41
|
+
polysome = polysome_counts,
|
|
42
|
+
metadata = metadata,
|
|
43
|
+
gene_metadata = gene_metadata,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
model = MonopolyModel(
|
|
47
|
+
dataset = dataset,
|
|
48
|
+
reference = 'Control',
|
|
49
|
+
).fit(
|
|
50
|
+
normalization = 'fraction',
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
results = model.contrast('poly', 'mono')
|
|
54
|
+
results.write('polyVsMono.tsv')
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`poly` and `mono` are accepted contrast aliases for `polysome` and `monosome`.
|
|
58
|
+
`input` is used without an alias. Version 0.1 requires exactly two conditions and
|
|
59
|
+
infers the test condition as the level other than `reference`.
|
|
60
|
+
|
|
61
|
+
A positive polysome-versus-monosome `log2FoldChange` means that the normalized
|
|
62
|
+
polysome-to-monosome ratio is higher in the test condition than in the reference
|
|
63
|
+
condition. `poly` versus `input` and `mono` versus `input` provide secondary
|
|
64
|
+
decompositions.
|
|
65
|
+
|
|
66
|
+
## Model
|
|
67
|
+
|
|
68
|
+
Monopoly fits a negative-binomial generalized linear model with participant fixed
|
|
69
|
+
effects, fraction effects, and condition-by-fraction interactions. Participant fixed
|
|
70
|
+
effects make each contrast a within-participant fraction comparison. The released
|
|
71
|
+
model uses one moderated dispersion per gene across fractions and asymptotic Wald
|
|
72
|
+
tests through PyDESeq2.
|
|
73
|
+
|
|
74
|
+
Fraction-wise median-of-ratios normalization is the default. It avoids treating
|
|
75
|
+
input, monosome, and polysome libraries as one compositionally homogeneous source.
|
|
76
|
+
Joint normalization remains available as an explicit sensitivity analysis:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
model.fit(normalization = 'joint')
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The complete mathematical specification and assumptions are in
|
|
83
|
+
[method specification](https://github.com/WillDeGroat/monopoly/blob/main/docs/METHODS.md).
|
|
84
|
+
|
|
85
|
+
## Interpretation boundary
|
|
86
|
+
|
|
87
|
+
Monopoly estimates relative redistribution among sequenced RNA pools. It does not
|
|
88
|
+
measure absolute protein synthesis, absolute RNA allocation, or ribosome number per
|
|
89
|
+
transcript. Monosome fractions may contain actively translated RNA and must not be
|
|
90
|
+
described as untranslated RNA.
|
|
91
|
+
|
|
92
|
+
The Wald test assumes that one moderated dispersion per gene adequately represents
|
|
93
|
+
all modeled fractions. Strong fraction-specific mean-variance differences can
|
|
94
|
+
invalidate that assumption. Small studies can still use Monopoly for effect
|
|
95
|
+
estimation, ranking, diagnostics, and sensitivity analyses, but the package does not
|
|
96
|
+
claim that gene-level false-discovery rates are calibrated merely because a model
|
|
97
|
+
can be fit. Larger studies should also inspect fraction-specific variability and
|
|
98
|
+
perform design-appropriate sensitivity analyses.
|
|
99
|
+
|
|
100
|
+
Participant fixed effects leave each modeled library cell unique, so automatic
|
|
101
|
+
Cook's filtering and outlier replacement are disabled. Cook's distances and explicit
|
|
102
|
+
fit statuses remain available as diagnostics.
|
|
103
|
+
|
|
104
|
+
## Results
|
|
105
|
+
|
|
106
|
+
`MonopolyResults.table` contains stable camelCase columns:
|
|
107
|
+
|
|
108
|
+
- `geneId` and optional `geneName`;
|
|
109
|
+
- `baseMean`, `log2FoldChange`, and `log2FoldChangeSE`;
|
|
110
|
+
- `statistic`, `pValue`, and `adjustedPValue`.
|
|
111
|
+
|
|
112
|
+
`MonopolyResults.diagnostics` reports fit status, dispersion, maximum Cook's
|
|
113
|
+
distance, Cook's-outlier status, and independent-filter status for every gene.
|
|
114
|
+
`MonopolyResults.provenance` records package versions, input fingerprints, design,
|
|
115
|
+
normalization, fit settings, contrast direction, and inferential scope.
|
|
116
|
+
|
|
117
|
+
`results.write('polyVsMono.tsv')` writes three files:
|
|
118
|
+
|
|
119
|
+
- `polyVsMono.tsv`;
|
|
120
|
+
- `polyVsMono.diagnostics.tsv`; and
|
|
121
|
+
- `polyVsMono.provenance.json`.
|
|
122
|
+
|
|
123
|
+
Existing files are replaced.
|
|
124
|
+
|
|
125
|
+
## Development
|
|
126
|
+
|
|
127
|
+
```console
|
|
128
|
+
python -m pip install -e ".[dev]"
|
|
129
|
+
python -m ruff check .
|
|
130
|
+
python -m pytest --cov=monopoly
|
|
131
|
+
python -m build
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The release test suite covers validation, design identifiability, normalization,
|
|
135
|
+
contrast direction, invariance, diagnostics, output schemas, provenance, and package
|
|
136
|
+
construction. See the
|
|
137
|
+
[validation scope](https://github.com/WillDeGroat/monopoly/blob/main/docs/VALIDATION.md).
|
|
138
|
+
|
|
139
|
+
The public simulation benchmark independently compares Monopoly with R DESeq2,
|
|
140
|
+
edgeR, a log-ratio test, and FracFixR. Its estimands, frozen configurations, and run
|
|
141
|
+
instructions are in the
|
|
142
|
+
[benchmark README](https://github.com/WillDeGroat/monopoly/blob/main/benchmarks/README.md);
|
|
143
|
+
the [HPC guide](https://github.com/WillDeGroat/monopoly/blob/main/docs/HPC_BENCHMARKS.md)
|
|
144
|
+
covers publication-scale execution. FracFixR
|
|
145
|
+
results are not presented as the same contrast when its native test targets a
|
|
146
|
+
different single-fraction proportion.
|
|
147
|
+
|
|
148
|
+
Monopoly is developed by William DeGroat and Anat Kreimer and released under the
|
|
149
|
+
[MIT License](https://github.com/WillDeGroat/monopoly/blob/main/LICENSE).
|
|
150
|
+
|
|
151
|
+
## Publication benchmark
|
|
152
|
+
|
|
153
|
+
The complete frozen study benchmarks and the additional equal-dispersion run
|
|
154
|
+
are linked from [benchmark results](benchmarks/results/README.md).
|
|
155
|
+
See [release instructions](docs/RELEASING.md) for PyPI Trusted Publishing.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Monopoly style
|
|
2
|
+
|
|
3
|
+
Monopoly should remain small, explicit, and unsurprising.
|
|
4
|
+
|
|
5
|
+
Scientific terminology and assumptions are defined in `docs/METHODS.md`.
|
|
6
|
+
|
|
7
|
+
## Design
|
|
8
|
+
|
|
9
|
+
- Keep the public workflow centered on `MonopolyDataset`, `MonopolyModel`, and
|
|
10
|
+
`MonopolyResults`.
|
|
11
|
+
- Prefer plain functions to inheritance, registries, factories, or plugin systems.
|
|
12
|
+
- Add an abstraction only when it removes repeated behavior that already exists.
|
|
13
|
+
- Use established numerical libraries whenever they can express the required method.
|
|
14
|
+
- Use PyDESeq2 for negative-binomial estimation and established scientific
|
|
15
|
+
libraries for numerical work.
|
|
16
|
+
- Validate at public boundaries. Internal functions may rely on validated inputs.
|
|
17
|
+
- Never guess identifiers, silently remove observations, or mutate user objects.
|
|
18
|
+
|
|
19
|
+
## Source
|
|
20
|
+
|
|
21
|
+
- Use single-quoted strings. Docstrings use triple double quotes.
|
|
22
|
+
- Limit lines to 88 characters.
|
|
23
|
+
- Include spaces around keyword and default assignments.
|
|
24
|
+
- Use concise one-line docstrings ending in periods for public APIs.
|
|
25
|
+
- Use descriptive phrases for classes and imperative sentences for functions and
|
|
26
|
+
methods.
|
|
27
|
+
- Add comments only when they explain scientific or non-obvious algorithmic reasoning.
|
|
28
|
+
- Use `snake_case` internally and camelCase in exported scientific tables.
|
|
29
|
+
- Use Ruff for linting and line-length enforcement. Format manually because standard
|
|
30
|
+
Python formatters remove the approved spaces around keyword assignments.
|
|
31
|
+
|
|
32
|
+
## Errors
|
|
33
|
+
|
|
34
|
+
- Raise a dedicated Monopoly exception with an actionable message.
|
|
35
|
+
- Stop for invalid experiments or global model failures.
|
|
36
|
+
- Preserve valid genome-wide fits when isolated genes fail, and report those failures
|
|
37
|
+
through diagnostics.
|
|
38
|
+
|
|
39
|
+
## Tests
|
|
40
|
+
|
|
41
|
+
- Test public contracts, scientific invariants, and failure modes.
|
|
42
|
+
- Do not reproduce dependency test suites or preserve tests for rejected methods.
|
|
43
|
+
- Use fixed random seeds only for deterministic numerical contract tests.
|
|
44
|
+
- A successful test suite establishes implementation behavior, not universal
|
|
45
|
+
statistical calibration.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Monopoly benchmark
|
|
2
|
+
|
|
3
|
+
This benchmark evaluates the released three-pool model against independently
|
|
4
|
+
generated truth. It is not a search for settings that maximize discoveries.
|
|
5
|
+
|
|
6
|
+
## Methods
|
|
7
|
+
|
|
8
|
+
- `monopoly`: fraction-wise median-ratio normalization and the released PyDESeq2
|
|
9
|
+
participant-by-fraction interaction model.
|
|
10
|
+
- `deseq2`: an independent R implementation of the same design and normalization.
|
|
11
|
+
This is a numerical reference, not a method Monopoly is expected to outperform.
|
|
12
|
+
- `edgeR`: the corresponding robust quasi-likelihood interaction model with
|
|
13
|
+
fraction-wise TMM normalization.
|
|
14
|
+
- `ratioWelch`: a deliberately simple pseudocount log-ratio followed by a Welch
|
|
15
|
+
test. It represents a common analysis that does not model count uncertainty.
|
|
16
|
+
- `fracfixr`: FracFixR 1.1.0 fraction reconstruction followed by its native GLM,
|
|
17
|
+
Logit, and beta-binomial Wald tests.
|
|
18
|
+
|
|
19
|
+
Monopoly, DESeq2, edgeR, and `ratioWelch` target the condition difference in the
|
|
20
|
+
log2 polysome-to-monosome ratio. FracFixR's Logit and Wald tests target the odds of
|
|
21
|
+
one reconstructed fraction against the remainder. Its GLM returns a log2 ratio of
|
|
22
|
+
mean reconstructed proportions while testing a binomial condition coefficient.
|
|
23
|
+
All are reported under separate estimands. FracFixR fraction-weight recovery is
|
|
24
|
+
evaluated in a separate table.
|
|
25
|
+
|
|
26
|
+
## Run
|
|
27
|
+
|
|
28
|
+
Install Monopoly with its development dependencies, then install the frozen R
|
|
29
|
+
comparators:
|
|
30
|
+
|
|
31
|
+
```console
|
|
32
|
+
python -m pip install -e ".[dev]"
|
|
33
|
+
Rscript benchmarks/r/install.R
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Run the three-replicate software smoke test:
|
|
37
|
+
|
|
38
|
+
```console
|
|
39
|
+
python -m benchmarks.run benchmarks/configs/smoke.json benchmark-results/smoke \
|
|
40
|
+
--rscript Rscript --workers 1
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`preflight.json` is a small scientific diagnostic. The two `publication_*.json`
|
|
44
|
+
files contain the larger count-model and FracFixR grids. They are separate because
|
|
45
|
+
FracFixR fits gene-wise models for a related but non-identical estimand and is much
|
|
46
|
+
more computationally expensive. Run the smoke test and preflight locally before
|
|
47
|
+
submitting either publication grid. See the
|
|
48
|
+
[HPC walkthrough](../docs/HPC_BENCHMARKS.md) for a reproducible Slurm workflow.
|
|
49
|
+
|
|
50
|
+
Runs are resumable. A result directory cannot be resumed after its configuration,
|
|
51
|
+
method set, or benchmark source changes. Each run records seeds, configurations,
|
|
52
|
+
software versions, simulation hashes, result hashes, failures, and runtime.
|
|
53
|
+
The frozen R versions in `r/requirements.tsv` are enforced before any replicate is
|
|
54
|
+
run. Completed replicate parts are written atomically, and progress is printed at
|
|
55
|
+
approximately one-percent intervals. A missing or empty R result is retried once.
|
|
56
|
+
If a replicate still fails, the runner reports its scenario and replicate, retains
|
|
57
|
+
all other completed parts, and exits after the remaining submitted work finishes.
|
|
58
|
+
Resume an interrupted run with the identical command and output directory. Never
|
|
59
|
+
run multiple benchmark processes against the same output directory.
|
|
60
|
+
|
|
61
|
+
## Outputs
|
|
62
|
+
|
|
63
|
+
- `manifest.json`: run identity, environment, hashes, and completion state.
|
|
64
|
+
- `seedManifest.tsv`: one immutable configuration and seed per replicate.
|
|
65
|
+
- `replicateResults.tsv`: operating characteristics for each method and estimand.
|
|
66
|
+
- `metricSummary.tsv`: means and Monte Carlo standard errors across replicates.
|
|
67
|
+
- `benchmarkAssessment.tsv`: prespecified pass/fail calibration checks.
|
|
68
|
+
- `fractionRecovery.tsv`: FracFixR fraction-weight recovery metrics.
|
|
69
|
+
- `parts/`: atomic replicate outputs used for resumption and auditing.
|
|
70
|
+
|
|
71
|
+
The smoke and preflight configurations are engineering checks, not validation
|
|
72
|
+
evidence. Publication claims must use the frozen publication grids and report every
|
|
73
|
+
prespecified scenario, including failures.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"alpha": 0.05,
|
|
3
|
+
"benchmarkId": "monopoly-preflight-2026-09",
|
|
4
|
+
"methods": [
|
|
5
|
+
"monopoly",
|
|
6
|
+
"ratioWelch",
|
|
7
|
+
"deseq2",
|
|
8
|
+
"edgeR",
|
|
9
|
+
"fracfixr"
|
|
10
|
+
],
|
|
11
|
+
"minimumMean": 20,
|
|
12
|
+
"scenarios": [
|
|
13
|
+
{
|
|
14
|
+
"dispersionCorrelation": 1.0,
|
|
15
|
+
"dispersionLogSd": 0.5,
|
|
16
|
+
"fractionDispersions": [0.15, 0.15, 0.15],
|
|
17
|
+
"genes": 500,
|
|
18
|
+
"participantsPerCondition": 3,
|
|
19
|
+
"redistributedGenes": 0,
|
|
20
|
+
"replicates": 4,
|
|
21
|
+
"scenarioId": "equalNullN3",
|
|
22
|
+
"seedStart": 41107000,
|
|
23
|
+
"transcriptionGenes": 0
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"dispersionCorrelation": 0.7,
|
|
27
|
+
"dispersionLogSd": 0.5,
|
|
28
|
+
"fractionDispersions": [0.05, 0.15, 0.5],
|
|
29
|
+
"genes": 500,
|
|
30
|
+
"participantsPerCondition": 3,
|
|
31
|
+
"redistributedGenes": 0,
|
|
32
|
+
"replicates": 4,
|
|
33
|
+
"scenarioId": "unequalNullN3",
|
|
34
|
+
"seedStart": 41108000,
|
|
35
|
+
"transcriptionGenes": 0
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"dispersionCorrelation": 1.0,
|
|
39
|
+
"dispersionLogSd": 0.5,
|
|
40
|
+
"fractionDispersions": [0.15, 0.15, 0.15],
|
|
41
|
+
"genes": 500,
|
|
42
|
+
"participantsPerCondition": 3,
|
|
43
|
+
"redistributedGenes": 100,
|
|
44
|
+
"redistributionLog2Effect": 2,
|
|
45
|
+
"redistributionPositiveFraction": 0.5,
|
|
46
|
+
"replicates": 4,
|
|
47
|
+
"scenarioId": "equalEffect2N3",
|
|
48
|
+
"seedStart": 41109000,
|
|
49
|
+
"transcriptionGenes": 100,
|
|
50
|
+
"transcriptionLog2Effect": 1
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"dispersionCorrelation": 0.7,
|
|
54
|
+
"dispersionLogSd": 0.5,
|
|
55
|
+
"fractionDispersions": [0.05, 0.15, 0.5],
|
|
56
|
+
"genes": 500,
|
|
57
|
+
"participantsPerCondition": 3,
|
|
58
|
+
"redistributedGenes": 100,
|
|
59
|
+
"redistributionLog2Effect": 2,
|
|
60
|
+
"redistributionPositiveFraction": 0.5,
|
|
61
|
+
"replicates": 4,
|
|
62
|
+
"scenarioId": "unequalEffect2N3",
|
|
63
|
+
"seedStart": 41110000,
|
|
64
|
+
"transcriptionGenes": 100,
|
|
65
|
+
"transcriptionLog2Effect": 1
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|