Schema Care

Normalizing Lab Result Units with UCUM

By Schema CarePublished Updated

Normalizing lab result units means mapping each unit spelling printed on a lab report, such as "mg/dl", "MG/DL" or "K/uL", to one standard code, usually from UCUM, while keeping the printed text beside it. The value stays as printed. Normalizing the unit makes records comparable across labs; converting the number is a separate step that is often the wrong one.

Why lab result units need normalizing before analysis

Lab result units need normalizing because labs print the same unit in different ways, and software compares text exactly. "mg/dL", "mg/dl" and "MG/DL" name one unit, yet a query, a chart or a dedupe step treats them as three. Normalizing gives each record one comparable unit code without touching the value.

The problem shows up as soon as reports from more than one source meet in a table. A fictional clinic that receives results from a hospital lab, a reference lab and a point-of-care device might see these unit strings for results that a reader would call the same unit:

  • mg/dL from the hospital lab's PDF
  • mg/dl from the reference lab's printout
  • MG/DL from an older system that prints in capitals

A filter on unit = "mg/dL" finds a third of the rows. A count of distinct units reports three where there is one. A data quality check that compares a result's unit with the unit expected for its test raises false alarms on two of the three sources.

Copy errors make it worse. Scanned pages turn the micro sign into a "u" or an "m", and people keying results by hand type "mcg" where the page says "µg". None of these change the meaning, but all of them break exact matching.

Normalization fixes the unit field only. It does not decide whether a value is high or low, and it does not change the number the lab reported. Whether an extracted unit fits the test it sits beside is a separate check, covered in whether the extracted unit fits the lab test.

What are UCUM units in lab data?

UCUM units in lab data are unit codes from the Unified Code for Units of Measure, a code system written for computers rather than for print. The UCUM specification states its purpose as facilitating "unambiguous electronic communication of quantities together with their units". A UCUM code such as mg/dL has exactly one meaning wherever it appears.

A few rules from the specification explain most of what you see in lab data:

  • Case matters in the standard form. UCUM defines a case-sensitive form and a case-insensitive form for every symbol, and says "Case insensitive symbols are incompatible to the case sensitive symbols." Pick the case-sensitive form for your normalized field and use it everywhere.
  • Prefixes are single ASCII letters. Deci is d, milli is m, kilo is k and micro is u. The Greek µ appears only in UCUM's print column, which the specification says is not normative.
  • Liter has two case-sensitive codes. Both l and L are defined. In the case-insensitive form there is only L.
  • Operators are a period and a solidus. A period means multiply and a slash means divide, read left to right with equal precedence.
  • Powers of ten use 10*. The specification lists 10* and 10^ as the same unit, "the number ten for arbitrary powers".
  • Curly braces are annotations. Text in braces, such as {rbc}, adds a label but no meaning; the specification says curly braces expressions are equivalent to the unit 1.
  • Arbitrary units sit in square brackets. The international unit is [IU] or [iU].

UCUM is also the unit vocabulary named in US interoperability rules. The USCDI laboratory data class lists UCUM as the standard for the result unit of measure and the result reference range, and LOINC for the test itself. Mapping test names to codes is the subject of the guide to mapping lab test names to LOINC.

A lab unit spelling map: from printed text to UCUM code

A lab unit spelling map is a lookup table from every unit string you actually see on reports to one UCUM code. You build it from your own data: list the distinct printed units, map each one once, and send any string not yet in the table to a person instead of guessing.

The map below covers spellings that appear on many fictional sample reports. Each row is an example; check your own map against the UCUM specification before you rely on it.

Printed unit (example)UCUM code (case-sensitive)Why
mg/dlmg/dLSame unit; l and L are both liter, so pick one form and stick to it
MG/DLmg/dLThe case-insensitive spelling of the same code
mg/dLmg/dLAlready the chosen form
K/uL10*3/uL"K" is a lab shorthand for thousand; UCUM writes it as a power of ten
x10^3/uL10*3/uL10^ and 10* are the same unit in UCUM
10E3/uL10*3/uLAnother print style for a power of ten
mmol/Lmmol/LAlready a UCUM code
mmol/lmmol/LLowercase liter, normalized to the chosen form
µg/dLug/dLMicro is the ASCII letter u in UCUM codes
mcg/dLug/dLA common hand-typed spelling of micro
U/LU/LU is the enzyme unit in UCUM
IU/L[IU]/LThe international unit takes square brackets
%%Percent is a UCUM unit, defined as 10*-2

