statisticspercentiledeveloper-guidehealthbody-composition

Implementing Body Measurement Percentiles: Where Does a User Rank in Their Population?

· 5 min read · Martin Hejda

A predicted chest circumference of 920mm is a number. Knowing it’s at the 42nd percentile for your height, sex, and regional population is insight. Percentile computation transforms the raw dimensions returned by a prediction API into something users can understand relative to themselves — and something useful for ergonomic design, health screening, and population analytics.

Here’s how to implement it.


The mathematical foundation

For adult body measurements in a reasonably homogeneous population, most dimensions follow an approximately normal distribution. This lets us compute percentiles using the standard normal CDF.

Given a dimension with population mean μ and standard deviation σ, the percentile for an individual with value x is:

percentile = Φ((x - μ) / σ) × 100

Where Φ is the standard normal CDF (cumulative distribution function).

from scipy import stats
import math

def value_to_percentile(value_mm: float, mean_mm: float, std_mm: float) -> float:
    """
    Compute population percentile for a body measurement.
    
    value_mm: the individual's measurement
    mean_mm: population mean for this dimension, sex, age group
    std_mm: population standard deviation
    
    Returns: percentile (0–100)
    """
    z = (value_mm - mean_mm) / std_mm
    percentile = stats.norm.cdf(z) * 100
    return round(percentile, 1)

def percentile_to_value(percentile: float, mean_mm: float, std_mm: float) -> float:
    """
    Inverse: compute the measurement value at a given population percentile.
    Useful for designing products that accommodate a target population range.
    """
    z = stats.norm.ppf(percentile / 100)
    return round(mean_mm + z * std_mm, 1)

Population reference data

To compute percentiles, you need population norms — mean and standard deviation for each dimension, stratified by sex and age group. These come from anthropometric surveys.

# Approximate population norms for reference
# Source: derived from ANSUR II, NHANES, SIZE UK — civilian populations
# Units: mm
# These are illustrative values; use published datasets for production

POPULATION_NORMS = {
    "GLOBAL": {
        "male": {
            "adult": {
                "stature":              {"mean": 1760, "std": 72},
                "chest_circumference":  {"mean": 1001, "std": 88},
                "waist_circumference_natural":  {"mean": 886,  "std": 100},
                "hip_circumference":    {"mean": 984,  "std": 72},
                "sitting_height":       {"mean": 921,  "std": 40},
                "biacromial_breadth":   {"mean": 400,  "std": 22},
                "head_circumference":   {"mean": 572,  "std": 18},
                "foot_length":          {"mean": 265,  "std": 13},
            }
        },
        "female": {
            "adult": {
                "stature":              {"mean": 1629, "std": 68},
                "chest_circumference":  {"mean": 915,  "std": 82},
                "waist_circumference_natural":  {"mean": 783,  "std": 100},
                "hip_circumference":    {"mean": 986,  "std": 80},
                "sitting_height":       {"mean": 855,  "std": 37},
                "biacromial_breadth":   {"mean": 363,  "std": 20},
                "head_circumference":   {"mean": 555,  "std": 17},
                "foot_length":          {"mean": 239,  "std": 12},
            }
        }
    },
    "EUROPE": {
        "male": {
            "adult": {
                "stature":              {"mean": 1782, "std": 70},
                "chest_circumference":  {"mean": 1005, "std": 84},
                "waist_circumference_natural":  {"mean": 882,  "std": 96},
                "hip_circumference":    {"mean": 988,  "std": 70},
            }
        },
        "female": {
            "adult": {
                "stature":              {"mean": 1654, "std": 66},
                "chest_circumference":  {"mean": 921,  "std": 80},
                "waist_circumference_natural":  {"mean": 776,  "std": 96},
                "hip_circumference":    {"mean": 993,  "std": 78},
            }
        }
    },
    "ASIA_PACIFIC": {
        "male": {
            "adult": {
                "stature":              {"mean": 1700, "std": 65},
                "chest_circumference":  {"mean": 880,  "std": 70},
                "waist_circumference_natural":  {"mean": 820,  "std": 88},
                "hip_circumference":    {"mean": 910,  "std": 65},
            }
        },
        "female": {
            "adult": {
                "stature":              {"mean": 1580, "std": 62},
                "chest_circumference":  {"mean": 835,  "std": 68},
                "waist_circumference_natural":  {"mean": 730,  "std": 88},
                "hip_circumference":    {"mean": 895,  "std": 72},
            }
        }
    }
}

def get_norm(dimension_id: str, gender: str, region: str = "GLOBAL", age_group: str = "adult") -> dict | None:
    """Look up population norm for a dimension."""
    region_data = POPULATION_NORMS.get(region, POPULATION_NORMS.get("GLOBAL", {}))
    gender_data = region_data.get(gender, {})
    age_data = gender_data.get(age_group, {})
    return age_data.get(dimension_id)

Computing a full percentile profile

def compute_percentile_profile(
    body_dimensions: dict,
    gender: str,
    region: str = "GLOBAL",
    age_group: str = "adult"
) -> dict:
    """
    Add population percentile information to each dimension in body_dimensions.
    
    body_dimensions: the 'body_dimensions' dict from the API response.
    Returns the same dict structure with percentile fields added to each entry.
    """
    result = {}
    
    for dim_id, dim in body_dimensions.items():
        value_mm = dim.get("value")
        
        if not value_mm:
            continue
        
        norm = get_norm(dim_id, gender, region, age_group)
        
        enriched = {
            **dim,
            "value_cm": round(value_mm / 10, 1)
        }
        
        if norm:
            pct = value_to_percentile(value_mm, norm["mean"], norm["std"])
            enriched["population_percentile"] = pct
            enriched["population_context"] = {
                "region": region,
                "gender": gender,
                "age_group": age_group,
                "percentile": pct,
                "description": _percentile_description(pct, dim_id)
            }
        
        result[dim_id] = enriched
    
    return result

