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.
- ratio_study/__init__.py +241 -0
- ratio_study/_data.py +25 -0
- ratio_study/_version.py +3 -0
- ratio_study/blinder_oaxaca.py +992 -0
- ratio_study/confint.py +238 -0
- ratio_study/data/ratio_study_sample_dataset.parquet +0 -0
- ratio_study/gini.py +1058 -0
- ratio_study/graphs.py +854 -0
- ratio_study/helpers.py +351 -0
- ratio_study/indicators.py +453 -0
- ratio_study/mcp_server.py +0 -0
- ratio_study/presets.py +387 -0
- ratio_study/ratio_study.py +1532 -0
- ratio_study/reporting.py +606 -0
- ratio_study-0.3.0.dist-info/METADATA +51 -0
- ratio_study-0.3.0.dist-info/RECORD +19 -0
- ratio_study-0.3.0.dist-info/WHEEL +5 -0
- ratio_study-0.3.0.dist-info/licenses/LICENSE +674 -0
- ratio_study-0.3.0.dist-info/top_level.txt +1 -0
ratio_study/__init__.py
ADDED
|
@@ -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())
|
ratio_study/_version.py
ADDED