Three practices keep the map honest. Map strings, not guesses: a row exists only after someone has seen that exact spelling on a page. Store the map as data, with a reviewer and date per row, so a change is traceable. And treat an unmapped unit as a stop, not a pass, because a silent default unit is worse than an empty field.

Building the map from your own reports

Start with a list of every distinct unit string in the results you already hold, with a count of how often each appears and one example page for each. Sort by count. The first twenty strings usually cover most rows, so a person can map them in one sitting and see each spelling on a real page while doing it.

Clean the strings before you look them up, but only in ways that cannot change meaning. Trim spaces at the ends, collapse a run of spaces into one, and turn a superscript such as the "3" in "10³/µL" into plain text. Do not lowercase everything: in UCUM's case-sensitive form, upper and lower case carry meaning, so a blanket lowercase step can turn one unit into another.

Then add new spellings as they arrive. A new lab, a new report template or a new scanner can each introduce one. Each new string waits for a person, gets a row with a name and date, and only then flows through automatically.

Watch for strings that look like units but are not. "See note", "N/A" and a blank cell all appear in unit columns. They map to no code, and the record should say so.

When not to convert lab result units between systems

Converting lab result units between systems, such as from mg/dL to mmol/L, changes the number, and that is a different job from normalizing the unit code. Do not convert as part of extraction. The conversion depends on the substance being measured, and a converted value no longer matches the page a reviewer checks it against.

UCUM itself shows why. Its tables list the gram as a unit of mass and the mole as a unit of amount of substance. A mass-per-volume unit and a moles-per-volume unit measure different kinds of quantity, so no unit rule alone turns one into the other; you need a factor that depends on the substance. LOINC keeps them apart too. In the NLM Clinical Table Search Service for LOINC, glucose in serum or plasma has one code with the property "MCnc", named "Glucose [Mass/volume] in Serum or Plasma", and another with "SCnc", named "Glucose [Moles/volume] in Serum or Plasma". The guide to how LOINC codes for lab tests are built explains the property part.

Leave the value alone in these cases as well:

  • The value carries a comparator. A result printed as "<5" or ">1000" is a limit, not a measured number. Converting the number and dropping the sign changes what the record says.
  • The unit is arbitrary. UCUM classes the international unit as an arbitrary unit, and lab-specific units are similar, so there is no general conversion.
  • The result is a ratio or a titer. A printed "1:40" has no unit to convert.
  • The unit is missing or unreadable. Normalize nothing, flag the row and send it to review.

If analysis later needs one unit for one test, convert in the analysis layer, with the factor recorded, and keep the extracted record as printed. That keeps the audit path short: page, extracted value, normalized unit code, and only then any derived number.

Should a normalized lab unit replace the printed unit?

A normalized lab unit should sit beside the printed unit, never replace it. Store two fields: the unit text exactly as the report prints it, and the UCUM code you mapped it to. The printed text is what a reviewer compares against the page; the code is what software compares across records.

Data standards keep both for the same reason. The FHIR R4 Quantity data type separates a "human-readable form of the unit" in its unit element from a "computer processable form of the unit" in its code element, with a system element naming the code system. You do not need to use FHIR to borrow that split.

A fictional result record with both fields looks like this:

FieldExample value
Test name (as printed)WBC
Result6.2
Unit (as printed)K/uL
Unit code10*3/uL
Unit code systemUCUM
SourcePage 1, row 3

Keeping the printed unit protects you from your own map. If a mapping row turns out to be wrong, every affected record can be found and fixed from the printed text. If the printed text was overwritten, the error is permanent.

It also helps review. Schema Care reads the unit beside each lab result as a separate field with its own confidence score and a link to where it sits on the page, so a reviewer checking a doubtful unit sees the printed text highlighted on the original. The list of supported documents shows units among the fields it reads from lab reports. Whatever happens to the unit later, the printed form is the anchor.

The unit is one of several fields on a result row that should be stored as printed. The flag column is another, and the guide to how abnormal flags are printed on lab reports applies the same rule to it. For loading normalized results into other systems, the developer integration category covers schemas, interfaces and file formats in general.

All posts in Lab Reports