ratio-study 0.3.0__py3-none-any.whl

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.
@@ -0,0 +1,241 @@
1
+ """ Ratio Studies Package
2
+ This package makes easier running a Ratio Study, an instrument on the analysis of real property valuation models
3
+
4
+ Based on IAAO's Standard on Ratio Studies available at https://www.iaao.org/media/standards/Standard_on_Ratio_Studies.pdf
5
+ and on the following work:
6
+ Quintos, C. (2021). A Gini decomposition of the sources of inequality in property assessments. Journal of
7
+ Property Tax Assessment & Administration, 18(2). Retrieved from https://researchexchange.iaao.org/ jptaa/vol18/iss2/6
8
+ Quintos, C. (2020). A Gini measure for vertical equity in property assessments. Journal of Property Tax
9
+ Assessment & Administration, 17(2). Retrieved from https://researchexchange.iaao.org/jptaa/vol17/iss2/ 2
10
+ Thomas J. DiCiccio. Bradley Efron. "Bootstrap confidence intervals." Statist. Sci. 11 (3) 189 - 228, August 1996.
11
+ https://doi.org/10.1214/ss/1032280214
12
+ Formulas on article by David Zaslavsky: https://www.ellipsix.net/blog/2012/11/the-gini-coefficient-for-distribution-inequality.html
13
+ """
14
+ __author__ = 'Eric Kutchukian @ MPAC'
15
+ __copyright__ = 'Copyright 2026, Municipal Property Assessment Corporation'
16
+ __credits__ = ['Eric Kutchukian, James Ellens, Micheal Boateng, James Bryan, James Gilbert, Mohammad Jaber']
17
+ __license__ = 'GPL v3'
18
+ __maintainer__ = '{Eric Kutchukian}'
19
+ __email__ = '{eric.kutchukian@mpac.ca}'
20
+ __status__ = '{Dev}'
21
+
22
+
23
+ """ratio_study — ratio-study analysis for real-property assessment.
24
+
25
+ Quick start
26
+ -----------
27
+ >>> from ratio_study import ratios, IAAO_RESIDENTIAL
28
+ >>> results = ratios(df, "assessed_value", "sale_price", config=IAAO_RESIDENTIAL)
29
+ """
30
+
31
+ from ._version import __version__
32
+ from ratio_study._data import load_sample_dataset, sample_dataset_path
33
+
34
+ __all__ = ["load_sample_dataset", "sample_dataset_path", ...]
35
+
36
+ __all__ = [
37
+ "load_sample_dataset",
38
+ "sample_dataset_path",
39
+ 'rts_calculator',
40
+ 'ratios',
41
+ 'ratios_report',
42
+ 'gini_stats',
43
+ 'gini_decomp',
44
+ 'gini_factors',
45
+ 'gini_lorenz_plot',
46
+ 'compare_ratios',
47
+ 'vei_boxplot',
48
+ 'vei_analysis',
49
+ 'asr_median',
50
+ 'asr_mean',
51
+ 'cod',
52
+ 'cod_residual',
53
+ 'prd',
54
+ 'prb',
55
+ 'rmse',
56
+ 'mae',
57
+ 'mape',
58
+ 'mdmape',
59
+ 'fsd',
60
+ 'CoV_adj',
61
+ 'CoC',
62
+ 'compute_median_ci',
63
+ 'compute_median_ci_on_binomial',
64
+ 'bo_decompose',
65
+ 'bo_multi_decomposition',
66
+ 'bo_format_table',
67
+ 'bo_coefficient_plot',
68
+ 'bo_decomposition_plot',
69
+ 'bo_detail_plot',
70
+ ]
71
+
72
+
73
+ def __getattr__(name):
74
+ if name == "ratios_calculator":
75
+ from .ratio_study import ratios_calculator
76
+ return ratios_calculator
77
+
78
+ if name == "ratios":
79
+ from .ratio_study import ratios
80
+ return ratios
81
+
82
+ if name == "ratios_report":
83
+ from .ratio_study import ratios_report
84
+ return ratios_report
85
+
86
+ if name == "gini_stats":
87
+ from .gini import gini_stats
88
+ return gini_stats
89
+
90
+ if name == "gini_decomp":
91
+ from .gini import gini_decomp
92
+ return gini_decomp
93
+
94
+ if name == "gini_factors":
95
+ from .gini import gini_factors
96
+ return gini_factors
97
+
98
+ if name == "gini_lorenz_plot":
99
+ from .gini import gini_lorenz_plot
100
+ return gini_lorenz_plot
101
+
102
+ if name == "compare_ratios":
103
+ from .reporting import compare_ratios
104
+ return compare_ratios
105
+
106
+ if name == "vei_boxplot":
107
+ from .graphs import vei_boxplot
108
+ return vei_boxplot
109
+
110
+ if name == "vei_analysis":
111
+ from .indicators import vei_analysis
112
+ return vei_analysis
113
+
114
+ if name == "asr_median":
115
+ from .indicators import asr_median
116
+ return asr_median
117
+
118
+ if name == "asr_mean":
119
+ from .indicators import asr_mean
120
+ return asr_mean
121
+
122
+ if name == "cod":
123
+ from .indicators import cod
124
+ return cod
125
+
126
+ if name == "cod_residual":
127
+ from .indicators import cod_residual
128
+ return cod_residual
129
+
130
+ if name == "prd":
131
+ from .indicators import prd
132
+ return prd
133
+
134
+ if name == "prb":
135
+ from .indicators import prb
136
+ return prb
137
+
138
+ if name == "rmse":
139
+ from .indicators import rmse
140
+ return rmse
141
+
142
+ if name == "mae":
143
+ from .indicators import mae
144
+ return mae
145
+
146
+ if name == "mape":
147
+ from .indicators import mape
148
+ return mape
149
+
150
+ if name == "mdmape":
151
+ from .indicators import mdmape
152
+ return mdmape
153
+
154
+ if name == "fsd":
155
+ from .indicators import fsd
156
+ return fsd
157
+
158
+ if name == "CoV_adj":
159
+ from .indicators import CoV_adj
160
+ return CoV_adj
161
+
162
+ if name == "CoC":
163
+ from .indicators import CoC
164
+ return CoC
165
+
166
+ if name == "compute_median_ci":
167
+ from .confint import compute_median_ci
168
+ return compute_median_ci
169
+
170
+ if name == "compute_median_ci_on_binomial":
171
+ from .confint import compute_median_ci_on_binomial
172
+ return compute_median_ci_on_binomial
173
+
174
+ # ── Blinder-Oaxaca decomposition ──────────────────────────
175
+ if name == "bo_decompose":
176
+ from .blinder_oaxaca import bo_decompose
177
+ return bo_decompose
178
+
179
+ if name == "bo_multi_decomposition":
180
+ from .blinder_oaxaca import bo_multi_decomposition
181
+ return bo_multi_decomposition
182
+
183
+ if name == "bo_format_table":
184
+ from .blinder_oaxaca import bo_format_table
185
+ return bo_format_table
186
+
187
+ if name == "bo_coefficient_plot":
188
+ from .blinder_oaxaca import bo_coefficient_plot
189
+ return bo_coefficient_plot
190
+
191
+ if name == "bo_decomposition_plot":
192
+ from .blinder_oaxaca import bo_decomposition_plot
193
+ return bo_decomposition_plot
194
+
195
+ if name == "bo_detail_plot":
196
+ from .blinder_oaxaca import bo_detail_plot
197
+ return bo_detail_plot
198
+
199
+ raise AttributeError(f"module {__name__} has no attribute {name}")
200
+
201
+
202
+ # from __future__ import annotations
203
+
204
+ # from ratio_study._version import __version__
205
+ # from ratio_study.presets import (
206
+ # IAAO_INCOME_PRODUCING,
207
+ # IAAO_RESIDENTIAL,
208
+ # IAAO_VACANT_LAND,
209
+ # KNOWN_INDICATORS,
210
+ # MPAC_DEFAULT,
211
+ # STRICT,
212
+ # BootstrapConfig,
213
+ # ExcelConfig,
214
+ # GiniConfig,
215
+ # GraphsConfig,
216
+ # PdfConfig,
217
+ # RatioStudyConfig,
218
+ # )
219
+
220
+ # # Phase 2+ imports will be added here as modules are created.
221
+ # # e.g.:
222
+ # # from ratio_study.ratio_study import ratios, ratios_report, analyze
223
+ # # from ratio_study.ratio_study import gini_stats, gini_decomp, vei_analysis
224
+
225
+ # __all__ = [
226
+ # "__version__",
227
+ # # config models
228
+ # "RatioStudyConfig",
229
+ # "BootstrapConfig",
230
+ # "GiniConfig",
231
+ # "PdfConfig",
232
+ # "GraphsConfig",
233
+ # "ExcelConfig",
234
+ # "KNOWN_INDICATORS",
235
+ # # presets
236
+ # "IAAO_RESIDENTIAL",
237
+ # "IAAO_INCOME_PRODUCING",
238
+ # "IAAO_VACANT_LAND",
239
+ # "STRICT",
240
+ # "MPAC_DEFAULT",
241
+ # ]
ratio_study/_data.py ADDED
@@ -0,0 +1,25 @@
1
+ """Internal helpers for accessing packaged data files."""
2
+ from importlib import resources
3
+ from pathlib import Path
4
+ import pandas as pd
5
+
6
+
7
+ def sample_dataset_path() -> Path:
8
+ """Return a filesystem path to the bundled sample dataset.
9
+
10
+ Works whether the package is installed normally, in editable mode,
11
+ or run from a wheel/zip.
12
+ """
13
+ # files() returns a Traversable; for parquet we need a real path
14
+ # because pyarrow/fastparquet read from disk
15
+ data_files = resources.files("ratio_study").joinpath(
16
+ "data", "ratio_study_sample_dataset.parquet"
17
+ )
18
+ # as_file() materializes to disk if needed (e.g., inside a zip)
19
+ with resources.as_file(data_files) as p:
20
+ return Path(p)
21
+
22
+
23
+ def load_sample_dataset() -> pd.DataFrame:
24
+ """Load the bundled sample dataset as a pandas DataFrame."""
25
+ return pd.read_parquet(sample_dataset_path())
@@ -0,0 +1,3 @@
1
+ from __future__ import annotations
2
+
3
+ __version__ = "0.3.0"