cristianbabalau.dev
← cd ../blog
#thesis#Python#NLP#graph analysis#influence operations

Hunting Coordinated Bots with Temporal Semantic Proximity

ccristianbabalau·JUN 2026·4 min read
Hunting Coordinated Bots with Temporal Semantic Proximity

Influence operations don't announce themselves. They coordinate dozens or hundreds of accounts to push the same narrative, slightly reworded, at roughly the same time. Behavioural detectors catch the clumsy ones (synchronized retweets, identical posting schedules), but accounts paraphrasing a shared script slip right through. My BSc thesis asks: what if we measured *what* accounts say and *when* they say it, together?

The Idea: TSPA

Temporal Semantic Proximity Analysis (TSPA) scores pairs of accounts by the semantic similarity of their posts inside sliding time windows. Two accounts that repeatedly post near-identical *meaning* within the same window accumulate proximity, a content-based signal that complements the behavioural traces most existing detectors rely on. Every post is embedded with multilingual sentence-transformer embeddings (768-dimensional MPNet), so paraphrases and even cross-language repeats land close together in vector space.

Making It Scale

The pipeline processes up to 500k tweets per campaign across 14 real-world Twitter influence operations. All-pairs cosine similarity over half a million 768-d vectors will happily eat all your RAM, so the core step is a memory-bounded, row-chunked BLAS matrix multiplication in NumPy. Together with a thorough complexity-optimization pass, the pipeline went from exponential to logarithmic time. The lesson: at this scale, cosine similarity is a memory-layout problem before it's a math problem.

If your NumPy job is swapping, no amount of vectorization will save you. Chunk the rows, bound the working set, and let BLAS do what BLAS does.

From Similarity to Communities

Pairwise proximity scores become weighted user-similarity graphs. On those I run weighted Leiden community detection (igraph / leidenalg) and rank accounts by eigenvector centrality to surface the coordinated core of each cluster. Everything is explorable in an interactive VIS-Network.js dashboard, cross-referenced with documented examples of prior *Coordinated Infamous Activity*.

Did It Work?

Benchmarked against behavioural-trace baselines with ROC-AUC, PR-AUC, and non-parametric significance testing, TSPA surfaces coordinated communities with purities up to 100%, and more interestingly, it complements behavioural signals rather than duplicating them. Content and timing catch what schedules alone miss.

Stack for the curious: Python, NumPy, pandas, scikit-learn, SciPy, sentence-transformers, NetworkX, igraph, leidenalg, Jupyter, VIS-Network.js.

share: