Downloads · 30 days
0
SamaGalagoda/threadcraft-fit-recommender
threadcraft-fit-recommender is a tabular classification model from SamaGalagoda. Use it for the tabular classification task on the model card, and read the license before you ship it in a product. It is set up for sklearn. The card lists the license as cc-by-4.0.
Gradient-boosted classifier predicting whether a garment size will run small, fit, or large for a given customer's body measurements.
Downloads · 30 days
0
Access
Public
Updated Aug 16, 2026
Repo size
1.8 MB
Likes
0
Public
Click a slice to open those files.
.joblib1.8 MB · 95%
From the Hugging Face model README
Gradient-boosted classifier predicting whether a garment size will run small, fit, or large for a given customer's body measurements.
Built for ThreadCraft, an AI-powered custom clothing design and ordering platform, as a final-year BSc Software Engineering project.
| Metric | Model | Majority-class baseline |
|---|---|---|
| Accuracy | 0.7140 | 0.7378 |
| Balanced accuracy | 0.3960 | 0.3333 |
| Macro F1 | 0.4051 | 0.2830 |
| Weighted F1 | 0.6623 | 0.6265 |
Macro F1 is +43.1% relative to the baseline.
Read macro F1 and balanced accuracy, not accuracy. The fit class is ~74% of the data, so a
model that always predicted fit scores 73.8% accuracy while never once
warning a customer that a size runs small. Accuracy flatters the useless model here.
| config | accuracy | balanced_accuracy | macro_f1 | weighted_f1 |
|---|---|---|---|---|
| baseline (always 'fit') | 0.7378 | 0.3333 | 0.283 | 0.6265 |
| weighting = None | 0.7373 | 0.3409 | 0.3012 | 0.6331 |
| weighting = sqrt | 0.714 | 0.396 | 0.4051 | 0.6623 |
| weighting = balanced | 0.4001 | 0.4918 | 0.3684 | 0.4349 |
sqrt weighting was selected: fully balanced weighting collapses accuracy for a worse
macro-F1, and no weighting barely improves on the baseline.
Sweeping candidate sizes and taking the highest P(fit), evaluated on
3,000 orders the customer reported as fitting:
| Exact size match | 0.036 |
| Within ±1 size | 0.186 |
| Within ±2 sizes | 0.434 |
These are modest. "Exact" understates real usefulness — several sizes can legitimately fit one person and we only observe the one they ordered — but they are low enough that this model must be surfaced as an advisory starting point, never an authoritative size.
A fit-risk advisory for a made-to-measure ordering flow: flagging that a given size is likely to run small or large for this body, as an overridable suggestion alongside proper measurement. It is not a replacement for taking measurements, and should not be presented as one.
height_cm, weight_kg, bmi, bust_band, bust_cup, age, size, body_type, category, rented_for
Most predictive (permutation importance): size, category, weight_kg, rented_for.
Numeric missing values are handled natively by the model — no imputation, because inventing a weight for a customer who never gave one would be fabricating a body measurement.
rating, review_text, review_summary (all recorded after wearing the garment, and
unavailable at prediction time), plus user_id and item_id.
weight_kg and ~10% of bust_band are missing in the source data; predictions for
customers supplying fewer measurements are correspondingly less certain.import joblib, numpy as np, pandas as pd
from huggingface_hub import hf_hub_download
art = joblib.load(hf_hub_download("SamaGalagoda/threadcraft-fit-recommender", "fit_recommender.joblib"))
model, encoder = art["model"], art["encoder"]
customer = {"height_cm": 165, "weight_kg": 61, "bmi": 22.4, "bust_band": 34,
"bust_cup": 2, "age": 29, "body_type": "hourglass",
"category": "dress", "rented_for": "wedding"}
rows = []
for size in art["candidate_sizes"]:
row = {f: customer.get(f, np.nan) for f in art["features"]}
row["size"] = size
rows.append(row)
frame = pd.DataFrame(rows)
for col in art["categorical_features"]:
frame[col] = frame[col].fillna(art["missing_token"]).astype(str)
X = frame[art["numeric_features"]].astype(float)
enc = encoder.transform(frame[art["categorical_features"]])
for i, col in enumerate(art["categorical_features"]):
X[col] = enc[:, i] + 1
proba = model.predict_proba(X[art["features"]])
fit_idx = list(model.classes_).index("fit")
best = max(zip(art["candidate_sizes"], proba[:, fit_idx]), key=lambda t: t[1])
print(f"Suggested starting size {best[0]:.0f} (P(fit)={best[1]:.2f})")
| Algorithm | HistGradientBoostingClassifier (scikit-learn 1.6.1) |
| Boosting iterations | 142 (early stopping, patience 25) |
| Learning rate | 0.08 |
| Max leaf nodes | 31 |
| Class weighting | sqrt |
| Train / Val / Test | 153,972 / 19,246 / 19,247 |
| Hardware | Kaggle CPU (no GPU required) |
Misra, R., Wan, M., & McAuley, J. (2018). Decomposing fit semantics for product size recommendation in metric spaces. RecSys 2018.
Source data: CC BY 4.0, via the UCSD McAuley Lab.