Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make bandit tests configurable #1236

Merged
merged 10 commits into from
Oct 30, 2024
Merged

Make bandit tests configurable #1236

merged 10 commits into from
Oct 30, 2024

Conversation

tomrf1
Copy link
Member

@tomrf1 tomrf1 commented Oct 23, 2024

Note - epic only for now, support for banner tests will come soon.

Adds an optional methodologies array field to the Test model. If missing or empty, we default to an AB test.
With this change we can now:

  1. configure the epsilon value for epsilon-greedy bandit tests,
  2. configure more than one methodology per epic test, to compare them. E.g. AB test vs epsilon-greedy.

Currently we support ABTest or EpsilonGreedyBandit. For the latter, an epsilon value is required.

If more than one methodology is configured then the the audience is split evenly between the methodologies. Each methodology is tracked separately with a different test name.
E.g. for test name MY_TEST and the following config:

methodologies: [
  { name: 'ABTest' },
  { name: 'EpsilonGreedyBandit', epsilon: 0.5 }
]

The audience is split 50/50 between the two, and the test names become:

  • MY_TEST-ABTest
  • MY_TEST-EpsilonGreedyBandit-0.5

This means they will show up as separate tests in the Tableau dashboard.

Associated changes:

@tomrf1 tomrf1 changed the title Tf epsilon Make bandit tests configurable Oct 23, 2024
@@ -1,6 +1,5 @@
import { EpicTest, EpicVariant } from '../../shared/types';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

previously this file was specific to Epics, but I've made it generic

@@ -126,7 +126,6 @@ export const epicTestFromToolSchema = testSchema.extend({
articlesViewedSettings: articlesViewedSettingsSchema.optional(),
priority: z.number(),
variants: variantSchema.array(),
isBanditTest: z.boolean().optional(),
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are currently no tests using this field, so I'm replacing it with the methodologies field which better models the capabilities

* If controlProportionSettings is set then we use this to define the range of mvt values for the control variant.
* Otherwise we evenly distribute all variants across maxMvt.
*/
export const selectVariant = <V extends Variant, T extends Test<V>>(test: T, mvtId: number): V => {
export const selectVariantUsingMVT = <V extends Variant, T extends Test<V>>(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

banner + header selection is still done using this function (for AB testing only)

@tomrf1 tomrf1 marked this pull request as ready for review October 24, 2024 09:04
@tomrf1 tomrf1 requested a review from a team as a code owner October 24, 2024 09:04
};
}
} else if (test.methodologies) {
// More than one methodology, pick one of them using the mvt value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this know to spilt it 50/50?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getRandomNumber function returns a value based on the user's mvtId.
The % test.methodologies.length part divides all values between the methodologies. So if there are 2 methodologies then they'll be split 50/50.
This is similar to the logic in selectWithSeed elsewhere in this file.

} else {
// No configured methodology, default to AB test
const methodology: Methodology = { name: 'ABTest' };
const variant = selectVariantWithMethodology<V, T>(test, mvtId, banditData, methodology);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could call selectVariantUsingMVT instead? Had to double check but don't think specifying 'ABTest' is doing anything here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point!

name: z.literal('EpsilonGreedyBandit'),
epsilon: z.number(),
});
const methodologySchema = z.discriminatedUnion('name', [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

Copy link
Contributor

@andrewHEguardian andrewHEguardian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Exciting 🤠

@tomrf1 tomrf1 merged commit 408d71c into main Oct 30, 2024
4 checks passed
@tomrf1 tomrf1 deleted the tf-epsilon branch October 30, 2024 08:27

const addMethodologyToTestName = (testName: string, methodology: Methodology): string => {
if (methodology.name === 'EpsilonGreedyBandit') {
return `${testName}_EpsilonGreedyBandit-${methodology.epsilon}`;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realised a flaw in cases where this is used (i.e. where we have more than 1 methodology).
In banditData.ts we don't currently append the methodology to the test name when looking up data for a given test.
This isn't currently an issue because nothing is using bandit tests yet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants