Tabular Regression
Scikit-learn
Joblib
anthropometry
fashion

ThreadCraft Measurement Predictor & Validator

Predicts a person's full set of garment measurements from the few they have actually taken, and flags entered measurements that contradict the rest of their profile.

Built for ThreadCraft, an AI-powered custom clothing design and ordering platform, as a final-year BSc Software Engineering project.

Why it exists

The ThreadCraft proposal names self-reported measurement error as an explicit limitation of the platform. This model addresses it directly: Step 4 of the design wizard pre-fills editable suggestions instead of blank boxes, and warns when an entry looks like a typo or a unit mix-up.

Results (held-out test split, n=607)

Accuracy depends on how much the customer supplied, so it is reported per scenario:

scenario mean_r2 mean_mae_cm
A: height+weight only 0.818 1.625
B: + chest & waist 0.82 1.325
C: + chest, waist, hip, shoulder 0.828 1.205

Per-field RΒ² (scenario A = height/weight/age/sex only):

field A: height+weight only B: + chest & waist C: + chest, waist, hip, shoulder
ankle 0.558 0.568 0.568
calf 0.677 0.718 0.717
chest 0.879 nan nan
collar 0.87 0.869 0.88
cuff 0.79 0.795 0.796
hip 0.872 0.884 nan
inseam 0.813 0.812 0.813
outseam 0.897 0.91 0.912
shoulder 0.759 0.769 nan
sleeve 0.841 0.847 0.871
thigh 0.84 0.861 0.912
total_length 0.983 0.983 0.982
waist 0.859 nan nan

Mean absolute error, cm:

field A: height+weight only B: + chest & waist C: + chest, waist, hip, shoulder
ankle 0.78 0.77 0.77
calf 1.3 1.23 1.23
chest 2.73 nan nan
collar 1.1 1.11 1.07
cuff 0.46 0.45 0.45
hip 2.16 2.06 nan
inseam 1.91 1.91 1.92
outseam 1.65 1.53 1.51
shoulder 1.15 1.13 nan
sleeve 1.84 1.8 1.62
thigh 1.79 1.65 1.34
total_length 0.92 0.92 0.92
waist 3.33 nan nan

Validator performance

At the 99th-percentile residual threshold, averaged across fields: 2.2% false-positive rate on genuine measurements, catching 98.6% of values corrupted by 20%. Full percentile sweep in threshold_tuning.csv.

Design: masked-input training

A customer supplies an arbitrary subset of measurements, so each regressor is trained on randomly masked copies of the data rather than complete rows. This avoids a train/serve mismatch and was measured against the simpler base-features-only alternative β€” masking won on 13/13 targets even at the hardest scenario. See design_comparison.csv.

Limitations β€” read before deploying

  • The training population is US Army personnel (ANSUR II, 2012). They are younger, fitter and more athletic than a general civilian population, so predictions will be systematically off for older, sedentary or higher-BMI customers, and the extremes of the civilian distribution are under-represented.
  • Body proportions vary between populations. ThreadCraft serves a Sri Lankan market; ANSUR II is a US sample. Predicted values should be treated as a starting point a customer edits, never as a substitute for measuring. This is the single most important caveat here.
  • Sex is modelled as the binary recorded in ANSUR II. That is a limitation of the source data, and the model should not be presented as covering all customers.
  • ANSUR II contains no bust circumference and no knee circumference, so those ThreadCraft fields cannot be predicted by this model. chest is the closest available analogue to bust, and calf the closest lower-leg circumference.
  • shoulder maps to biacromial breadth and inseam to crotch height β€” close analogues of the tailoring measurements, not identical definitions. Expect a small systematic offset against a tailor's own tape.

Usage

import joblib, numpy as np, pandas as pd
from huggingface_hub import hf_hub_download

art = joblib.load(hf_hub_download("SamaGalagoda/threadcraft-measurement-predictor", "measurement_predictor.joblib"))
models, feature_sets = art["models"], art["feature_sets"]

customer = {"height": 170.0, "weight": 68.0, "age": 30.0, "sex": 0,
            "chest": 92.0, "waist": 76.0}
customer["bmi"] = customer["weight"] / (customer["height"] / 100) ** 2
known = [k for k in art["targets"] if k in customer]

for target in art["targets"]:
    if target in known:
        continue
    feats = feature_sets[target]
    row = {f: customer.get(f, np.nan) for f in feats}
    for f in feats:
        if f not in art["base_features"] and f not in known:
            row[f] = np.nan
    value = models[target].predict(pd.DataFrame([row])[feats])[0]
    print(f"{target:14s} {value:6.1f} cm")

Training

Algorithm HistGradientBoostingRegressor x 13 (one per measurement)
Augmentation 4 masked copies per row, mask rate 20–90%
Train / Val / Test 4,854 / 607 / 607 (stratified on sex)
Hardware Kaggle CPU (no GPU required)
scikit-learn 1.6.1

Source data

ANSUR II β€” 2012 Anthropometric Survey of US Army Personnel, public release subset (4,082 male + 1,986 female, 93 measurements), NATICK/TR-15/007, distributed by the Penn State OPEN Design Lab. US Government work, cleared for unlimited public release.

Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Dataset used to train SamaGalagoda/threadcraft-measurement-predictor