The AI (artificial intelligence, data science & machine learning) team here at Iterable strives to deliver high-quality, updated machine learning models to our customers. However, even if weโve made a great model, how can we decide before deployment that this model is good enough to deploy? How can we avoid deploying โbadโ models (models which donโt reflect our customersโ data well or have mistakes or biases in their design)? How can we automate such testing to fit within our CI/CD framework?
In this article, I will outline the types of models used by our team and the challenges in testing them, followed by a description of our end-to-end โsynthetic dataโ testing solution for Send Time Optimization, one of our teamโs products.
Unsupervised Machine Learning
Why Use Unsupervised ML?
The types of machine learning models we use are entirely motivated by the types of data available to us. The vast majority of Iterableโs data does not contain a โground truthโ labelโfor example, is there a โground truthโ best time to send an email to a given customer, and even if there is, how could we identify that โground truthโ and validate the โground truthโ label for accuracy? This means that supervised ML methods canโt be applied here, as we cannot define a loss function to optimize. Instead, we must use unsupervised ML algorithms to extract insights from our vast quantities of data.
Measuring Performance of Unsupervised ML Models
The AI team monitors the performance of our production models โin the wildโ through key performance indicators (KPIs) such as open rate lift (please download โThe Growth Marketerโs Guide to Email Metricsโ for more information about these metrics!). Although KPIs are a great tool, the goal for this project is to identify problems before the model makes it into production, instead of afterwards. Therefore, Iโll focus on tests I can perform immediately after training, not tests in production.
One of the challenges in working with unsupervised models is evaluating their performance โ since you donโt have a โground truthโ for comparison, itโs not always obvious how to judge your modelโs predictions or results. For example, one of the classic data science projects for exploring NLP (natural language processing) is topic modeling on the New York Times articles dataset.
Most data scientists can easily produce a model which can output lists of words describing various โtopicsโ within the dataset. Itโs much more challenging, however, to determine if those topics reflect the data well; often the scientist will simply read the topics and decide if the topics match some internal expectations they have about what the โcorrectโ topics should be โ not a very reproducible or quantifiable test! In addition, the โhuman eyeballsโ test is extremely susceptible to biases (the scientist might overlook clusters they canโt interpret clearly, or they might ignore or discredit clusters from topics outside of their experience).
For the AI team, however, such โeyeballโ tests arenโt really possible โ I cannot feasibly review millions of email opens by myself and personally determine if our models match my expectations.
Itโs pretty easy to rule out the โeyeball testโ, but what options do we have left? Letโs consider clustering algorithms as an example. We can evaluate the within-cluster sum-of-squares (WCSS) to determine the โspreadโ or inertia of our clusters; however, many clustering algorithms minimize this value by design, and our baseline for comparison would be the WCSS from previous models (not great if both models have the same biases!).
Since we donโt have any โground truthโ labels, we canโt use many of the traditional tests of cluster quality, such as homogeneity (whether all data points in a cluster have the same โground truthโ label) or completeness (whether all data points with the same โground truthโ label belong to the same cluster).
Synthesizing Data With Labels
Bootstrapping in ML
Our approach to handling this problem is to synthesize labeled data via bootstrapping. Bootstrapping is a catch-all term referring to tests or metrics which use random sampling with replacement. A popular ML use case for bootstrapping is โbaggingโ (i.e. โbootstrap aggregatingโ), a meta-algorithm most commonly used with decision forest models to improve their performance. Bagging creates a unique sample (a โbootstrap sampleโ) for each decision tree in the forest by randomly sampling the original dataset with replacement. Because a bagged random forest averages the results of multiple classifiers, this results in lower variance.
For our purposes, however, weโll use bootstrapping to select data from known distributions or distributions designed by hand, labeling the points based on their source distribution.
What is Send Time Optimization?
In this example, I will focus on testing our Send Time Optimization (STO) product. For email blast campaigns, STO experiments attempt to maximize the email open rate by reviewing recipientsโ historical engagement behavior (email opens). The message is sent to each recipient at the hour theyโre most likely to open it (based on their previous opens). Therefore, the โground truthโ that weโre creating in our synthetic data is each recipientโs preferred time to open emails.
Bootstrapping for Sample Synthesis
Letโs say we want to create a sample of synthetic email open data where all customers are either โmorning peopleโ (i.e. their favorite time to open emails is a normal distribution centered around 9AM) or โnight peopleโ (same thing but centered around 9pm).
- To create synthetic data for a single customer, weโll first randomly choose this user to be either a morning person or a night person. We will also choose n_user_emails, the number of unique email opens per user (chosen from a normal distribution centered on a reasonable value).
- To synthesize a userโs email opens, we randomly sample from their โsource distributionโ, either the morning-centered or night-centered normal distribution, repeating this sampling n_user_emails times to generate n_user_emails opens.
- Repeat this sampling procedure for as many users as desired and save the resulting table of synthetic customer email open with day/night labels to a Delta table.

At this point, we have officially created our labeled data!
Evaluating Performance Using Synthetic Samples
Now letโs say that somebody on the AI team has made changes to the STO model and would like to confirm that the updated model performs well as part of CI/CD testing.
- When the model change is ready to merge and deploy, our CI/CD tools train a STO model reflecting the change using a recent set of synthetic data.
- Next, send a set of synthetic data (either the same as used for training, or a separate testing set) through the model API.
- The model assigns each user to a โresult distributionโ which should reflect that userโs open behavior, and the API samples that distribution to return the โbestโ open time for that particular user.
- Repeat this sampling multiple times for each user, then perform a goodness-of-fit test to determine the likelihood that these samples came from a distribution matching the userโs โsource distributionโ (or a very similar-looking distribution).
- If the result and source distributions have a similar shape, then the samples from the API should pass a goodness-of-fit test (such as an Anderson-Darling test) when compared to the source distribution.
- On the other hand, we might find that the results from the API were unlikely to come from a distribution matching the source (low goodness-of-fit); this could indicate that thereโs an issue with our model or with the API.

If the modelโs performance meets an acceptable threshold that we define, the developer can choose to go through with deploying the model to users. Otherwise, this indicates that thereโs some errors in the model and the developer should try to correct any mistakes.
Although I described a very simple testing case here (morning vs. night), this framework can be expanded to include more complex test scenarios.
Next Steps
If youโve made it this far, thanks for reading! In this post, I summarized the reasons for synthesizing data for testing unsupervised ML models. I also gave a simple example of how you could use this test to gauge model performance in a CI/CD system.
This โend-to-endโ test is an example of model testing, testing which confirms that the model follows certain expected behaviors. Adding our end-to-end test is one of several types of testing used by the AI team to ensure a high quality product. Please look for future posts from AI on ML testing and technical debt reduction; this is an active area of development for our team, and we look forward to sharing our progress with you!
