@@ -355,7 +355,7 @@ def _fail_neg(values, errmsg='negative value'):
355
355
raise StatisticsError (errmsg )
356
356
yield x
357
357
358
- def _rank (data , / ) -> list [float ]:
358
+ def _rank (data , / , * , key = None , reverse = False , ties = 'average' ) -> list [float ]:
359
359
"""Rank order a dataset. The lowest value has rank 1.
360
360
361
361
Ties are averaged so that equal values receive the same rank.
@@ -369,10 +369,27 @@ def _rank(data, /) -> list[float]:
369
369
>>> _rank([3.5, 5.0, 3.5, 2.0, 6.0, 1.0])
370
370
[3.5, 5.0, 3.5, 2.0, 6.0, 1.0]
371
371
372
+ It is possible to rank the data in reverse order so that
373
+ the highest value has rank 1. Also, a key-function can
374
+ extract the field to be ranked:
375
+
376
+ >>> goals = [('eagles', 45), ('bears', 48), ('lions', 44)]
377
+ >>> _rank(goals, key=itemgetter(1), reverse=True)
378
+ [2.0, 1.0, 3.0]
379
+
372
380
"""
373
- # Handling of ties matches scipy.stats.mstats.spearmanr
374
- val_pos = sorted (zip (data , count ()))
375
- i = 0
381
+ # If this function becomes public at some point, more thought
382
+ # needs to be given to the signature. A list of ints is
383
+ # plausible when ties is "min" or "max". When ties is "average",
384
+ # either list[float] or list[Fraction] is plausible.
385
+
386
+ # Default handling of ties matches scipy.stats.mstats.spearmanr.
387
+ if ties != 'average' :
388
+ raise ValueError (f'Unknown tie resolution method: { ties !r} ' )
389
+ if key is not None :
390
+ data = map (key , data )
391
+ val_pos = sorted (zip (data , count ()), reverse = reverse )
392
+ i = 0 # To rank starting at 0 instead of 1, set i = -1.
376
393
result = [0 ] * len (val_pos )
377
394
for _ , g in groupby (val_pos , key = itemgetter (0 )):
378
395
group = list (g )
0 commit comments