Detect sales chasing in a vector of sales ratios#

assesspy.is_sales_chased(x: list[int] | list[float] | Series, method='both', bounds: tuple[float, float] = (0.98, 1.02), gap: float = 0.05) bool#

Sales chasing is when a property is selectively reappraised to shift its assessed value toward its recent sale price. Sales chasing is difficult to detect. This function is NOT a statistical test and does not provide the probability of the given result. Rather, it combines two heuristic methods to roughly estimate if sales chasing has occurred.

The first method (cdf) detects discontinuities in the cumulative distribution function (CDF) of the ratios of input values. Sales ratios that are not sales chased should have a fairly smooth CDF. Discontinuous jumps in the CDF, particularly around 1, may indicate sales chasing. This can usually be seen visually as a “flat spot” on the CDF.

The second method (dist) uses the technique outlined in the IAAO Standard on Ratio Studies Appendix E, Section 4. It compares the percentage of real data within +-2% of the mean ratio to the percentage of data within the same bounds given a constructed normal distribution with the same mean and standard deviation. The intuition here is that ratios that are sales chased may be more “bunched up” in the center of the distribution.

Parameters:
  • x (Array-like numeric values) – A list or pd.Series of numeric values. Must be longer than 2 and cannot contain Inf or NaN values.

  • method (str) – Default both. String indicating sales chasing detection method. Options are cdf, dist, or both.

  • bounds (tuple[float, float]) – Default (0.98, 1.02). Tuple of two floats indicating the lower and upper bounds of the range of ratios to consider when detecting sales chasing. Setting this to a narrow band at the center of the ratio distribution prevents detecting false positives at the tails.

  • gap (float) – Default 0.05. Float tuning factor. For the CDF method, it sets the maximum percentage difference between two adjacent ratios. For the distribution method, it sets the maximum percentage point difference between the percentage of the data between the bounds in the real distribution compared to the ideal distribution.

Returns:

A boolean value indicating whether or not the input values may have been sales chased.

Return type:

bool

Example:

import assesspy as ap
import numpy as np
from statsmodels.distributions.empirical_distribution import ECDF
from matplotlib import pyplot

# Generate fake data with normal vs chased ratios
normal_ratios = np.random.normal(1, 0.15, 10000).tolist()
chased_ratios = list(np.random.normal(1, 0.15, 900)) + [1] * 100

# Plot to view discontinuity
ecdf = ECDF(normal_ratios)
pyplot.plot(ecdf.x, ecdf.y)
pyplot.show()
ap.is_sales_chased(normal_ratios)

ecdf = ECDF(chased_ratios)
pyplot.plot(ecdf.x, ecdf.y)
pyplot.show()
ap.is_sales_chased(chased_ratios)