finite-selection 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.
- finite_selection-0.1.0/LICENSE +21 -0
- finite_selection-0.1.0/PKG-INFO +168 -0
- finite_selection-0.1.0/README.md +135 -0
- finite_selection-0.1.0/pyproject.toml +170 -0
- finite_selection-0.1.0/pyproject.toml.orig +130 -0
- finite_selection-0.1.0/src/finite_selection/__init__.py +45 -0
- finite_selection-0.1.0/src/finite_selection/core.py +365 -0
- finite_selection-0.1.0/src/finite_selection/data/lalonde.parquet +0 -0
- finite_selection-0.1.0/src/finite_selection/datasets.py +62 -0
- finite_selection-0.1.0/src/finite_selection/features.py +56 -0
- finite_selection-0.1.0/src/finite_selection/inference.py +380 -0
- finite_selection-0.1.0/src/finite_selection/plot.py +109 -0
- finite_selection-0.1.0/src/finite_selection/py.typed +0 -0
- finite_selection-0.1.0/src/finite_selection/som.py +146 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 goji+
|
|
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,168 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: finite-selection
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Finite Selection Model for randomized, balanced allocation of units to treatment groups
|
|
5
|
+
Keywords: experimental design,randomization,covariate balance,finite selection model,causal inference,randomized controlled trials
|
|
6
|
+
Author: Gaurav Sood
|
|
7
|
+
Author-email: Gaurav Sood <gsood07@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Dist: numpy>=2.0
|
|
20
|
+
Requires-Dist: pandas>=2.2
|
|
21
|
+
Requires-Dist: scipy>=1.11
|
|
22
|
+
Requires-Dist: pyarrow>=15 ; extra == 'data'
|
|
23
|
+
Requires-Dist: matplotlib>=3.8 ; extra == 'plot'
|
|
24
|
+
Requires-Python: >=3.12
|
|
25
|
+
Project-URL: Homepage, https://github.com/finite-sample/finite-selection
|
|
26
|
+
Project-URL: Documentation, https://finite-sample.github.io/finite-selection/
|
|
27
|
+
Project-URL: Repository, https://github.com/finite-sample/finite-selection
|
|
28
|
+
Project-URL: Issues, https://github.com/finite-sample/finite-selection/issues
|
|
29
|
+
Project-URL: Changelog, https://github.com/finite-sample/finite-selection/blob/main/CHANGELOG.md
|
|
30
|
+
Provides-Extra: data
|
|
31
|
+
Provides-Extra: plot
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# finite-selection
|
|
35
|
+
|
|
36
|
+
[](https://pypi.org/project/finite-selection/)
|
|
37
|
+
[](https://github.com/finite-sample/finite-selection/actions/workflows/ci.yml)
|
|
38
|
+
[](https://finite-sample.github.io/finite-selection/)
|
|
39
|
+
|
|
40
|
+
<!-- SPHINX-START -->
|
|
41
|
+
|
|
42
|
+
finite-selection assigns units to treatment groups at random while keeping the
|
|
43
|
+
groups alike on their covariates. It implements the Finite Selection Model
|
|
44
|
+
(FSM) that Carl Morris built for the RAND Health Insurance Experiment, in
|
|
45
|
+
Python, with allocation results checked against the R package
|
|
46
|
+
[FSM](https://cran.r-project.org/package=FSM). It works with NumPy arrays and
|
|
47
|
+
pandas data frames and includes balance diagnostics and randomization tests.
|
|
48
|
+
The contribution is a tested Python implementation, documented corrections,
|
|
49
|
+
and reproducible examples; the method is due to the authors cited below.
|
|
50
|
+
|
|
51
|
+
## How it works
|
|
52
|
+
|
|
53
|
+
The groups take turns choosing units, like captains picking teams. A random
|
|
54
|
+
draw fixes the order of turns, under a rule that never lets one group get far
|
|
55
|
+
ahead of its share. On its turn a group takes the remaining unit that most
|
|
56
|
+
improves its own design: by default, the unit that most increases the
|
|
57
|
+
determinant of its X'X matrix (D-optimality). Every group chases the same goal,
|
|
58
|
+
so the groups come out balanced. The turn order is random, so
|
|
59
|
+
randomization-based inference still applies.
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
Requires Python 3.12 or newer.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pip install finite-selection
|
|
67
|
+
pip install "finite-selection[data,plot]" # example data and love plots
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Example
|
|
71
|
+
|
|
72
|
+
This splits the 445 men of the National Supported Work data into groups of
|
|
73
|
+
222 and 223, once with the FSM and once by complete randomization. The table
|
|
74
|
+
reports TASMD for the first group: the distance between its covariate means and
|
|
75
|
+
the full-sample means, in standard deviations.
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
import numpy as np
|
|
79
|
+
import finite_selection as fs
|
|
80
|
+
|
|
81
|
+
x = fs.lalonde()
|
|
82
|
+
rng = np.random.default_rng(2026)
|
|
83
|
+
|
|
84
|
+
order = fs.som([222, 223], method="scomars", rng=rng) # who chooses when
|
|
85
|
+
fsm_z = fs.fsm(x, order, rng=rng).assignment # who goes where
|
|
86
|
+
crd_z = fs.crd([222, 223], rng=rng) # complete randomization
|
|
87
|
+
|
|
88
|
+
print(fs.tasmd_rand(x, {"CRD": crd_z, "FSM": fsm_z}).round(3))
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
CRD FSM
|
|
93
|
+
Age 0.066 0.002
|
|
94
|
+
Education 0.004 0.004
|
|
95
|
+
Black 0.023 0.011
|
|
96
|
+
Hispanic 0.055 0.007
|
|
97
|
+
Married 0.043 0.007
|
|
98
|
+
Nodegree 0.018 0.004
|
|
99
|
+
Re74 0.016 0.006
|
|
100
|
+
Re75 0.006 0.002
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The FSM group sits within 0.011 standard deviations of the full sample on
|
|
104
|
+
every covariate. The randomized group is off by up to 0.066, on age. That is
|
|
105
|
+
one draw of each. Over 200 draws, the average TASMD per covariate is 0.034 to
|
|
106
|
+
0.041 under complete randomization and 0.004 to 0.008 under the FSM.
|
|
107
|
+
`tasmd_rand` reports these averages when given a matrix of assignments.
|
|
108
|
+
|
|
109
|
+
The package also allocates units that arrive in batches (`fsm_batch`), offers
|
|
110
|
+
ten other selection functions, and covers the analysis side: Fisher
|
|
111
|
+
randomization tests (`perm_test`), effective sample sizes for comparing designs
|
|
112
|
+
(`ess_rand`, `ess_model`), squares and interactions of the covariates
|
|
113
|
+
(`make_sq_inter`), and love plots (`love_plot`). The
|
|
114
|
+
[user guide](https://finite-sample.github.io/finite-selection/guide.html) runs a full experiment with them.
|
|
115
|
+
|
|
116
|
+
## What it assumes
|
|
117
|
+
|
|
118
|
+
The FSM needs every unit and its covariates before assignment starts, so it
|
|
119
|
+
suits experiments that enroll a known list, not ones that recruit as they go.
|
|
120
|
+
It balances the columns you give it. Balance on squares or interactions
|
|
121
|
+
requires passing them in, through `make_sq_inter` for example. Against outcome
|
|
122
|
+
components it cannot see, it can increase variance relative to complete
|
|
123
|
+
randomization. Covariate
|
|
124
|
+
balance alone does not guarantee more precise estimates for every outcome.
|
|
125
|
+
The [JRSS-A discussion](https://doi.org/10.1093/jrsssa/qnag030) examines this
|
|
126
|
+
robustness concern. Run time grows with the square of the sample: about 0.1 seconds for 445
|
|
127
|
+
units and 7 seconds for 5,000.
|
|
128
|
+
|
|
129
|
+
## Agreement with R
|
|
130
|
+
|
|
131
|
+
The script `tests/fixtures/make_r_fixtures.R` runs R's exported functions on a
|
|
132
|
+
grid of cases and saves their inputs and outputs. The test suite checks the
|
|
133
|
+
Python functions against those records:
|
|
134
|
+
|
|
135
|
+
- Given the same turn order, `fsm` reproduces R's allocation and selection
|
|
136
|
+
sequence in all 67 cases, which span the 11 selection functions, two to four
|
|
137
|
+
groups, and the options (intercept, scaling, ridge size, `Q_initial`,
|
|
138
|
+
collinear data). `fsm_batch` does the same in 3 cases.
|
|
139
|
+
- Random draws (`som`, `crd`) match R in distribution over 10,000 draws. R and
|
|
140
|
+
numpy use different random number generators, so individual draws differ.
|
|
141
|
+
- In several places R 1.0.0 departs from its own documentation, and Python
|
|
142
|
+
follows the documentation. For example, R's `ess_rand` reads only the first N
|
|
143
|
+
assignments, and its `perm_test` ignores a nonzero null effect. Fixes are
|
|
144
|
+
proposed upstream, and [Behaviour and parity with R](https://finite-sample.github.io/finite-selection/behavior.html) lists
|
|
145
|
+
each departure with its test.
|
|
146
|
+
|
|
147
|
+
`perm_test` imputes the two-group sharp null for every supported contrast,
|
|
148
|
+
including when `tau=0`. Sampled reference assignments use the Monte Carlo
|
|
149
|
+
correction `(b + 1) / (B + 1)`; `exact=True` is for a complete, equally weighted
|
|
150
|
+
reference distribution. Rank tests and tests with more than two groups support
|
|
151
|
+
only the sharp no-effect null.
|
|
152
|
+
|
|
153
|
+
## Credits
|
|
154
|
+
|
|
155
|
+
Carl N. Morris introduced the FSM (1979, *Journal of Econometrics* 11, 43-61).
|
|
156
|
+
Ambarish Chattopadhyay, Carl N. Morris and José R. Zubizarreta recast it in the
|
|
157
|
+
potential-outcomes framework and wrote the R package FSM, described in
|
|
158
|
+
"Randomized and balanced allocation of units into treatment groups using the
|
|
159
|
+
finite selection model for R" (arXiv:2105.02393) and "Balanced and robust
|
|
160
|
+
randomized treatment assignments: the finite selection model for the Health
|
|
161
|
+
Insurance Experiment and beyond" (*JRSS-A* 189(4), 2026; arXiv:2205.09736).
|
|
162
|
+
This package is an independent implementation checked against theirs. The
|
|
163
|
+
bundled data is Dehejia and Wahba's subset of the National Supported Work
|
|
164
|
+
demonstration (LaLonde 1986), from
|
|
165
|
+
[NBER](https://users.nber.org/~rdehejia/nswdata.html).
|
|
166
|
+
|
|
167
|
+
Cite the papers when you use the method, and this package (`CITATION.cff`) when
|
|
168
|
+
you use the software.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# finite-selection
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/finite-selection/)
|
|
4
|
+
[](https://github.com/finite-sample/finite-selection/actions/workflows/ci.yml)
|
|
5
|
+
[](https://finite-sample.github.io/finite-selection/)
|
|
6
|
+
|
|
7
|
+
<!-- SPHINX-START -->
|
|
8
|
+
|
|
9
|
+
finite-selection assigns units to treatment groups at random while keeping the
|
|
10
|
+
groups alike on their covariates. It implements the Finite Selection Model
|
|
11
|
+
(FSM) that Carl Morris built for the RAND Health Insurance Experiment, in
|
|
12
|
+
Python, with allocation results checked against the R package
|
|
13
|
+
[FSM](https://cran.r-project.org/package=FSM). It works with NumPy arrays and
|
|
14
|
+
pandas data frames and includes balance diagnostics and randomization tests.
|
|
15
|
+
The contribution is a tested Python implementation, documented corrections,
|
|
16
|
+
and reproducible examples; the method is due to the authors cited below.
|
|
17
|
+
|
|
18
|
+
## How it works
|
|
19
|
+
|
|
20
|
+
The groups take turns choosing units, like captains picking teams. A random
|
|
21
|
+
draw fixes the order of turns, under a rule that never lets one group get far
|
|
22
|
+
ahead of its share. On its turn a group takes the remaining unit that most
|
|
23
|
+
improves its own design: by default, the unit that most increases the
|
|
24
|
+
determinant of its X'X matrix (D-optimality). Every group chases the same goal,
|
|
25
|
+
so the groups come out balanced. The turn order is random, so
|
|
26
|
+
randomization-based inference still applies.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
Requires Python 3.12 or newer.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install finite-selection
|
|
34
|
+
pip install "finite-selection[data,plot]" # example data and love plots
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Example
|
|
38
|
+
|
|
39
|
+
This splits the 445 men of the National Supported Work data into groups of
|
|
40
|
+
222 and 223, once with the FSM and once by complete randomization. The table
|
|
41
|
+
reports TASMD for the first group: the distance between its covariate means and
|
|
42
|
+
the full-sample means, in standard deviations.
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import numpy as np
|
|
46
|
+
import finite_selection as fs
|
|
47
|
+
|
|
48
|
+
x = fs.lalonde()
|
|
49
|
+
rng = np.random.default_rng(2026)
|
|
50
|
+
|
|
51
|
+
order = fs.som([222, 223], method="scomars", rng=rng) # who chooses when
|
|
52
|
+
fsm_z = fs.fsm(x, order, rng=rng).assignment # who goes where
|
|
53
|
+
crd_z = fs.crd([222, 223], rng=rng) # complete randomization
|
|
54
|
+
|
|
55
|
+
print(fs.tasmd_rand(x, {"CRD": crd_z, "FSM": fsm_z}).round(3))
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
CRD FSM
|
|
60
|
+
Age 0.066 0.002
|
|
61
|
+
Education 0.004 0.004
|
|
62
|
+
Black 0.023 0.011
|
|
63
|
+
Hispanic 0.055 0.007
|
|
64
|
+
Married 0.043 0.007
|
|
65
|
+
Nodegree 0.018 0.004
|
|
66
|
+
Re74 0.016 0.006
|
|
67
|
+
Re75 0.006 0.002
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The FSM group sits within 0.011 standard deviations of the full sample on
|
|
71
|
+
every covariate. The randomized group is off by up to 0.066, on age. That is
|
|
72
|
+
one draw of each. Over 200 draws, the average TASMD per covariate is 0.034 to
|
|
73
|
+
0.041 under complete randomization and 0.004 to 0.008 under the FSM.
|
|
74
|
+
`tasmd_rand` reports these averages when given a matrix of assignments.
|
|
75
|
+
|
|
76
|
+
The package also allocates units that arrive in batches (`fsm_batch`), offers
|
|
77
|
+
ten other selection functions, and covers the analysis side: Fisher
|
|
78
|
+
randomization tests (`perm_test`), effective sample sizes for comparing designs
|
|
79
|
+
(`ess_rand`, `ess_model`), squares and interactions of the covariates
|
|
80
|
+
(`make_sq_inter`), and love plots (`love_plot`). The
|
|
81
|
+
[user guide](https://finite-sample.github.io/finite-selection/guide.html) runs a full experiment with them.
|
|
82
|
+
|
|
83
|
+
## What it assumes
|
|
84
|
+
|
|
85
|
+
The FSM needs every unit and its covariates before assignment starts, so it
|
|
86
|
+
suits experiments that enroll a known list, not ones that recruit as they go.
|
|
87
|
+
It balances the columns you give it. Balance on squares or interactions
|
|
88
|
+
requires passing them in, through `make_sq_inter` for example. Against outcome
|
|
89
|
+
components it cannot see, it can increase variance relative to complete
|
|
90
|
+
randomization. Covariate
|
|
91
|
+
balance alone does not guarantee more precise estimates for every outcome.
|
|
92
|
+
The [JRSS-A discussion](https://doi.org/10.1093/jrsssa/qnag030) examines this
|
|
93
|
+
robustness concern. Run time grows with the square of the sample: about 0.1 seconds for 445
|
|
94
|
+
units and 7 seconds for 5,000.
|
|
95
|
+
|
|
96
|
+
## Agreement with R
|
|
97
|
+
|
|
98
|
+
The script `tests/fixtures/make_r_fixtures.R` runs R's exported functions on a
|
|
99
|
+
grid of cases and saves their inputs and outputs. The test suite checks the
|
|
100
|
+
Python functions against those records:
|
|
101
|
+
|
|
102
|
+
- Given the same turn order, `fsm` reproduces R's allocation and selection
|
|
103
|
+
sequence in all 67 cases, which span the 11 selection functions, two to four
|
|
104
|
+
groups, and the options (intercept, scaling, ridge size, `Q_initial`,
|
|
105
|
+
collinear data). `fsm_batch` does the same in 3 cases.
|
|
106
|
+
- Random draws (`som`, `crd`) match R in distribution over 10,000 draws. R and
|
|
107
|
+
numpy use different random number generators, so individual draws differ.
|
|
108
|
+
- In several places R 1.0.0 departs from its own documentation, and Python
|
|
109
|
+
follows the documentation. For example, R's `ess_rand` reads only the first N
|
|
110
|
+
assignments, and its `perm_test` ignores a nonzero null effect. Fixes are
|
|
111
|
+
proposed upstream, and [Behaviour and parity with R](https://finite-sample.github.io/finite-selection/behavior.html) lists
|
|
112
|
+
each departure with its test.
|
|
113
|
+
|
|
114
|
+
`perm_test` imputes the two-group sharp null for every supported contrast,
|
|
115
|
+
including when `tau=0`. Sampled reference assignments use the Monte Carlo
|
|
116
|
+
correction `(b + 1) / (B + 1)`; `exact=True` is for a complete, equally weighted
|
|
117
|
+
reference distribution. Rank tests and tests with more than two groups support
|
|
118
|
+
only the sharp no-effect null.
|
|
119
|
+
|
|
120
|
+
## Credits
|
|
121
|
+
|
|
122
|
+
Carl N. Morris introduced the FSM (1979, *Journal of Econometrics* 11, 43-61).
|
|
123
|
+
Ambarish Chattopadhyay, Carl N. Morris and José R. Zubizarreta recast it in the
|
|
124
|
+
potential-outcomes framework and wrote the R package FSM, described in
|
|
125
|
+
"Randomized and balanced allocation of units into treatment groups using the
|
|
126
|
+
finite selection model for R" (arXiv:2105.02393) and "Balanced and robust
|
|
127
|
+
randomized treatment assignments: the finite selection model for the Health
|
|
128
|
+
Insurance Experiment and beyond" (*JRSS-A* 189(4), 2026; arXiv:2205.09736).
|
|
129
|
+
This package is an independent implementation checked against theirs. The
|
|
130
|
+
bundled data is Dehejia and Wahba's subset of the National Supported Work
|
|
131
|
+
demonstration (LaLonde 1986), from
|
|
132
|
+
[NBER](https://users.nber.org/~rdehejia/nswdata.html).
|
|
133
|
+
|
|
134
|
+
Cite the papers when you use the method, and this package (`CITATION.cff`) when
|
|
135
|
+
you use the software.
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "finite-selection"
|
|
3
|
+
description = "Finite Selection Model for randomized, balanced allocation of units to treatment groups"
|
|
4
|
+
readme = "README.md"
|
|
5
|
+
license = "MIT"
|
|
6
|
+
license-files = ["LICENSE"]
|
|
7
|
+
requires-python = ">=3.12"
|
|
8
|
+
version = "0.1.0"
|
|
9
|
+
keywords = [
|
|
10
|
+
"experimental design",
|
|
11
|
+
"randomization",
|
|
12
|
+
"covariate balance",
|
|
13
|
+
"finite selection model",
|
|
14
|
+
"causal inference",
|
|
15
|
+
"randomized controlled trials",
|
|
16
|
+
]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 4 - Beta",
|
|
19
|
+
"Intended Audience :: Science/Research",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
26
|
+
"Typing :: Typed",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"numpy>=2.0",
|
|
30
|
+
"pandas>=2.2",
|
|
31
|
+
"scipy>=1.11",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[[project.authors]]
|
|
35
|
+
name = "Gaurav Sood"
|
|
36
|
+
email = "gsood07@gmail.com"
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://github.com/finite-sample/finite-selection"
|
|
40
|
+
Documentation = "https://finite-sample.github.io/finite-selection/"
|
|
41
|
+
Repository = "https://github.com/finite-sample/finite-selection"
|
|
42
|
+
Issues = "https://github.com/finite-sample/finite-selection/issues"
|
|
43
|
+
Changelog = "https://github.com/finite-sample/finite-selection/blob/main/CHANGELOG.md"
|
|
44
|
+
|
|
45
|
+
[project.optional-dependencies]
|
|
46
|
+
plot = ["matplotlib>=3.8"]
|
|
47
|
+
data = ["pyarrow>=15"]
|
|
48
|
+
|
|
49
|
+
[build-system]
|
|
50
|
+
requires = ["uv_build>=0.12.5,<0.13"]
|
|
51
|
+
build-backend = "uv_build"
|
|
52
|
+
|
|
53
|
+
[tool.uv.build-backend]
|
|
54
|
+
module-name = "finite_selection"
|
|
55
|
+
|
|
56
|
+
[tool.ruff]
|
|
57
|
+
line-length = 88
|
|
58
|
+
target-version = "py312"
|
|
59
|
+
|
|
60
|
+
[tool.ruff.lint]
|
|
61
|
+
external = ["DOC"]
|
|
62
|
+
select = [
|
|
63
|
+
"E",
|
|
64
|
+
"W",
|
|
65
|
+
"F",
|
|
66
|
+
"I",
|
|
67
|
+
"B",
|
|
68
|
+
"C4",
|
|
69
|
+
"UP",
|
|
70
|
+
"N",
|
|
71
|
+
"D",
|
|
72
|
+
"S",
|
|
73
|
+
"SIM",
|
|
74
|
+
"T20",
|
|
75
|
+
"PT",
|
|
76
|
+
"RUF",
|
|
77
|
+
"PTH",
|
|
78
|
+
"RET",
|
|
79
|
+
"PIE",
|
|
80
|
+
"FURB",
|
|
81
|
+
"PERF",
|
|
82
|
+
"DTZ",
|
|
83
|
+
"LOG",
|
|
84
|
+
"G",
|
|
85
|
+
"TC",
|
|
86
|
+
"FLY",
|
|
87
|
+
"RSE",
|
|
88
|
+
"SLOT",
|
|
89
|
+
"FA",
|
|
90
|
+
"A",
|
|
91
|
+
"EXE",
|
|
92
|
+
"ICN",
|
|
93
|
+
"PGH",
|
|
94
|
+
"PLE",
|
|
95
|
+
"ARG",
|
|
96
|
+
"SLF",
|
|
97
|
+
]
|
|
98
|
+
ignore = [
|
|
99
|
+
"D203",
|
|
100
|
+
"D213",
|
|
101
|
+
"W191",
|
|
102
|
+
"D206",
|
|
103
|
+
"D300",
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
[tool.ruff.lint.pydocstyle]
|
|
107
|
+
convention = "google"
|
|
108
|
+
|
|
109
|
+
[tool.ruff.lint.per-file-ignores]
|
|
110
|
+
"tests/**" = [
|
|
111
|
+
"S101",
|
|
112
|
+
"D",
|
|
113
|
+
"ARG",
|
|
114
|
+
"SLF",
|
|
115
|
+
]
|
|
116
|
+
"docs/**" = ["D"]
|
|
117
|
+
|
|
118
|
+
[tool.pyright]
|
|
119
|
+
include = ["src"]
|
|
120
|
+
typeCheckingMode = "standard"
|
|
121
|
+
|
|
122
|
+
[tool.pydoclint]
|
|
123
|
+
style = "google"
|
|
124
|
+
arg-type-hints-in-docstring = false
|
|
125
|
+
check-return-types = false
|
|
126
|
+
check-yield-types = false
|
|
127
|
+
check-class-attributes = false
|
|
128
|
+
allow-init-docstring = true
|
|
129
|
+
exclude = '\.venv|tests|docs'
|
|
130
|
+
|
|
131
|
+
[tool.pytest.ini_options]
|
|
132
|
+
minversion = "8"
|
|
133
|
+
testpaths = ["tests"]
|
|
134
|
+
log_level = "INFO"
|
|
135
|
+
xfail_strict = true
|
|
136
|
+
filterwarnings = ["error"]
|
|
137
|
+
addopts = [
|
|
138
|
+
"-ra",
|
|
139
|
+
"--strict-config",
|
|
140
|
+
"--strict-markers",
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
[tool.coverage.run]
|
|
144
|
+
source = ["src"]
|
|
145
|
+
|
|
146
|
+
[tool.preen]
|
|
147
|
+
|
|
148
|
+
[tool.codespell]
|
|
149
|
+
ignore-words-list = "som"
|
|
150
|
+
|
|
151
|
+
[dependency-groups]
|
|
152
|
+
dev = [
|
|
153
|
+
"ruff>=0.14",
|
|
154
|
+
"pyright>=1.1.390",
|
|
155
|
+
"pre-commit>=4",
|
|
156
|
+
{ include-group = "test" },
|
|
157
|
+
]
|
|
158
|
+
test = [
|
|
159
|
+
"matplotlib>=3.8",
|
|
160
|
+
"pyarrow>=15",
|
|
161
|
+
"pytest>=8",
|
|
162
|
+
"pytest-cov>=6",
|
|
163
|
+
]
|
|
164
|
+
docs = [
|
|
165
|
+
"sphinx>=8",
|
|
166
|
+
"py-canon @ git+https://github.com/gojiplus/py-canon@v1",
|
|
167
|
+
"furo",
|
|
168
|
+
"myst-parser",
|
|
169
|
+
"sphinx-copybutton",
|
|
170
|
+
]
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "finite-selection"
|
|
3
|
+
description = "Finite Selection Model for randomized, balanced allocation of units to treatment groups"
|
|
4
|
+
readme = "README.md"
|
|
5
|
+
license = "MIT"
|
|
6
|
+
license-files = ["LICENSE"]
|
|
7
|
+
authors = [{ name = "Gaurav Sood", email = "gsood07@gmail.com" }]
|
|
8
|
+
requires-python = ">=3.12"
|
|
9
|
+
version = "0.1.0"
|
|
10
|
+
keywords = [
|
|
11
|
+
"experimental design",
|
|
12
|
+
"randomization",
|
|
13
|
+
"covariate balance",
|
|
14
|
+
"finite selection model",
|
|
15
|
+
"causal inference",
|
|
16
|
+
"randomized controlled trials",
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 4 - Beta",
|
|
20
|
+
"Intended Audience :: Science/Research",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Programming Language :: Python :: 3.14",
|
|
26
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
27
|
+
"Typing :: Typed",
|
|
28
|
+
]
|
|
29
|
+
dependencies = [
|
|
30
|
+
"numpy>=2.0",
|
|
31
|
+
"pandas>=2.2",
|
|
32
|
+
"scipy>=1.11",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/finite-sample/finite-selection"
|
|
37
|
+
Documentation = "https://finite-sample.github.io/finite-selection/"
|
|
38
|
+
Repository = "https://github.com/finite-sample/finite-selection"
|
|
39
|
+
Issues = "https://github.com/finite-sample/finite-selection/issues"
|
|
40
|
+
Changelog = "https://github.com/finite-sample/finite-selection/blob/main/CHANGELOG.md"
|
|
41
|
+
|
|
42
|
+
[project.optional-dependencies]
|
|
43
|
+
plot = [
|
|
44
|
+
"matplotlib>=3.8",
|
|
45
|
+
]
|
|
46
|
+
data = [
|
|
47
|
+
"pyarrow>=15",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[build-system]
|
|
51
|
+
requires = ["uv_build>=0.12.5,<0.13"]
|
|
52
|
+
build-backend = "uv_build"
|
|
53
|
+
|
|
54
|
+
[tool.uv.build-backend]
|
|
55
|
+
module-name = "finite_selection"
|
|
56
|
+
|
|
57
|
+
[dependency-groups]
|
|
58
|
+
dev = [
|
|
59
|
+
"ruff>=0.14",
|
|
60
|
+
"pyright>=1.1.390",
|
|
61
|
+
"pre-commit>=4",
|
|
62
|
+
{ include-group = "test" },
|
|
63
|
+
]
|
|
64
|
+
test = [
|
|
65
|
+
"matplotlib>=3.8",
|
|
66
|
+
"pyarrow>=15",
|
|
67
|
+
"pytest>=8",
|
|
68
|
+
"pytest-cov>=6",
|
|
69
|
+
]
|
|
70
|
+
docs = [
|
|
71
|
+
"sphinx>=8",
|
|
72
|
+
"py-canon @ git+https://github.com/gojiplus/py-canon@v1",
|
|
73
|
+
"furo",
|
|
74
|
+
"myst-parser",
|
|
75
|
+
"sphinx-copybutton",
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
[tool.ruff]
|
|
79
|
+
line-length = 88
|
|
80
|
+
target-version = "py312"
|
|
81
|
+
|
|
82
|
+
[tool.ruff.lint]
|
|
83
|
+
external = ["DOC"]
|
|
84
|
+
select = [
|
|
85
|
+
"E", "W", "F", "I", "B", "C4", "UP", "N", "D", "S", "SIM", "T20", "PT", "RUF",
|
|
86
|
+
"PTH", "RET", "PIE", "FURB", "PERF", "DTZ", "LOG", "G", "TC", "FLY",
|
|
87
|
+
"RSE", "SLOT", "FA", "A", "EXE", "ICN", "PGH", "PLE", "ARG", "SLF",
|
|
88
|
+
]
|
|
89
|
+
# D203/D213: the google convention this standard picks. W191/D206/D300:
|
|
90
|
+
# ruff's own docs list these as always incompatible with `ruff format`,
|
|
91
|
+
# which the standard also runs.
|
|
92
|
+
ignore = ["D203", "D213", "W191", "D206", "D300"]
|
|
93
|
+
|
|
94
|
+
[tool.ruff.lint.pydocstyle]
|
|
95
|
+
convention = "google"
|
|
96
|
+
|
|
97
|
+
[tool.ruff.lint.per-file-ignores]
|
|
98
|
+
# Unused fixture arguments and private-member access are how tests are written.
|
|
99
|
+
"tests/**" = ["S101", "D", "ARG", "SLF"]
|
|
100
|
+
"docs/**" = ["D"]
|
|
101
|
+
|
|
102
|
+
[tool.pyright]
|
|
103
|
+
include = ["src"]
|
|
104
|
+
typeCheckingMode = "standard"
|
|
105
|
+
|
|
106
|
+
[tool.pydoclint]
|
|
107
|
+
style = "google"
|
|
108
|
+
arg-type-hints-in-docstring = false
|
|
109
|
+
check-return-types = false
|
|
110
|
+
check-yield-types = false
|
|
111
|
+
check-class-attributes = false
|
|
112
|
+
allow-init-docstring = true
|
|
113
|
+
exclude = '\.venv|tests|docs'
|
|
114
|
+
|
|
115
|
+
[tool.pytest.ini_options]
|
|
116
|
+
minversion = "8"
|
|
117
|
+
testpaths = ["tests"]
|
|
118
|
+
log_level = "INFO"
|
|
119
|
+
xfail_strict = true
|
|
120
|
+
filterwarnings = ["error"]
|
|
121
|
+
addopts = ["-ra", "--strict-config", "--strict-markers"]
|
|
122
|
+
|
|
123
|
+
[tool.coverage.run]
|
|
124
|
+
source = ["src"]
|
|
125
|
+
|
|
126
|
+
[tool.preen]
|
|
127
|
+
|
|
128
|
+
[tool.codespell]
|
|
129
|
+
# som is the selection order matrix function, named as in the R package.
|
|
130
|
+
ignore-words-list = "som"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Finite Selection Model: randomized, balanced allocation of units to groups."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
from .core import FSMResult, fsm, fsm_batch
|
|
6
|
+
from .datasets import lalonde
|
|
7
|
+
from .features import make_sq_inter
|
|
8
|
+
from .inference import (
|
|
9
|
+
PermTestResult,
|
|
10
|
+
TasmdSummary,
|
|
11
|
+
crd,
|
|
12
|
+
ess_model,
|
|
13
|
+
ess_rand,
|
|
14
|
+
perm_test,
|
|
15
|
+
tasmd,
|
|
16
|
+
tasmd_rand,
|
|
17
|
+
)
|
|
18
|
+
from .plot import asmd, love_plot
|
|
19
|
+
from .som import SelectionOrder, scomars_probs, som
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
__version__ = version("finite-selection")
|
|
23
|
+
except PackageNotFoundError: # pragma: no cover - not installed
|
|
24
|
+
__version__ = "0.0.0"
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"FSMResult",
|
|
28
|
+
"PermTestResult",
|
|
29
|
+
"SelectionOrder",
|
|
30
|
+
"TasmdSummary",
|
|
31
|
+
"asmd",
|
|
32
|
+
"crd",
|
|
33
|
+
"ess_model",
|
|
34
|
+
"ess_rand",
|
|
35
|
+
"fsm",
|
|
36
|
+
"fsm_batch",
|
|
37
|
+
"lalonde",
|
|
38
|
+
"love_plot",
|
|
39
|
+
"make_sq_inter",
|
|
40
|
+
"perm_test",
|
|
41
|
+
"scomars_probs",
|
|
42
|
+
"som",
|
|
43
|
+
"tasmd",
|
|
44
|
+
"tasmd_rand",
|
|
45
|
+
]
|