Links: CS224W L05 (GNN training: dataset splits, transductive vs inductive, the L05 proof workshop on AUC),
notebooks/project/retweet_thread.py §L05 and §L06–07 (the same detector). Atlas: evaluation; social networks.
Question
Graph benchmarks split nodes at random. In a coordination problem that means members of the same ring land on both sides of the split, and anything the model learns about one member (its targets, its partners, its label if the model uses neighbours' labels) transfers to the others for free. A platform never gets that: the campaign it must catch next month is made of accounts it has never labelled. How large is the gap between the number a paper would report and the number a deployment would see?
Hypotheses (written before running)
-
Label-free model. For a detector that uses only features and structure (no labels of neighbours), a random node split and a ring-held-out split agree within 0.03 AUC.
-
Label-aware model. For a detector that also uses training labels of neighbours (share of known-bot neighbours, label propagation), the random split overestimates the ring-held-out split by at least 0.10 AUC.
-
New world = unseen rings. Training on one world and testing on another gives the label-free model about the same AUC as the ring-held-out split (within 0.03).
-
Early detection. Testing on a new world observed only for its first 10 days (of 30) costs the label-free model at least 0.10 AUC against full observation.
-
Link prediction. For Adamic–Adar, common neighbours and preferential attachment, a random edge split overestimates the temporal split (days 0–20 → new edges in days 20–30) by at least 0.05 AUC in every world type.
Setup
- Worlds: reciprocal and co-amplification rings (
gl.exp.WORLD_TYPES), seeds inconfig.yaml. -
Label-free detector: 7 account features, their neighbourhood means, reciprocity and mutual triangles (the project's feature set 4), logistic regression.
-
Label-aware detector: the same plus three features built from the training labels only: share of neighbours that are known bots, share that are known humans, and a label-propagation score.
-
Protocols: random stratified 5-fold node split; ring-held-out (each fold holds out one whole ring and a random share of humans); cross-world (train on world a, test on world b, where 10% of humans are known and no bot is); early detection (cross-world, test world truncated at day 10).
Run: uv run marimo edit experiments/honest-splits/honest_splits.py and press the run button. The notebook writes
results.md and results.json.
Added after the first run (not tests): a features-only model, because the full label-free model was at the ceiling on reciprocal worlds; and a 1-hop-only label-aware model, to locate the leak.
Results (summary; full tables in results.md)
| world | model | random | ring-held-out | cross-world | early (day 10) |
|---|---|---|---|---|---|
| reciprocal | label-free | 0.996 | 0.991 | 0.995 | 0.894 |
| reciprocal | label-aware | 1.000 | 0.754 | 0.919 | 0.730 |
| co-amplify | label-free | 0.950 | 0.919 | 0.954 | 0.914 |
| co-amplify | label-aware | 0.872 | 0.696 | 0.883 | 0.817 |
- H1 refuted, narrowly. Label-free gap 0.005 (reciprocal) but 0.031 (co-amplify), just over the 0.03 threshold.
-
H2 supported, strongly. The label-aware model loses 0.246 (reciprocal) and 0.176 (co-amplify) when whole rings are held out. Worse: on held-out rings it is below the label-free model (0.754 vs 0.991), because it learned to rely on "my neighbours are known bots", which is zero for a ring nobody has labelled. A model selected on a random split is the wrong one to deploy.
-
Where the leak travels. With 1-hop label features only, the gap is 0.190 on reciprocal rings (members are neighbours) but 0.074 on co-amplification rings; label propagation adds the rest there, carrying labels two hops through shared targets.
-
H3 refuted. Cross-world is higher than ring-held-out on co-amplification worlds (0.954 vs 0.919): ring-held-out trains on only two of three rings, so it is pessimistic about data size as well as honest about leakage.
-
H4 refuted. Ten days instead of thirty cost 0.10 on reciprocal worlds (0.995 → 0.894) but only 0.04 on co-amplification worlds.
-
H5 supported. Random edge splits overestimate temporal ones by 0.12–0.14 AUC for all three heuristics in both worlds.
Real-data extension: temporal link prediction (added after the first run; hypotheses written before running it)
Hypothesis 5 held on synthetic worlds. Real networks grow by mechanisms nobody wrote down, so the gap could be larger,
smaller or reversed. Five timestamped social networks from gl.datasets: CollegeMsg (messages), EU e-mail (temporal),
Bitcoin OTC (trust ratings), MathOverflow (answers and comments) and Higgs Twitter (retweets only). Each pair's first
interaction time decides its side of the split: pairs that first appear before the 80% quantile form the past graph,
later pairs between two accounts already in the past graph are the temporal positives. The random split hides the same
number of pairs drawn from all pairs. Negatives are random non-edges; three seeds; at most 5,000 positives per split.
-
The leak is real. On every real network, the random split overestimates the temporal split by at least 0.05 AUC for common neighbours and for Adamic–Adar.
-
Growth is rich-get-richer. For preferential attachment the gap (random − temporal) is smaller than for Adamic–Adar on every network, because new real ties attach to hubs more than they close triangles.
Run: the second button in the notebook (a few minutes; Higgs and MathOverflow are the large ones). Results go to
real_results.json and a separate section of results.md.
Real-data results (summary; full table in results.md)
Random − temporal AUC (means over 3 seeds):
| network | common neighbours | Adamic–Adar | preferential attachment |
|---|---|---|---|
| CollegeMsg | +0.127 | +0.127 | +0.079 |
| EU e-mail (temporal) | +0.048 | +0.048 | +0.041 |
| Bitcoin OTC | +0.042 | +0.041 | −0.090 |
| MathOverflow | +0.045 | +0.045 | −0.010 |
| Higgs (retweets) | −0.011 | −0.011 | −0.480 |
-
H6 refuted. The random split overestimates the neighbourhood heuristics on four of five networks, but by ≥ 0.05 only on CollegeMsg (+0.13, as large as in the synthetic world); on e-mail, Bitcoin and MathOverflow the gap is 0.04–0.05. The direction of hypothesis 5 holds on real data; its size was a property of the synthetic world.
-
H7 supported. Preferential attachment's gap is smaller everywhere, and negative on Bitcoin, MathOverflow and Higgs: in a temporal split new ties go to hubs, so degree predicts the future better than it predicts a random hold-out.
-
Higgs is a different question, not a counter-example. 55% of randomly hidden Higgs pairs touch an account with no other tie (1–10% elsewhere): most retweeters act once, so the random split is mostly cold start (degree 0 after hiding, PA = 0), while the temporal protocol keeps only pairs of accounts already seen. Read the Higgs row as "random splits of cascade data test cold start", which is a protocol choice to state, not a leak.
Next steps
- A trained GNN with label features (label trick, Wang & Leskovec 2021) under the same protocols.
-
Train-time ring masking: drop the label features of a random half of known bots during training so the model cannot lean on them (the remedy the label trick uses).
-
Temporal campaigns: rings that start mid-month, with a split by account creation time.
Results
Generated by honest_splits.py from config.yaml (worlds [0, 1, 2], cross-world pairs
[[0, 1], [1, 2], [2, 0]]). Bot-detection AUC, means over worlds.
| world | model | random | ring-held-out | cross-world | early (day 10) | random − ring-held-out |
|---|---|---|---|---|---|---|
| co-amplify | features only | 0.882 | 0.865 | 0.863 | 0.809 | 0.017 |
| co-amplify | label-aware | 0.872 | 0.696 | 0.883 | 0.817 | 0.176 |
| co-amplify | label-aware, 1-hop only | 0.938 | 0.864 | 0.962 | 0.902 | 0.074 |
| co-amplify | label-free | 0.950 | 0.919 | 0.954 | 0.914 | 0.031 |
| reciprocal | features only | 0.824 | 0.824 | 0.838 | 0.736 | -0.000 |
| reciprocal | label-aware | 1.000 | 0.754 | 0.919 | 0.730 | 0.246 |
| reciprocal | label-aware, 1-hop only | 1.000 | 0.810 | 0.909 | 0.732 | 0.190 |
| reciprocal | label-free | 0.996 | 0.991 | 0.995 | 0.894 | 0.005 |
Early detection (cross-world AUC by days of the test world observed):
| world | model | day 3 | day 5 | day 10 | day 15 | day 20 | day 30 |
|---|---|---|---|---|---|---|---|
| co-amplify | features only | 0.657 | 0.707 | 0.809 | 0.825 | 0.852 | 0.863 |
| co-amplify | label-aware | 0.727 | 0.737 | 0.817 | 0.822 | 0.870 | 0.883 |
| co-amplify | label-aware, 1-hop only | 0.697 | 0.790 | 0.902 | 0.911 | 0.935 | 0.962 |
| co-amplify | label-free | 0.707 | 0.816 | 0.914 | 0.920 | 0.941 | 0.954 |
| reciprocal | features only | 0.720 | 0.749 | 0.736 | 0.792 | 0.817 | 0.838 |
| reciprocal | label-aware | 0.582 | 0.602 | 0.730 | 0.805 | 0.854 | 0.919 |
| reciprocal | label-aware, 1-hop only | 0.568 | 0.621 | 0.732 | 0.803 | 0.844 | 0.909 |
| reciprocal | label-free | 0.701 | 0.782 | 0.894 | 0.964 | 0.979 | 0.995 |
Link prediction (AUC):
| world | heuristic | random edge split | temporal split | random − temporal |
|---|---|---|---|---|
| co-amplify | Adamic–Adar | 0.848 | 0.708 | +0.139 |
| co-amplify | common neighbours | 0.842 | 0.706 | +0.135 |
| co-amplify | preferential attachment | 0.816 | 0.672 | +0.144 |
| reciprocal | Adamic–Adar | 0.848 | 0.722 | +0.127 |
| reciprocal | common neighbours | 0.842 | 0.721 | +0.121 |
| reciprocal | preferential attachment | 0.809 | 0.677 | +0.132 |
Verdicts: H1 refuted, H2 supported, H3 refuted, H4 refuted, H5 supported.
Real-data extension
Generated by honest_splits.py (real-data extension) from config.yaml: networks ['collegemsg', 'email-eu-temporal', 'bitcoin-otc', 'mathoverflow', 'higgs-activity'],
cut at the 80% quantile of first-contact times, seeds [0, 1, 2]. Link-prediction AUC, means over seeds.
| network | heuristic | random edge split | temporal split | random − temporal |
|---|---|---|---|---|
| collegemsg | Adamic–Adar | 0.777 | 0.650 | +0.127 |
| collegemsg | common neighbours | 0.773 | 0.646 | +0.127 |
| collegemsg | preferential attachment | 0.887 | 0.808 | +0.079 |
| email-eu-temporal | Adamic–Adar | 0.943 | 0.894 | +0.048 |
| email-eu-temporal | common neighbours | 0.937 | 0.889 | +0.048 |
| email-eu-temporal | preferential attachment | 0.858 | 0.817 | +0.041 |
| bitcoin-otc | Adamic–Adar | 0.816 | 0.775 | +0.041 |
| bitcoin-otc | common neighbours | 0.814 | 0.772 | +0.042 |
| bitcoin-otc | preferential attachment | 0.840 | 0.930 | -0.090 |
| mathoverflow | Adamic–Adar | 0.930 | 0.885 | +0.045 |
| mathoverflow | common neighbours | 0.929 | 0.884 | +0.045 |
| mathoverflow | preferential attachment | 0.944 | 0.954 | -0.010 |
| higgs-activity | Adamic–Adar | 0.541 | 0.553 | -0.011 |
| higgs-activity | common neighbours | 0.541 | 0.552 | -0.011 |
| higgs-activity | preferential attachment | 0.447 | 0.927 | -0.480 |
Share of random-split positives with a cold-start endpoint (degree 0 after hiding): collegemsg 0.03; email-eu-temporal 0.01; bitcoin-otc 0.12; mathoverflow 0.03; higgs-activity 0.55.
Verdicts: H6 refuted, H7 supported.
In the repository: experiments/honest-splits/ · README.md config.yaml honest_splits.py real_results.json results.json results.md