Assign a rank to each value in a column — the largest gets rank 1. By hand, each value's rank is 1 plus the count of values strictly greater than it. With pandas, Series.rank(ascending=False) does this in one call.

By hand

For each score, count how many other scores are strictly greater than it — that count plus 1 is the rank. All values are distinct, so there are no ties and the formula produces gap-free integer ranks.

naive.py
Replay: real traced execution (multi-file project)
scores = [80, 55, 90, 70]
ranks = []
for s in scores:
    rank = 1
    for other in scores:
        if other > s:
            rank += 1
    ranks.append(rank)
print('RESULT:', ranks)
  1. scores ← [80, 55, 90, 70]

    1scores = [80, 55, 90, 70]2ranks = []
    values this step[80, 55, 90, 70]scores
  2. ranks ← []

    1scores = [80, 55, 90, 70]2ranks = []3for s in scores:
    values this step[]ranks
  3. s ← 80

    2ranks = []3for s in scores:4    rank = 1
    values this step80s
  4. rank ← 1

    3for s in scores:4    rank = 15    for other in scores:
    values this step1rank
  5. other ← 80

    pass 1 of 3
    4rank = 15for other in scores:6    if other > s:7        rank += 1
    values this step80other
    All 3 passes — pass 1 is the card above
    passother
    180
    280 55
    355 90
  6. rank ← 2

    6    if other > s:7        rank += 18ranks.append(rank)
    values this step1 2rank
  7. other ← 70

    4rank = 15for other in scores:6    if other > s:
    values this step90 70other
  8. if other > s:

    5for other in scores:6    if other > s:7        rank += 1
  9. for other in scores:

    4rank = 15for other in scores:6    if other > s:
  10. ranks ← [2]

    7            rank += 18    ranks.append(rank)9print('RESULT:', ranks)
    values this step[] [2]ranks
  11. s ← 55

    2ranks = []3for s in scores:4    rank = 1
    values this step80 55s
  12. rank ← 1

    3for s in scores:4    rank = 15    for other in scores:
    values this step2 1rank
  13. other ← 55, rank ← 2

    pass 1 of 2
    4rank = 15for other in scores:6    if other > s:7        rank += 18ranks.append(rank)
    values this step80 55other1 2rank
  14. other ← 70, rank ← 3

    pass 2 of 2
    4rank = 15for other in scores:6    if other > s:7        rank += 18ranks.append(rank)
    values this step90 70other2 3rank
  15. rank ← 4

    6    if other > s:7        rank += 18ranks.append(rank)
    values this step3 4rank
  16. for other in scores:

    4rank = 15for other in scores:6    if other > s:
  17. ranks ← [2, 4]

    7            rank += 18    ranks.append(rank)9print('RESULT:', ranks)
    values this step[2] [2, 4]ranks
  18. s ← 90

    2ranks = []3for s in scores:4    rank = 1
    values this step55 90s
  19. rank ← 1

    3for s in scores:4    rank = 15    for other in scores:
    values this step4 1rank
  20. other ← 80

    pass 1 of 4
    4rank = 15for other in scores:6    if other > s:7        rank += 1
    values this step70 80other
    All 4 passes — pass 1 is the card above
    passother
    170 80
    280 55
    355 90
    490 70
  21. for other in scores:

    4rank = 15for other in scores:6    if other > s:
  22. ranks ← [2, 4, 1]

    7            rank += 18    ranks.append(rank)9print('RESULT:', ranks)
    values this step[2, 4] [2, 4, 1]ranks
  23. s ← 70

    2ranks = []3for s in scores:4    rank = 1
    values this step90 70s
  24. rank = 1

    3for s in scores:4    rank = 15    for other in scores:
  25. other ← 55, rank ← 2

    pass 1 of 2
    4rank = 15for other in scores:6    if other > s:7        rank += 18ranks.append(rank)
    values this step80 55other1 2rank
  26. other ← 70, rank ← 3

    pass 2 of 2
    4rank = 15for other in scores:6    if other > s:7        rank += 18ranks.append(rank)
    values this step90 70other2 3rank
  27. for other in scores:

    4rank = 15for other in scores:6    if other > s:
  28. ranks ← [2, 4, 1, 3]

    7            rank += 18    ranks.append(rank)9print('RESULT:', ranks)
    values this step[2, 4, 1] [2, 4, 1, 3]ranks
  29. for s in scores:

    2ranks = []3for s in scores:4    rank = 1
  30. stdout ← RESULT: [2, 4, 1, 3]

    8    ranks.append(rank)9print('RESULT:', ranks)
    values this stepRESULT: [2, 4, 1, 3]stdout

With pandas

df['score'].rank(ascending=False) assigns rank 1 to the largest value. rank() always returns float64; with distinct values the fractional part is always .0, so casting to int is safe.

library.py
import pandas as pd
from dalib.display import set_display
set_display()

scores = [80, 55, 90, 70]
df = pd.DataFrame({'score': scores})
r = df['score'].rank(ascending=False)
ranks = [int(x) for x in r.tolist()]
print('index:', r.index.tolist())
print('values:', r.tolist())
print('dtype:', r.dtype)
print('RESULT:', ranks)
index: [0, 1, 2, 3]
values: [2.0, 4.0, 1.0, 3.0]
dtype: float64
RESULT: [2, 4, 1, 3]

Implementation notes

  • rank(ascending=True) (the default) assigns rank 1 to the smallest value. Pass ascending=False to rank largest-first, as done here — this matches the naive formula (1 + count of values greater).
  • With distinct values all tie methods agree. When ties exist, pandas offers: method='average' (default — mean of tied ranks), method='min' (lowest rank in the tie group), method='dense' (no gaps — [1,2,2,3] rather than [1,2,2,4]).
  • rank() always returns float64 regardless of the input dtype; cast with int() or .astype(int) only after confirming no NaN values.
  • Cross-reference: rank-assign (python-data-basics) for the pure-Python version.