def _percentile_description(percentile: float, dimension_id: str) -> str:
    """Human-readable description of a percentile position."""
    if percentile < 5:
        qualifier = "well below average"
    elif percentile < 25:
        qualifier = "below average"
    elif percentile < 75:
        qualifier = "around average"
    elif percentile < 95:
        qualifier = "above average"
    else:
        qualifier = "well above average"
    
    dim_display = dimension_id.replace("_", " ")
    return f"{dim_display} is {qualifier} for your population ({percentile:.0f}th percentile)"

Full integration example

import requests

def get_dimensions_with_percentiles(
    gender: str,
    height_cm: float,
    weight_kg: float,
    region: str = "GLOBAL"
) -> dict:
    """
    Get body dimension predictions with population percentile context.
    """
    response = requests.post(
        "https://dimensionspot-bodysize-engine.p.rapidapi.com/v1/predict",
        json={
            "input_data": {
                "input_unit_system": "metric",
                "subject": {"gender": gender, "input_origin_region": region},
                "anchors": {
                    "body_height": int(height_cm * 10),  # cm → mm
                    "body_mass": weight_kg
                }
            },
            "output_settings": {
                "calculation": {"target_region": region, "body_build_type": "CIVILIAN"},
                "requested_dimensions": {"bundle": "TORSO"},
                "output_format": {
                    "include_range_95": True,
                    "confidence_score_threshold": 60
                }
            }
        },
        headers={
            "X-RapidAPI-Key": "YOUR_API_KEY",
            "X-RapidAPI-Host": "dimensionspot-bodysize-engine.p.rapidapi.com"
        }
    )
    
    data = response.json()
    dims = data.get("body_dimensions", {})
    
    # Enrich with percentiles
    dims_with_percentiles = compute_percentile_profile(dims, gender, region)
    
    return {
        **data,
        "body_dimensions": dims_with_percentiles,
        "population_context": {
            "region": region,
            "gender": gender,
            "note": "Percentiles are relative to adult civilian population for the specified region."
        }
    }

Percentile bands for ergonomic design

One of the most practical uses of percentile computation is in ergonomic product design. The standard design principle — accommodate the 5th to 95th percentile — translates directly to measurement values:

def design_accommodation_range(
    dimension_id: str,
    gender: str | None,  # None = combined sex
    region: str,
    p_low: float = 5.0,
    p_high: float = 95.0
) -> dict:
    """
    Compute the body dimension range that a product must accommodate
    to serve the specified population percentage.
    
    Example: what chest circumference range covers 90% of European women?
    """
    genders = [gender] if gender else ["male", "female"]
    values = []
    
    for g in genders:
        norm = get_norm(dimension_id, g, region)
        if norm:
            low = percentile_to_value(p_low, norm["mean"], norm["std"])
            high = percentile_to_value(p_high, norm["mean"], norm["std"])
            values.extend([low, high])
    
    if not values:
        return {"error": f"No population data for {dimension_id}, {gender}, {region}"}
    
    return {
        "dimension_id": dimension_id,
        "region": region,
        "gender": gender or "combined",
        "accommodation_range": {
            "low_mm": round(min(values)),
            "high_mm": round(max(values)),
            "low_cm": round(min(values) / 10, 1),
            "high_cm": round(max(values) / 10, 1),
        },
        "target_coverage": f"{p_high - p_low:.0f}% of {region} {'combined' if not gender else gender} adults",
        "note": f"Designing for this range covers {p_low:.0f}th to {p_high:.0f}th percentile"
    }

# Example: what waist circumference range does a one-size chair belt need to cover
# for 90% of European adults?
# result = design_accommodation_range("waist_circumference_natural", None, "EUROPE")
# → {"low_cm": 66.1, "high_cm": 118.3, "target_coverage": "90% of EUROPE combined adults"}

Important caveats

Population specificity: Percentiles are always relative to a specific population. A waist circumference at the 60th percentile for US adults may be at a different percentile for Korean adults. Always display which population the percentile refers to.

Normality assumption: Adult body measurements follow approximately normal distributions, but circumference measurements (waist, hip, chest) are right-skewed — the upper tail extends further than a normal distribution predicts. For dimensions where this matters (particularly at the extremes, above the 90th percentile), the normal approximation understates the actual values.

The prediction is already uncertain: A predicted dimension has a confidence interval (the range_95 from the API). The percentile computed from a predicted value inherits this uncertainty. A user predicted at 920mm chest ± 60mm might be anywhere from the 30th to 75th percentile. Consider computing percentiles at both the low and high ends of the prediction interval to show the range.


Percentiles are a user-friendly way to present anthropometric data. Most people understand “above average for your population” more intuitively than “920mm.” The computation is straightforward once you have population norms and a predicted value. The main implementation work is building the population norm dataset and deciding how to communicate uncertainty to users when both the prediction and the percentile calculation have meaningful error ranges.

Try DimensionsPot

Free tier — 100 requests/month, no credit card required.

Get API on RapidAPI