event2vec

Event2Vec

Vectors for event histories. A customer, an account or a machine becomes the sum of its events, and every score you build on top splits exactly into the events behind it.

pip install event2vector

Open source, MIT · scikit-learn API · trains on a laptop CPU · version 0.3.0

Figure 1Why is this customer about to leave?
–
Loading the model…
A churn model built on Event2Vec, explained purchase by purchase. Real customers of a UK online shop (Online Retail II, UCI). Event2Vec learned a 32-number vector for each of 3,114 products from the order in which 5,121 customers bought them, without labels, in 33 seconds on a laptop CPU. A customer's vector is the sum of their purchases. The bars show the model's score for the 90 days after 1 September 2011, split exactly into recency, frequency, spend, tenure and each product they bought; red pushes toward leaving, blue toward staying. The map places every product by its learned vector; the timeline shows one cell per product per order. These are real examples, including ones the model gets wrong.

What the 32 numbers are worth

Every feature set below goes into the same logistic regression and is scored with five-fold cross-validation on who stopped buying in the next 90 days (57% of customers did).

FeaturescolumnsAUC
Which products they bought (tf-idf bag)3,1140.627
Event2Vec vector of the same purchases320.683
Recency, frequency, spend, tenure (RFM)40.787
RFM + Event2Vec360.785

As a description of what someone bought, Event2Vec's 32 numbers beat the full 3,114-column product list, and the gap is largest for customers with short histories (AUC 0.59 vs 0.54 below 20 purchases). Rarely bought products borrow strength from the products they behave like. Recency and frequency still carry most of the churn signal: adding Event2Vec to RFM does not raise the AUC. What it adds is the right-hand side of Figure 1, a reason for every score, product by product.

How it works

Each kind of event gets a vector. A history is the running sum of its events' vectors, kept bounded by a norm clip so very long histories don't blow up. The model learns the vectors by predicting the next event from that sum, so it needs no labels, only events in the order they happened.

h = e1 + e2 + … + en   →   p(next event) = softmax(W h + b)

Because a history is a sum, any linear model on top of it is a sum as well. A churn, fraud or risk score splits into one term per event, the terms add up to the score exactly, and removing an event removes exactly its term. There is no sampling and no surrogate model in that explanation.

score = Σi ei·w + b

Events that lead to similar futures end up with similar vectors. That is what lets 32 numbers describe a customer better than thousands of product columns, and it is why the product map in Figure 1 has structure at all.

Figure 2Compose, then decompose (schematic)
history signed up ordered ordered again returned an item compose: add the vectors h decompose: score = Σ e·w + b signed up ordered ordered again returned baseline 0 toward leaving → ← staying
The whole idea in one picture. Events are added as vectors into one history vector h (left). A linear score on h is a sum of one term per event (right), so the explanation is exact. The values here are illustrative; Figure 1 shows the real thing.

It finds structure nobody labelled

The same estimator, pointed at sequences of letters, sounds and words, separates categories it was never told about, and does so much more cleanly than Word2Vec trained on the same sequences.

Figure 3Letters split into vowels and consonants
Event2Vecsilhouette
Word2Vecsilhouette

Seven ways to add events

The sum in Figure 2 is the Euclidean case. Event2Vec ships six more update rules, each the natural home of a structure plain addition can't carry: hierarchies, cycles, and histories where the order of events changes the outcome. They share one estimator and one argument.

Figure 4The same three events, composed by each geometry
"euclidean"

vector addition

Bags of events and exact explanations. The default, and the fastest.

"hyperbolic"

Möbius addition, curvature c > 0

Hierarchies: product categories, diagnosis codes, org charts.

"stereographic"

κ-addition, signed κ

One dial: κ < 0 hyperbolic, 0 flat, κ > 0 spherical.

"spherical"

κ-addition, κ > 0

Cycles: weekdays, seasons, shift patterns.

"rotation"

product of SO(n) rotations

Histories where the same steps in another order end somewhere else.

