THE OBVIOUS MEASUREMENT SAYS THE TRANSFER FAILS COMPLETELY, AND IT IS WRONG. A filter trained on 5,574 labelled SMS messages, applied to 1,956 YouTube comments at the default 0.5 cutoff, scores 53.2% accuracy against a majority-class rate of 51.4%, catching 9.5% of the spam. That reads as total failure and it is the number you get by running the obvious code. It is measuring the wrong thing.
A borrowed spam filter fails here — and the obvious way to measure that is wrong
Does a spam filter trained on 5,574 labelled SMS messages work on 1,956 YouTube comments, and how many of your own labels would it take to do better?
What the analysis found, including the results that went against us
Each of these came out of the run. None has been softened.
Your own labels against five thousand borrowed ones
Accuracy against the number of in-domain labels used for training, with the best result from all 5,572 borrowed labels shown as a flat line. The curve crosses it early.
run.py section 6: held out on one video, averaged over five choices and ten draws.
THE DEFAULT CUTOFF ENCODES THE SPAM RATE OF THE CORPUS THE MODEL LEFT BEHIND. SMS is 13.4% spam and these comments are 51.4% — a factor of 3.8. A model trained where spam is rare puts most of its probability mass below 0.5, so almost nothing clears the bar in a population where spam is common. Move the cutoff to the target's own rate — which needs an estimate of how much spam you have, not labels saying which comments are spam — and accuracy goes from 53.2% to 69.4%, and recall from 9.5% to 70.5%. The model never changed and neither did its predictions.
Accuracy by threshold, transferred filter
Accuracy of the borrowed filter on YouTube comments as the decision threshold moves. The default of 0.5 sits far from the best available cutoff, because it encodes the spam rate of the corpus the model was trained on.
run.py section 4: one model, one set of predictions, threshold swept.
WHAT ACTUALLY TRANSFERRED IS MODEST, AND AUC IS HOW YOU SEE IT. The borrowed filter's AUC on these comments is 0.774. AUC reads the ranking alone and is unaffected by the threshold, which is exactly why it is the honest measure when a model moves between populations — accuracy at a fixed cutoff conflates how well the model separates the classes with a decision rule calibrated somewhere else.
Detection quality per video
Area under the ROC curve for each held-out video when the filter is trained on the other four. Five videos is a thin basis for a general claim.
run.py section 5: leave-one-video-out.
A FILTER TRAINED ON THE TARGET'S OWN COMMENTS SCORES 0.982 AGAINST 0.774 BORROWED. Trained on four videos and tested on the fifth, held out entirely, the in-domain filter reaches 93.3% accuracy. The gap to the borrowed filter is the cost of using someone else's corpus, and it is large.
ABOUT 25 OF YOUR OWN LABELS BEAT ALL 5,574 BORROWED ONES. Training on a random sample of in-domain comments and testing on a held-out video, accuracy passes the best the borrowed corpus achieves at roughly 25 labels — about one 223th of the borrowed set. For a team deciding whether to label their own data, that is the number that matters, and an afternoon covers it.
SHUFFLING THE SPLIT WOULD HAVE ADDED 2.0 POINTS FOR NOTHING. Pooled five-fold cross-validation over all the comments scores 95.3% against 93.3% leave-one-video-out. Comments under one video share vocabulary, campaigns and posting bots, so a shuffled split trains on the same video it tests on and measures memorisation as much as detection. The gap is small here and rests on five videos, but its direction is the one that flatters.
THE RANKING IS STABLE ACROSS VIDEOS AND THE DECISION IS NOT. Held-out AUC varies only from 0.983 to 0.990 across the five videos, while accuracy at the same fixed cutoff spans 89.4% to 95.9% — a range of 6.5 points. It is the threshold lesson again at a smaller scale: what a model knows travels between populations more reliably than where you should cut it, and a single accuracy figure conflates the two.
Full results tables
The same model, two thresholds
| Measure | Default 0.5 cutoff | Cutoff moved to the local spam rate |
|---|---|---|
| Accuracy | 53.2% | 69.4% |
| Recall on spam | 9.5% | 70.5% |
| AUC (unchanged — the ranking is the same) | 0.774 | 0.774 |
Per-video, trained on the other four
| Video | Comments | AUC | Accuracy |
|---|---|---|---|
| Eminem | 448 | 0.983 | 93.1% |
| KatyPerry | 350 | 0.983 | 94.9% |
| LMFAO | 438 | 0.990 | 95.9% |
| Psy | 350 | 0.986 | 89.4% |
| Shakira | 370 | 0.987 | 92.7% |
How many of your own labels you need
| In-domain labels | Accuracy |
|---|---|
| 10 | 60.5% |
| 25 | 75.3% |
| 50 | 81.0% |
| 100 | 86.3% |
| 200 | 89.7% |
| 400 | 91.5% |
| 800 | 92.4% |
| 1500 | 93.2% |
Limitations
Stated by the analysis, not added afterwards. A project without these is not finished.
- Five videos is a thin basis for a general claim. Every per-video figure rests on 350 to 448 comments, and the pooled-versus-held-out gap in particular rests on five clusters. The direction of these results is clear; their magnitude on any other corpus is not established by this one.
- The comments were collected in 2013 and 2014 and spam is adversarial — it moves precisely because filters catch it. Nothing here supports a claim about how any filter would perform on comments written now. What transfers is the measurement lesson, not the accuracy.
- Author names were dropped at load and every run of digits in the comment text was replaced before anything read it — 56 comments contained one. These are real messages written by real people, some containing contact details, and none of it is needed to classify a comment. Digits are replaced rather than deleted because 'call this number' and 'call' are different sentences, but no number survives into the model, the charts or this page.
- Both corpora label English text at message length, so nothing here transfers to long-form content, other languages, or media. Two datasets that are both 'spam or not' turn out to be very different problems, which is the finding — and it applies to this pair, not to corpus transfer in general.
- The threshold correction uses the target's overall spam rate, which a team would have to estimate. A wrong estimate moves the cutoff and the accuracy with it, so the improvement reported here is the best case for that method rather than what an operator would reliably obtain.
- TF-IDF with logistic regression is deliberately ordinary. A modern text model would score higher on both sides of the comparison, and might narrow or widen the gap — this project does not test that, and its subject is the corpora rather than the architecture.
Data: UCI YouTube Spam Collection with UCI SMS Spam Collection, UCI YouTube Spam Collection with UCI SMS Spam Collection, CC BY 4.0. 7,528 rows, YouTube comments 2013-2014; SMS collected 2011-2012.
Libraries and methods this analysis used
Read from this project's own run.py when the page was built — 410 lines of it. Not a list of everything we know; a list of what this analysis imports and calls.
7 names from NumPy appear in this analysis.
- array_split
- concatenate
- errstate
- isfinite
- linspace
- quantile
- random
4 names from scikit-learn appear in this analysis.
- LogisticRegression
- TfidfVectorizer
- accuracy_score
- roc_auc_score
3 names from pandas appear in this analysis.
- astype
- read_csv
- transform
How every number on this page is checked
A script deletes each result file, re-runs the project and diffs the output. If a headline figure moves, the check fails, and the page does not ship. That is the only reason to believe anything on this page.
Running this method on your own data
The method above transfers; the result will not. Send us a extract and we will tell you what is forecastable in it and what is not, before anyone signs anything.