Of all the columns in a racing results table, the margin is the one that causes the most grief. A finishing position is a clean integer. A finish time is a number with a unit. The distance beaten, though, arrives as ½, nk, shd, 2-3/4, NOSE or a dash, depending on the country, and no two sources agree on how to write it.

What follows covers horse racing margins as they appear in real results data, taken from 1.86 million UK and Irish runner records and 365,000 from Hong Kong, and what to do with them.

What a margin measures

The margin is the gap between a runner and the one directly ahead of it, not the gap to the winner. The winner has no margin. Second place is beaten by some distance. Third is beaten by some distance from second, and so on down the field.

Distances shorter than a length get their own names, in descending order: a short head, a head, a neck. Anything longer is counted in lengths and fractions of a length, usually quarters.

UK and Irish margins

UK results write most margins in lengths with the fraction symbols ¼, ½ and ¾ and use abbreviations for the very close finishes. Counting every record in our archive, the commonest are:

Written asMeaningRecords
½half a length139,937
nkneck112,499
¾three quarters of a length104,732
1¼a length and a quarter87,314
1½a length and a half70,921
hdhead65,799
shdshort head42,295
nsenose26,577
dhdead heat2,319
dista distance, beyond the point where lengths are counted917

A neck is the second most common margin in the whole archive. Close finishes are the norm, not the exception, so a single rounding rule matters a lot to anyone calculating speed figures.

We store a second, numeric column next to it, distance_btn_total, which is the cumulative gap to the winner. For a race where second is beaten by 3¾ and third by a further 1¼, the totals are 0, 3.75 and 5.0. If you need a margin as a number, use that field, not your own parsing.

Hong Kong margins

Hong Kong writes fractions with a slash and joins whole lengths with a hyphen: 2-3/4 is two and three quarters, 1/2 is half a length. Short margins are spelled out in capitals. The commonest in our data:

Written asMeaningRecords
Nneck4,618
SHshort head3,368
HDhead2,401
NKneck (an alternative spelling)665
NOSEnose570
T.O.tailed off371

The winner carries a dash, which is a nuisance, because a plain minus sign is not a number either. A parser has to treat the lone dash as zero and everything else as text to decode.

Turning text into numbers

There is no official conversion, but most analysts use the same rough scale, and you should write down yours. A common one:

  • nose: 0.05 of a length
  • short head: 0.1
  • head: 0.2
  • neck: 0.3
  • anything else: the written value

Whatever you choose, apply it the same way to both markets, and keep the original text in its own column. Rounding is a modelling decision, and you will want to change it later without reloading everything.

Two more things deserve care. First, dead heats produce a margin of zero between two runners, which breaks any logic that assumes margins rise with finishing position. Second, a margin is measured to the horse in front, so a long gap further up the field says nothing about this runner’s own performance. When people compare the true size of a victory, they usually sum the margins to the winner rather than quoting a single one.

A small parser

Most people end up writing a function like this one, in Python, for both markets. It is short on purpose.

import re

WORDS = {"nse": 0.05, "nose": 0.05, "shd": 0.1, "sh": 0.1, "hd": 0.2,
         "h": 0.2, "nk": 0.3, "n": 0.3}
FRACTIONS = {"¼": 0.25, "½": 0.5, "¾": 0.75}

def margin_in_lengths(text):
    text = (text or "").strip().lower()
    if text in ("", "-", "---"):
        return 0.0
    if text in WORDS:
        return WORDS[text]
    uk = re.fullmatch(r"(d+)?([¼½¾])?", text)
    if uk and (uk.group(1) or uk.group(2)):
        return float(uk.group(1) or 0) + FRACTIONS.get(uk.group(2), 0)
    hk = re.fullmatch(r"(?:(d+)-)?(d)/(d)", text)
    if hk:
        return float(hk.group(1) or 0) + int(hk.group(2)) / int(hk.group(3))
    return None

Anything that returns None is a code you have not handled yet, such as dh or dist, and the right move is to look at those rows rather than let them fall through as zero.

Where to get it

Write down your conversion scale, apply it the same way to both markets, and keep the original text. Both formats come through as published in the API and the horse racing datasets, with the numeric cumulative gap for UK races. If you need to know why a runner has no margin at all, see the result codes guide, and for equipment, Hong Kong gear codes.

Tags:

Comments are closed

0
    0
    Your Cart
    Your cart is emptyReturn to Shop