Back to AI architectures leaderboard
hobby Color polygraph · architecture detail Best gender AUC, 2026

LightGBM + bucket scores

Same Single LightGBM as the perceptual-features variant, plus target-encoded colour-bucket scores looked up trilinearly across an 8x8x8 RGB grid. The signed gender-bucket total is the single highest-gain feature in the entire input vector. New top of the gender column.

Scores

Gender AUC
0.881
+0.003 vs perceptual-only
Age MAE
6.89
-0.03 vs perceptual-only
Mood MAE
8.91
+0.04 vs perceptual-only

How the bucket scores work

RGB space is divided into an 8x8x8 grid of 32-wide cubes, with bucket centres at RGB values 16, 48, 80, ..., 240. For each session we build a 512-dim signed delta vector that captures both the colours the user picked and the colours they declined:

Per CV fold (StratifiedKFold for gender, KFold for the regression heads, seed 42), we average the discrete delta vectors across the training rows of each class / target value to build per-bucket score grids:

Lookup uses trilinear interpolation: each colour's contribution is spread across the 8 bucket centres surrounding it in RGB space, with weights summing to 1. A colour exactly at a bucket centre lands entirely in that bucket; a colour in the middle of two adjacent centres splits 50/50; a colour in the middle of the 8-corner cube splits eighths. The per-session feature is then smooth_delta @ grid, which is mathematically equivalent to "look up every event's interpolated grid value, weight by +0.229 or -0.1, sum across the session".

Critically, the grids are built using only training rows in the current fold, so a session's bucket-derived features never depend on its own label - the standard guard against target-encoding leakage.

What the data found on its own

The buckets with the highest girly-vs-masculine lead, computed from the full dataset:

RGB centre Lead
(240, 176, 208)+0.0190
(208, 176, 208)+0.0174
(240, 144, 176)+0.0154
(208, 176, 240)+0.0152
(208, 144, 208)+0.0150

And the most masculine-leaning:

RGB centre Lead
(48, 16, 240)-0.0161
(48, 48, 240)-0.0138
(48, 48, 208)-0.0136
(80, 240, 48)-0.0136
(16, 48, 176)-0.0133

The data identifies the same gender-coded clusters humans would: pinks and light purples lean girly, bright and dark blues lean masculine. The outlier is a single bright green (80, 240, 48) - a boy colour the prototypes I hand-coded missed.

The age grid is just as crisp. Buckets that most predict above-average age are dark and muted: dark blue (80, 80, 208), dark purple (80, 48, 144), dark green (16, 112, 16). Buckets predicting below-average age are pastels and brights: pale pink (240, 208, 240), light cyan (112, 208, 240), white (240, 240, 240). Kids pick light and saturated colours, adults pick muted ones - and the model figures that out from the colour picks alone, without any hand-coding.

Feature importance

Gain-based importance from a full-data LightGBM on gender. The three gender-bucket features absolutely dominate the top of the list (* = new feature from this experiment, all ranks out of 477).

Rank Feature Gain
★ 1signed_total27,326
★ 3girly_total1,789
★ 6masc_total1,119

signed_total alone carries gain 27,326 - more than 2.5x the next-best feature (r1_lab_b_std at 10,689) and more than 15x the next individual bucket feature. The signed difference is the information-dense one because it captures the gender direction with the baseline popularity divided out.

Cached lookup table

After CV the script also fits the four grids on the full dataset and writes them to bucket_scores.npz. Anyone with that file plus the conversion constants can score a new session without re-running training: bucket a colour's RGB into the grid, look up the score with trilinear interpolation, multiply by +0.229 or -0.1 depending on whether the colour was picked, sum across the session. Four numbers come out per session - girly_total, masc_total, age_total, mood_total - and they alone hold most of what the bigger model uses to discriminate.

Configuration

Project links

Back to AI architectures leaderboard