Estimating agent-based models by matching random features

An agent-based simulation is easy to run and hard to fit. This explainer shows how to estimate its p unknown parameters by asking the real data and the simulated data the same 2p + 1 randomly chosen questions, then tuning the parameters until the answers agree.

Written for statistics undergraduates. Based on Shalizi (2021) and two papers by Wieck-Sosa and Shalizi (2026). The epidemic model and all interactive figures were built for this page and do not appear in those papers.

susceptible infected recovered

What you need before starting

Expectation and variance, the sample mean and the law of large numbers, the normal distribution, and the idea of an estimator. Everything else is introduced when it is needed. Each step has a figure you can operate. The figures run small simulations in your browser, so numbers differ a little from run to run.

1An agent-based model is a probability distribution you can only sample from

An agent-based model (ABM) is a computer program that tracks many individual agents: people, animals, firms, cars. Each agent has a state and follows simple rules that involve chance and depend on nearby agents. Nobody writes down a formula for the behavior of the whole population. The large-scale pattern comes from running the rules.

The running example on this page is a small epidemic. There are 1,024 people arranged on a 32 by 32 grid whose edges wrap around. Each person is susceptible, infected, or recovered. Every day:

The unknown parameter vector is θ = (β, γ), so the number of parameters is p = 2. We never see the grid. We see two numbers per day: the percentage of positives among 400 randomly tested people (the test has sensitivity 0.95 and specificity 0.99), and the count of new cases. The observed data are a time series X1, …, Xn where each Xt has d = 2 entries.

    Try this. Press Run twice without moving the sliders. The two traces differ day by day, yet they fluctuate around the same level with the same rhythm. Then change γ and run again: the whole pattern shifts. Each run starts from a random mix of states and an 80 day warm-up so that the starting configuration no longer matters.

    Two facts from this figure drive everything that follows.

    For a fixed θ, the output is random. The model therefore defines a probability distribution Pθ over whole time series. A run of the program is one draw from Pθ.

    Changing θ changes the distribution, not any particular value. Estimation means finding the θ whose distribution most plausibly produced the series we observed. The true value is written θ0.

    2Why maximum likelihood is out of reach

    The standard recipe for estimation is maximum likelihood. Write the probability of the observed data as a function of the parameter, L(θ) = p(xobs; θ), and choose the θ that makes it largest. Bayesian inference needs the same function. Both require a formula for p(x; θ), or at least a way to compute it.

    In an ABM the observed numbers depend on the hidden history h of every agent on every day. The probability of the data is a sum over all hidden histories that could have produced it:

    p(xobs; θ) = Σh p(xobs, h; θ)
    Parameters θ = (β, γ) Hidden history 1,024 agents × 300 days Observed series 2 numbers × 300 days Forward: run the program. A few milliseconds. Backward: the probability of the data is a sum over every hidden history 3307,200 ≈ 10146,571 possible histories
    Each of the 1,024 × 300 = 307,200 agent-days can be in one of three states. For comparison, the observable universe holds roughly 1080 atoms. No algebra trick collapses this sum for a model with local interactions.

    The situation is lopsided. Drawing a sample from Pθ is cheap. Evaluating the probability that Pθ assigns to a given series is infeasible. Methods built for this situation are called likelihood-free or simulation-based inference.

    3The simulation-based idea: match summaries, and the trouble with choosing them

    If we cannot compute probabilities, we can still compare. Pick a summary: any function T that turns a data set into a few numbers. Compute T on the real data. Then search for the θ whose simulated data give about the same T. The method of simulated moments, indirect inference, and approximate Bayesian computation are all versions of this loop.

    Propose θa candidate value Simulaterun the ABM at θ SummarizeT(simulated data) Comparedistance T(observed data)computed once adjust θ to shrink the distance, repeat

    The whole method stands or falls on the choice of T. Good summaries must be (i) easy to compute, (ii) sensitive to the parameters, and (iii) identifying: two different parameter values must not produce the same expected summary. The third property is the hard one. The figure below tries the most natural summary for our epidemic, the average percentage of positive tests.

    The observed data were generated at β = 0.10, γ = 0.15 (the cross). Press the button to simulate at 324 parameter values and color each cell by how far its average positive share is from the observed one.

    What to look for. The stronger the violet, the closer a cell comes to the observed average. The matching cells form a long curved valley, not a single spot. A more contagious disease with faster recovery gives the same average as a less contagious one with slower recovery. One summary cannot pin down two parameters, and adding a second summary only helps if it reacts to β and γ in a different way from the first.

    In practice, scientists either hand-craft summaries using deep knowledge of the model and then check properties (i) to (iii) by trial and error, or they train neural networks to learn summaries from many simulated data sets, which costs a lot of computation. The proposal examined here is a third route: choose the summaries at random, from a family of functions rich enough that a handful of them will identify the parameters with probability one.

    4A random feature is a random question about a distribution

    Start with a fact from probability theory. A distribution is fully described by the expected values it gives to a rich enough family of test functions. One such family is the sines and cosines. The characteristic function of a random variable X is

    ψ(ω) = E[eiωX] = E[cos(ωX)] + i E[sin(ωX)]

    It plays the same role as the moment generating function, with the advantage that it always exists. The uniqueness theorem says that two distributions with the same ψ at every frequency ω are the same distribution. So "what is E[cos(ωX)]?" is a question about the distribution, and the collection of all such questions has a unique answer sheet for each distribution.

    A random Fourier feature is one of these questions, drawn at random:

    φ(x) = cos(ωx + α),   ω ~ N(0, 1),   α ~ Uniform(−π, π)

    Random Fourier features come from machine learning (Rahimi and Recht, 2007), where they are used to speed up kernel methods. Here they do a different job: they act as probes that tell probability distributions apart. In statistics any function of the data is called a statistic. Machine learning calls it a feature, and the papers follow that usage. The frequency ω and phase α are drawn once, before looking at the data, and then held fixed. The expected value of the feature under parameter θ is written Φ(θ) = Eθ[φ(X)]. A trigonometric identity shows that it reads off the characteristic function at the random frequency: Φ(θ) = cos(α) Re ψθ(ω) − sin(α) Im ψθ(ω).

    The simplest test case has one parameter: independent draws from a normal distribution with unknown mean μ and variance 1. There Φ(μ) = eω²/2 cos(ωμ + α), which the figure plots on the right.

    Left. 200 data points (dots) placed on the wave cos(ωx + α). The feature value is the average height of the dots. Right. The expected feature value Φ(μ) as μ varies, with the current sample average marked. Slide μ and watch the dots ride up and down the wave. Hollow circles mark other values of μ that would give the same feature value. For display, frequencies near zero are skipped.

    Three things to take from this figure. First, the sample average of the feature lands close to its expected value: that is the law of large numbers at work. Second, the feature responds smoothly to the parameter, so it carries information about μ. Third, one feature is not enough. The curve on the right goes up and down, so several values of μ share the same feature value. A single question has an ambiguous answer.

    5Why 2p + 1 random features are enough

    Use k features at once and stack their expected values into a vector Φ(θ) = (Φ1(θ), …, Φk(θ)). As θ moves through the p-dimensional parameter space, Φ(θ) traces a p-dimensional shape inside k-dimensional space. The parameters are identified by the features when this map is one-to-one: the shape never passes through the same point twice. Then knowing Φ tells you θ.

    For the normal mean, p = 1 and the shape is a curve. The figure lets you compare k = 2 with k = 2p + 1 = 3.

    The curve Φ(μ) for μ from −8 to 8, colored from teal (μ = −8) through violet to pink (μ = 8). Axes are rescaled to fill the box. With two features the curve lies in a plane and crosses itself: each ring marks two different means that the features cannot tell apart. With three features the same curve has room to pass over and under itself. Drag to rotate.

    The string picture and the counting argument

    Drop a long piece of string on a table and it will cross itself. Wave the same string around in the air and freeze it: the chance that two separate points of the string occupy the same point in space is zero. A curve needs three dimensions to avoid itself. A p-dimensional surface needs 2p + 1.

    Here is why that number appears. A failure of identification is a pair of different parameter values θ and θ′ with Φ(θ) = Φ(θ′). The pair (θ, θ′) has 2p free coordinates. Each feature contributes one equation, Φi(θ) = Φi(θ′). With 2p + 1 independent equations and only 2p unknowns, the system is overdetermined, and for randomly chosen equations it has no solutions apart from the trivial ones with θ = θ′.

    ModelParameters pFeatures 2p + 1
    Normal mean (this step)13
    Grid epidemic on this page25
    Hénon map with noise (paper)37
    Lorenz-63 with noise (paper)613
    Structural time series (paper)817

    What the theorem says

    The idea has a long history in geometry and in nonlinear dynamics. Whitney (1936) showed that a typical smooth map of a d-dimensional manifold into 2d + 1 dimensions is one-to-one. Takens (1981) used this to show that the state of a d-dimensional dynamical system can be rebuilt from 2d + 1 delayed readings of a single measurement. Sauer, Yorke and Casdagli (1991) replaced "typical" with a probabilistic "almost every". Those results concern generic smooth maps, which one cannot sample from. Wieck-Sosa and Shalizi (2026) prove the version needed for statistics, using a recent result called the finite witness theorem (Amir et al., 2023). In plain terms:

    Theorem (informal). Suppose (1) the parameter space Θ is a closed, bounded region with a simple shape, such as a box; (2) different parameter values give different distributions, so the model is identifiable in principle; and (3) the characteristic function of the model depends smoothly (analytically) on the parameter and the frequency. Draw k = 2p + 1 random Fourier features. Then, with probability one over that draw, the map from θ to the expected feature values Φ(θ) is one-to-one on Θ.

    Nothing in the statement requires understanding the model, inspecting the data, or knowing which aspects of the output are informative. That is the practical appeal for ABMs, where such understanding is hard to come by.

    One caution. The theorem is about identification: the expected feature values determine θ. It does not say how precisely θ can be estimated from a finite, noisy data set. Precision depends on how strongly the features react to θ relative to their sampling noise. Steps 6 to 9 deal with data.

    6From expectations to data: average the features over time

    The theorem speaks of expected values. We have one observed time series, not an expectation. With independent data, the sample mean estimates the expectation. With time series the observations depend on each other, but the same trick still works under two conditions: the process is stationary (its statistical behavior does not drift over time) and its memory fades (what happened long ago has little influence on today). Then the ergodic theorem, the law of large numbers for dependent data, says that averages over time converge to expectations.

    Features that see the dynamics

    A feature that looks at one day at a time only learns about the distribution of single days. To learn how today depends on yesterday, let each feature read a short window of m + 1 consecutive days. With d numbers per day the window holds (m + 1) × d numbers, and the feature assigns a random frequency to each one:

    φi(xtm, …, xt) = cos( Ωi,1 · xtm + … + Ωi,m+1 · xt + αi )

    Each Ωi,j is a vector of d independent N(0, 1) draws and the dot is the dot product. For a model where tomorrow depends only on today (a Markov model) the papers suggest m = 1. Our epidemic observed through noisy tests is not exactly Markov in the observed series, but m = 1 works well. The summary that gets matched is the time average of each feature:

    Fi = (1 / (nm)) Σt=m+1…n φi(Xtm, …, Xt)
    Top. One simulated run of the epidemic at β = 0.10, γ = 0.15. Both series are shown in the units used by the features (one unit is 4 percentage points, or 5 cases). The shaded band is the two-day window that the feature reads on the current day. Bottom. Small dots are the daily feature values: noisy and hard to interpret. The thick line is their running average. Thin lines are running averages from three other runs with the same parameters. All four settle toward the dashed line, the long-run expected value estimated from a run of 6,000 days.

    When the process is not stationary

    Many ABMs are run from a special starting state and never settle: an outbreak that rises and burns out, a market after a shock, a city that grows. Then the expected feature value changes over time, and a single average over the whole series blurs the early and late behavior together. The second estimator in Wieck-Sosa and Shalizi (2026) replaces the global average by rolling-window averages: the mean feature value over the last w days, computed at every day, for both the observed and the simulated series. The parameter estimate minimizes the average squared gap between the two rolling curves. The supporting theory uses a regime in which more data means denser sampling of the same episode, called infill asymptotics.

    A single outbreak with no loss of immunity, observed for 120 days at true β = 0.08 (dark line). The orange line averages 3 simulations at the slider value. Bottom. Rolling 15-day averages of one random feature for observed and simulated data. Move the slider until the two rolling curves lie on top of each other. The readout reports the rolling mismatch summed over three random features (2p + 1 with p = 1). The full estimator in the paper adds a correction term and data-driven rules for the window length; see the source for details.

    7The full recipe

    Here is the time-average estimator from start to finish, for an ABM with p parameters whose output is a d-dimensional time series of length n.

    1. Set up. Choose the parameter box Θ. Put each output series in units where its fluctuations are of order 1, using constants fixed in advance.
    2. Draw the questions. Draw k = 2p + 1 random Fourier features: frequencies Ω from N(0, 1), phases α from Uniform(−π, π). Do this once and store them.
    3. Question the data. Compute the k time averages on the observed series. Call the result Fobs.
    4. Question the simulator. For a candidate θ, run the ABM s times, compute the same k time averages on each run, and average over runs. Call the result sim(θ).
    5. Measure the mismatch. Q(θ) = ‖Fobssim(θ)‖, the Euclidean distance between two points in k-dimensional space.
    6. Search. Hand Q to a global optimizer. The estimate θ̂ is the minimizer.
    candidate θ simulate s runs with fixed seeds run 1 run 2 run s observed series the same k = 2p + 1 random features, averaged over time F(run 1) F(run 2) F(run s) F obs Q(θ) = distance( F obs , average of F(runs) ) optimizer proposes a new θ
    The observed series and every simulated series pass through the same features. The features are drawn once and never change during the search.

    In Python the core fits in a few lines. Here run_abm stands for your simulator and must return an array with n rows and d columns.

    import numpy as np
    from scipy.optimize import differential_evolution
    
    p, d, m, s = 2, 2, 1, 10
    k = 2 * p + 1
    rng = np.random.default_rng(1)
    Omega = rng.normal(size=(k, (m + 1) * d))     # random frequencies, drawn once
    alpha = rng.uniform(-np.pi, np.pi, size=k)    # random phases, drawn once
    
    def features(X):                              # X has shape (n, d), already rescaled
        n = len(X)
        W = np.hstack([X[j:n - m + j] for j in range(m + 1)])   # all windows of m+1 days
        return np.cos(W @ Omega.T + alpha).mean(axis=0)         # k time averages
    
    F_obs = features(X_obs)
    
    def Q(theta):
        runs = [features(run_abm(theta, n=len(X_obs), seed=r)) for r in range(s)]
        return np.linalg.norm(F_obs - np.mean(runs, axis=0))
    
    fit = differential_evolution(Q, bounds=[(0.03, 0.25), (0.05, 0.35)], seed=2)
    theta_hat = fit.x

    Practical choices

    How many simulations s per candidate?

    The papers use s = 10 throughout. Simulation noise inflates the variance of the estimate by a factor of 1 + 1/s relative to having exact expectations, so s = 10 costs 10 percent and larger values bring little.

    Reuse the same random seeds for every candidate

    In the code above, run r always uses seed r. This is the method of common random numbers. Without it, Q would jump randomly between two evaluations at the same θ, and the optimizer would chase noise. With it, Q is a fixed function of θ. The papers formalize this by writing the simulated series as a function of θ and a sequence of noise inputs.

    Use a global optimizer

    The mismatch surface of a stochastic simulator is bumpy, and gradients are unavailable. Shalizi (2021) used generalized simulated annealing. Wieck-Sosa and Shalizi (2026) used differential evolution from SciPy and report that other optimizers perform comparably. The cost of the whole procedure is (number of evaluations) × s × (time for one ABM run), so a slow ABM is the binding constraint.

    Why rescale the data?

    If a series fluctuates by hundreds of units, a frequency of order 1 makes the cosine spin through many cycles, its average is close to zero for every θ, and the feature carries almost no signal. If the series fluctuates by thousandths, the cosine barely moves. Dividing each series by a constant chosen in advance is equivalent to changing the variance of the frequency distribution, which the theorem allows. This is practical advice from building this page and is not a recommendation made in the papers.

    Warm-up and window length

    For the time-average estimator, discard an initial stretch of each run so the arbitrary starting state is forgotten. For the window length m, use the Markov order if known. Shalizi (2021) notes that results on estimating joint distributions suggest letting the window grow no faster than log n.

    8Live estimation of the grid epidemic

    This figure runs the whole recipe in your browser. The true parameters generate 300 days of observed data. Five random features (2p + 1 with p = 2) are drawn, each reading a two-day window of both series. A small differential evolution search, 12 candidates improved over 20 generations with s = 3 runs per candidate, looks for the minimizer of Q. The budget is kept small so that it finishes in a few seconds. The papers use s = 10 and a full optimizer run.

    Press Estimate θ to start the search.

      Left. The parameter box. The cross is the truth, which the algorithm never sees. Small circles are the current candidates, the large ring is the best one so far, and filled dots are finished estimates. Top right. The five feature averages for the observed data and for simulations at the best candidate. Bottom right. The observed positive-test series and one simulated series at the best candidate.

      Things worth trying, in order:

      9Uncertainty, model checking, and limits

      Standard errors by parametric bootstrap

      A point estimate needs a measure of uncertainty. Because we can simulate, the parametric bootstrap is the natural tool: generate a fresh data set from the fitted model at θ̂, re-estimate the parameters from it, and repeat. The spread of the re-estimates approximates the sampling variability of θ̂. The Bootstrap button in step 8 does this six times (a real analysis would use hundreds) and reports the standard deviations. Both papers recommend this approach. Wieck-Sosa and Shalizi also state that a separate manuscript establishes asymptotic normality of the estimators, which would justify confidence sets of the familiar "estimate ± 2 standard errors" type.

      Checking the fit with fresh features

      Shalizi (2021) points out a convenient check. Draw additional random features that were not used for fitting. Compute them on the observed data and on many simulations at θ̂. If the observed values fall far in the tails of the simulated ones, the model at its best-fitting parameters still fails to reproduce some aspect of the data. Since the fresh features played no part in the fit, this check does not reuse the data in a circular way.

      What the evidence covers and what it does not

      The numerical experiments in the three sources use time series models: normal and t location families, the logistic map with and without observation noise, a Hénon map, the Lorenz-63 equations, a moving-average process with intractable noise, a state-space model, an SIR differential-equation model observed through binomial testing, and a structural time series with a change-point. Estimates concentrate around the truth and tighten as n grows from 100 to 1,000. None of these experiments is a spatial agent-based simulation. Shalizi (2021) motivates the method with ABMs, citing a spatial-network epidemic model with three free parameters and 630-dimensional data, and the theory covers any simulator whose output can be written as a function of the parameters and a stream of random inputs with fading influence. An ABM that reports aggregate time series fits that description. The grid epidemic on this page is a demonstration, not a validation study.

      Conditions to think about for your own ABM

      A checklist