Skip to content

Commit

Permalink
Merge pull request #156 from glevv/gastwirth-loc
Browse files Browse the repository at this point in the history
Add Gastwirth's location estimator
  • Loading branch information
glevv authored Nov 30, 2024
2 parents 68c7c7b + 3f6cf44 commit 6719c98
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 15 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

- Collection of measures of central tendency - `obscure_stats/central_tendency`:
* Contraharmonic Mean;
* Gastwirth's Location;
* Grenander's Mode;
* Half-Sample Mode;
* Hodges-Lehmann-Sen Location;
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ scipy = "^1.9.1"
mypy = "^1.6.1"
pytest = "^8.0.0"
pytest-cov = "^5.0.0"
ruff = "^0.7.0"
ruff = "^0.8.0"
hypothesis = "^6.103.1"
hypothesis-pytest = "^0.19.0"

Expand Down
2 changes: 1 addition & 1 deletion src/obscure_stats/association/association.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ def winsorized_correlation(x: np.ndarray, y: np.ndarray, k: float = 0.1) -> floa
Input array.
y : array_like
Input array.
k : float
k : float, default = 0.1
The percentages of values to winsorize on each side of the arrays.
Returns
Expand Down
2 changes: 2 additions & 0 deletions src/obscure_stats/central_tendency/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from .central_tendency import (
contraharmonic_mean,
gastwirth_location,
grenanders_m,
half_sample_mode,
hodges_lehmann_sen_location,
Expand All @@ -15,6 +16,7 @@

__all__ = [
"contraharmonic_mean",
"gastwirth_location",
"grenanders_m",
"half_sample_mode",
"hodges_lehmann_sen_location",
Expand Down
50 changes: 42 additions & 8 deletions src/obscure_stats/central_tendency/central_tendency.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def standard_trimmed_harrell_davis_quantile(x: np.ndarray, q: float = 0.5) -> fl
----------
x : array_like
Input array.
q : float
q : float, default = 0.5
Quantile value in range (0, 1).
Returns
Expand Down Expand Up @@ -286,7 +286,7 @@ def tau_location(x: np.ndarray, c: float = 4.5) -> float:
----------
x : array_like
Input array.
c : float
c : float, default = 4.5
Constant that filter outliers.
Returns
Expand All @@ -310,7 +310,7 @@ def tau_location(x: np.ndarray, c: float = 4.5) -> float:
return np.nansum(x * w) / np.nansum(w)


def grenanders_m(x: np.ndarray, p: float = 1.5, k: int = 3) -> float:
def grenanders_m(x: np.ndarray, p: float = 1.001, k: int = 2) -> float:
"""Calculate Grenander's Mode.
This measure is a direct nonparametric estimation of the mode.
Expand All @@ -322,10 +322,10 @@ def grenanders_m(x: np.ndarray, p: float = 1.5, k: int = 3) -> float:
----------
x : array_like
Input array.
p : float
p : float, default = 1.001
Smoothing constant.
k : int
The number of samples to exclude from the calculation.
k : int, default = 2
The number of samples to filter.
Returns
-------
Expand All @@ -339,6 +339,7 @@ def grenanders_m(x: np.ndarray, p: float = 1.5, k: int = 3) -> float:
Annals of Mathematical Statistics, 36, 131-138.
"""
x_sort = np.sort(x)
x_sort = x_sort.astype("float")
x_sort = x_sort[np.isfinite(x_sort)]

if p <= 1:
Expand All @@ -351,8 +352,41 @@ def grenanders_m(x: np.ndarray, p: float = 1.5, k: int = 3) -> float:
if len(x_sort) <= k:
return np.nan

# pre calculate diffs
diff = x_sort[k:] - x_sort[:-k]
# if the diffs are constant - return the value
if diff.sum() == 0.0:
return x_sort[0]
# to avoid division by zero
diff[diff == 0.0] = np.nan

return (
0.5
* np.sum((x_sort[k:] + x_sort[:-k]) / np.power(x_sort[k:] - x_sort[:-k], p))
/ np.sum(np.power(x_sort[k:] - x_sort[:-k], -p))
* np.nansum((x_sort[k:] + x_sort[:-k]) / np.power(diff, p))
/ np.nansum(np.power(diff, -p))
)


def gastwirth_location(x: np.ndarray) -> float:
"""Calculate Gastwirth's location estimator.
This measure is more robust then average.
Parameters
----------
x : array_like
Input array.
Returns
-------
gle : float
The value of the Gastwirth's location.
References
----------
Gastwirth, J. L. (1966).
On Robust Procedures.
J. Amer. Statist. Assn., Vol. 61, pp. 929-948.
"""
p33, p50, p66 = np.nanquantile(x, [1 / 3, 0.5, 2 / 3])
return 0.3 * p33 + 0.4 * p50 + 0.3 * p66
8 changes: 4 additions & 4 deletions src/obscure_stats/skewness/skewness.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,8 +412,8 @@ def left_quantile_weight(x: np.ndarray, q: float = 0.25) -> float:
----------
x : array_like
Input array.
q : float
Quantile to use for the anchor.
q : float, default = 0.25
Quantile to use for the calculation, (0.0, 0.5)
Returns
-------
Expand Down Expand Up @@ -448,8 +448,8 @@ def right_quantile_weight(x: np.ndarray, q: float = 0.75) -> float:
----------
x : array_like
Input array.
q : float
Quantile to use for the anchor.
q : float, default = 0.75
Quantile to use for the calculation, (0.5, 1.0).
Returns
-------
Expand Down
2 changes: 1 addition & 1 deletion src/obscure_stats/variation/variation.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ def renyi_entropy(x: np.ndarray, alpha: float = 2) -> float:
----------
x : array_like
Input array.
alpha : float
alpha : float, default = 2
Order of the Rényi entropy
Returns
Expand Down
2 changes: 2 additions & 0 deletions tests/test_central_tendency.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from obscure_stats.central_tendency import (
contraharmonic_mean,
gastwirth_location,
grenanders_m,
half_sample_mode,
hodges_lehmann_sen_location,
Expand All @@ -26,6 +27,7 @@

all_functions = [
contraharmonic_mean,
gastwirth_location,
grenanders_m,
half_sample_mode,
hodges_lehmann_sen_location,
Expand Down

0 comments on commit 6719c98

Please sign in to comment.