diff --git a/.Rhistory b/.Rhistory deleted file mode 100644 index ec3efcc..0000000 --- a/.Rhistory +++ /dev/null @@ -1,350 +0,0 @@ -# Import necessary libraries -import numpy as np -import statsmodels.api as sm -from .utils import check_inputs -# COD, PRD, PRB functions -def cod(ratio): -""" -COD is the average absolute percent deviation from the -median ratio. It is a measure of horizontal equity in assessment. -Horizontal equity means properties with a similar fair market value -should be similarly assessed. -Lower COD indicates higher uniformity/horizontal equity in assessment. -The IAAO sets uniformity standards that define generally accepted ranges -for COD depending on property class. See `IAAO Standard on Ratio Studies`_ -Section 9.1, Table 1.3 for a full list of standard COD ranges. -.. _IAAO Standard on Ratio Studies: https://www.iaao.org/media/standards/Standard_on_Ratio_Studies.pdf -.. note:: -The IAAO recommends trimming outlier ratios before calculating COD, -as it is extremely sensitive to large outliers. The typical method used is -dropping values beyond 3 * IQR (inner-quartile range). See -`IAAO Standard on Ratio Studies`_ Appendix B.1. -:param ratio: -A numeric vector of ratios centered around 1, where the -numerator of the ratio is the estimated fair market value and the -denominator is the actual sale price. -:type ratio: numeric -:return: A numeric vector containing the COD of ``ratios``. -:rtype: float -:Example: -.. code-block:: python -# Calculate COD: -import assesspy as ap -ap.cod(ap.ratios_sample().ratio) -""" -# Input checking and error handling -check_inputs(ratio) -ratio = np.array(ratio) -n = ratio.size -median_ratio = np.median(ratio) -cod = 100 / median_ratio * (sum(abs(ratio - median_ratio)) / n) -return cod -def prd(assessed, sale_price): -""" -PRD is the mean ratio divided by the mean ratio weighted by sale -price. It is a measure of vertical equity in assessment. Vertical equity -means that properties at different levels of the income distribution -should be similarly assessed. -PRD centers slightly above 1 and has a generally accepted value of between -0.98 and 1.03, as defined in the `IAAO Standard on Ratio Studies`_ -Section 9.2.7. Higher PRD values indicate regressivity in assessment. -.. _IAAO Standard on Ratio Studies: https://www.iaao.org/media/standards/Standard_on_Ratio_Studies.pdf -.. note:: -The IAAO recommends trimming outlier ratios before calculating PRD, -as it is extremely sensitive to large outliers. PRD is being deprecated in -favor of PRB, which is less sensitive to outliers and easier to interpret. -:param assessed: -A numeric vector of assessed values. Must be the same length as ``sale_price``. -:param sale_price: -A numeric vector of sale prices. Must be the same length -as ``assessed``. -:type assessed: numeric -:type sale_price: numeric -:return: A numeric vector containing the PRD of the input vectors. -:rtype: float -:Example: -.. code-block:: python -# Calculate PRD: -import assesspy as ap -ap.prd(ap.ratios_sample().assessed, ap.ratios_sample().sale_price) -""" -assessed = np.array(assessed) -sale_price = np.array(sale_price) -# Input checking and error handling -check_inputs(assessed, sale_price) -ratio = assessed / sale_price -prd = ratio.mean() / np.average(a=ratio, weights=sale_price) -return prd -def prb(assessed, sale_price, round=None): -r""" -PRB is an index of vertical equity that quantifies the -relationship betweem ratios and assessed values as a percentage. In -concrete terms, a PRB of 0.02 indicates that, on average, ratios increase -by 2\% whenever assessed values increase by 100 percent. -PRB is centered around 0 and has a generally accepted value of between --0.05 and 0.05, as defined in the `IAAO Standard on Ratio Studies`_ -Section 9.2.7. Higher PRB values indicate progressivity in assessment, -while negative values indicate regressivity. -.. _IAAO Standard on Ratio Studies: https://www.iaao.org/media/standards/Standard_on_Ratio_Studies.pdf -.. note: PRB is significantly less sensitive to outliers than PRD or COD. -:param assessed: -A numeric vector of assessed values. Must be the same -length as ``sale_price``. -:param sale_price: -A numeric vector of sale prices. Must be the same length -as ``assessed``. -:param round: -Indicate desired rounding for output. -:type assessed: numeric -:type sale_price: numeric -:type round: int -:return: A numeric vector containing the PRB of the input vectors. -:rtype: float -:Example: -.. code-block:: python -# Calculate PRB: -import assesspy as ap -ap.prb(ap.ratios_sample().assessed, ap.ratios_sample().sale_price) -""" -assessed = np.array(assessed) -sale_price = np.array(sale_price) -# Input checking and error handling -check_inputs(assessed, sale_price) -ratio = assessed / sale_price -median_ratio = np.median(ratio) -lhs = (ratio - median_ratio) / median_ratio -rhs = np.log(((assessed / median_ratio) + sale_price) / 2) / np.log(2) -lhs = np.array(lhs) -rhs = np.array(rhs) -prb_model = sm.OLS(lhs, rhs).fit() -prb_val = float(prb_model.params) -prb_ci = prb_model.conf_int(alpha=0.05)[0].tolist() -if round is not None: -out = {"prb": np.round(prb_val, round), "95% ci": np.round(prb_ci, round)} -else: -out = {"prb": prb_val, "95% ci": prb_ci} -return out -# Functions to determine whether assessment fairness criteria has been met -def cod_met(x): -return 5 <= x <= 15 -def prd_met(x): -return 0.98 <= x <= 1.03 -def prb_met(x): -return -0.05 <= x <= 0.05 -import assesspy as ap -ap.prb(ap.ratios_sample().assessed, ap.ratios_sample().sale_price) -# Import necessary libraries -import pandas as pd -import pkg_resources -# Load pre-made ratios sample data. -def ratios_sample(): -""" -This sample was take from Evanston and New Trier in 2019. Ratios are -calculated using assessor certified (post-appeal) fair market values. -:return: -A data frame with 979 observation and 4 variables: -======================== ======================================================= -**assessed** (`float`) The fair market assessed value predicted by CCAO -assessment models, including any successful appeals -**sale_price** (`float`) The recorded sale price of this property -**ratio** (`float`) Sales ratio representing fair market value / sale price -**town** (`object`) Township name the property is in -======================== ======================================================= -:rtype: DataFrame -""" -stream = pkg_resources.resource_stream(__name__, "data/ratios_sample.parquet") -return pd.read_parquet(stream) -# Import necessary libraries -import numpy as np -import pandas as pd -from pandas.api.types import is_numeric_dtype -def check_inputs(*args): -out = [""] -for x in args: -# *args passed into *args can created nested tuples - unnest -if isinstance(x, tuple): -args = x -for x in args: -if type(x) == pd.core.frame.DataFrame: -raise Exception("Input cannot be a dataframe.") -check = pd.Series(x) -if not is_numeric_dtype(check): -raise Exception("All input vectors must be numeric.") -if check.isnull().values.any(): -out.append("\nInput vectors contain null values.") -if len(check) <= 1: -out.append("\nAll input vectors must have length greater than 1.") -if not all(np.isfinite(check) | check.isnull()): -out.append("\nInfinite values in input vectors.") -if any(check == 0): -out.append("\nInput vectors cannot contain values of 0.") -out = set(out) -if len(out) > 1: -raise Exception("".join(map(str, out))) -# Import necessary libraries -import numpy as np -import statsmodels.api as sm -from .utils import check_inputs -# COD, PRD, PRB functions -def cod(ratio): -""" -COD is the average absolute percent deviation from the -median ratio. It is a measure of horizontal equity in assessment. -Horizontal equity means properties with a similar fair market value -should be similarly assessed. -Lower COD indicates higher uniformity/horizontal equity in assessment. -The IAAO sets uniformity standards that define generally accepted ranges -for COD depending on property class. See `IAAO Standard on Ratio Studies`_ -Section 9.1, Table 1.3 for a full list of standard COD ranges. -.. _IAAO Standard on Ratio Studies: https://www.iaao.org/media/standards/Standard_on_Ratio_Studies.pdf -.. note:: -The IAAO recommends trimming outlier ratios before calculating COD, -as it is extremely sensitive to large outliers. The typical method used is -dropping values beyond 3 * IQR (inner-quartile range). See -`IAAO Standard on Ratio Studies`_ Appendix B.1. -:param ratio: -A numeric vector of ratios centered around 1, where the -numerator of the ratio is the estimated fair market value and the -denominator is the actual sale price. -:type ratio: numeric -:return: A numeric vector containing the COD of ``ratios``. -:rtype: float -:Example: -.. code-block:: python -# Calculate COD: -import assesspy as ap -ap.cod(ap.ratios_sample().ratio) -""" -# Input checking and error handling -check_inputs(ratio) -ratio = np.array(ratio) -n = ratio.size -median_ratio = np.median(ratio) -cod = 100 / median_ratio * (sum(abs(ratio - median_ratio)) / n) -return cod -def prd(assessed, sale_price): -""" -PRD is the mean ratio divided by the mean ratio weighted by sale -price. It is a measure of vertical equity in assessment. Vertical equity -means that properties at different levels of the income distribution -should be similarly assessed. -PRD centers slightly above 1 and has a generally accepted value of between -0.98 and 1.03, as defined in the `IAAO Standard on Ratio Studies`_ -Section 9.2.7. Higher PRD values indicate regressivity in assessment. -.. _IAAO Standard on Ratio Studies: https://www.iaao.org/media/standards/Standard_on_Ratio_Studies.pdf -.. note:: -The IAAO recommends trimming outlier ratios before calculating PRD, -as it is extremely sensitive to large outliers. PRD is being deprecated in -favor of PRB, which is less sensitive to outliers and easier to interpret. -:param assessed: -A numeric vector of assessed values. Must be the same length as ``sale_price``. -:param sale_price: -A numeric vector of sale prices. Must be the same length -as ``assessed``. -:type assessed: numeric -:type sale_price: numeric -:return: A numeric vector containing the PRD of the input vectors. -:rtype: float -:Example: -.. code-block:: python -# Calculate PRD: -import assesspy as ap -ap.prd(ap.ratios_sample().assessed, ap.ratios_sample().sale_price) -""" -assessed = np.array(assessed) -sale_price = np.array(sale_price) -# Input checking and error handling -check_inputs(assessed, sale_price) -ratio = assessed / sale_price -prd = ratio.mean() / np.average(a=ratio, weights=sale_price) -return prd -def prb(assessed, sale_price, round=None): -r""" -PRB is an index of vertical equity that quantifies the -relationship betweem ratios and assessed values as a percentage. In -concrete terms, a PRB of 0.02 indicates that, on average, ratios increase -by 2\% whenever assessed values increase by 100 percent. -PRB is centered around 0 and has a generally accepted value of between --0.05 and 0.05, as defined in the `IAAO Standard on Ratio Studies`_ -Section 9.2.7. Higher PRB values indicate progressivity in assessment, -while negative values indicate regressivity. -.. _IAAO Standard on Ratio Studies: https://www.iaao.org/media/standards/Standard_on_Ratio_Studies.pdf -.. note: PRB is significantly less sensitive to outliers than PRD or COD. -:param assessed: -A numeric vector of assessed values. Must be the same -length as ``sale_price``. -:param sale_price: -A numeric vector of sale prices. Must be the same length -as ``assessed``. -:param round: -Indicate desired rounding for output. -:type assessed: numeric -:type sale_price: numeric -:type round: int -:return: A numeric vector containing the PRB of the input vectors. -:rtype: float -:Example: -.. code-block:: python -# Calculate PRB: -import assesspy as ap -ap.prb(ap.ratios_sample().assessed, ap.ratios_sample().sale_price) -""" -assessed = np.array(assessed) -sale_price = np.array(sale_price) -# Input checking and error handling -check_inputs(assessed, sale_price) -ratio = assessed / sale_price -median_ratio = np.median(ratio) -lhs = (ratio - median_ratio) / median_ratio -rhs = np.log(((assessed / median_ratio) + sale_price) / 2) / np.log(2) -lhs = np.array(lhs) -rhs = np.array(rhs) -prb_model = sm.OLS(lhs, rhs).fit() -prb_val = float(prb_model.params) -prb_ci = prb_model.conf_int(alpha=0.05)[0].tolist() -if round is not None: -out = {"prb": np.round(prb_val, round), "95% ci": np.round(prb_ci, round)} -else: -out = {"prb": prb_val, "95% ci": prb_ci} -return out -# Functions to determine whether assessment fairness criteria has been met -def cod_met(x): -return 5 <= x <= 15 -def prd_met(x): -return 0.98 <= x <= 1.03 -def prb_met(x): -return -0.05 <= x <= 0.05 -ap.prb(ap.ratios_sample().assessed, ap.ratios_sample().sale_price) -# read the contents of your README file, remove image -from pathlib import Path -from setuptools import find_packages, setup -this_directory = Path(__file__).parent -image = '' -long_description = (this_directory / "README.md").read_text().replace(image, '') -setup( -name="assesspy", -version="1.0.2", -description="General purpose Python package for measuring assessment performance", -long_description=long_description, -long_description_content_type='text/markdown', -url="https://github.com/ccao-data/assesspy", -author="CCAO", -author_email="assessor.data@cookcountyil.gov", -license="AGPL-3", -packages=find_packages(), -install_requires=[ -"pandas", -"pyarrow", -"numpy", -"scipy", -"statsmodels" -], -setup_requires=["pytest-runner"], -tests_require=["pytest", "pytest-cov"], -include_package_data = True, -package_data={ -"": ["*.parquet"], -} -) -pip install assesspy -install.package("assesspy") diff --git a/.gitignore b/.gitignore index e4b39e1..d29ffb7 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ __pycache__/ venv/ .Rproj.user .tox +.Rhistory