"heisenberg"

Heisenberg group product

Same endpoint, opposite signed area: order shows up as a separate number.

"product"

one update per factor

Two structures at once, such as a hierarchy × a cycle.

# one curvature dial
Event2Vec(V,
  geometry="stereographic",
  kappa=-1.0)

# order matters: SO(3)
Event2Vec(V,
  geometry="rotation",
  rotation_n=3)

# hierarchy × cycle
Event2Vec(V,
  geometry="product",
  product_kappas=(-1, 1))
Order is a choice. In the flat Euclidean panel both orders reach the same point, which is what makes its explanations exact. The curved and non-commutative geometries trade some of that exactness for memory of order and room for hierarchies. The animations run the package's own update formulas on three example events.

Where it doesn't help

We tried Event2Vec on other real tasks while building this page. These are the ones where a simpler method did as well or better, measured the same way.

TaskDataEvent2VecBetter or equalWhy
Flag failing sessions in server logs, no labelsHDFS, 575,061 sessions (Loghub)AP 0.27rare-line rule 0.75One line repeats hundreds of times and order matters; a sum blurs both.
Recommend the next basketOnline Retail IIhit@10 0.43rebuy rule 0.75People mostly reorder what they bought before.
Find look-alike customersOnline Retail IIoverlap 0.039tf-idf 0.041Exact product overlap already works well here.
Group WordNet concepts by typeWordNet hypernym paths0.13Word2Vec 0.23On a pure tree, averaging shared ancestors is enough.
Group recipes by cuisine3,723 recipes0.16Word2Vec 0.23A recipe is a set; order carries nothing.

AP: average precision. hit@10: share of customers whose next order contains one of ten suggestions. Overlap: how much ten look-alikes' later purchases overlap with the customer's own (Jaccard). WordNet and recipes: silhouette. Scripts for these runs are in tools/experiments/.

The pattern: Event2Vec earns its place when there are many kinds of events and each history is short or sparse, and when a score has to come with reasons. When a few event types repeat many times, when exact order is the signal, or when a set is all that matters, use a count, a rule or a sequence model.

Quickstart

Give it one list of event IDs per customer, account or machine, in time order. It behaves like any scikit-learn transformer.

from event2vector import Event2Vec

# one list of event IDs per customer, in time order
histories = [[0, 3, 3, 7], [1, 4, 2], ...]

model = Event2Vec(num_event_types=V, geometry="euclidean",
                  embedding_dim=32, pad_sequences=True)
model.fit(histories)                    # no labels needed

X = model.transform(histories)          # one 32-number vector per customer
model.most_similar(3, topn=5)            # events that behave like event 3

Choosing a geometry: see Figure 4. Start with "euclidean"; switch when your events form a hierarchy or when order should matter.

Questions

Can I use it in a commercial product?
Yes. event2vector is MIT licensed: use it, change it and ship it in closed-source software, keeping the copyright notice.
What does my data need to look like?
One list of integer event IDs per entity, sorted by time. Map event names to IDs with a dictionary. Timestamps are only used for sorting.
How big can it get?
The churn example has 590,454 events and trains in about half a minute on a laptop CPU. The model is the number of event types times the vector size, plus a linear decoder; for Figure 1 that is about 200,000 numbers.
Is it production-ready?
It is a research library with a small, stable surface (fit, transform, most_similar) and a test suite. Pin the version (event2vector==0.3.0) and validate on your own data first.
Where do I ask questions?
Open an issue on GitHub, or reach Antonin through sulcantonin.github.io.

Paper

Sulc, A. Event2Vec: A Geometric Approach to Learning Composable Representations of Event Sequences. arXiv:2509.12188.

BibTeX
@article{sulc2025event2vec,
  title   = {Event2Vec: A Geometric Approach to Learning
             Composable Representations of Event Sequences},
  author  = {Sulc, Antonin},
  journal = {arXiv preprint arXiv:2509.12188},
  year    = {2025}
}