Проведение мультивариантного (Multivariate) тестирования на сайте
Multivariate тестирование (MVT) позволяет одновременно проверить несколько изменений на странице и выявить наиболее эффективную комбинацию. В отличие от A/B теста, MVT определяет взаимодействие между элементами.
A/B vs Multivariate
| Критерий | A/B тест | MVT |
|---|---|---|
| Изменений | 1 (2 варианта) | 2+ элемента × N вариантов |
| Объём трафика | Меньше | Значительно больше |
| Скорость | Быстрее | Медленнее |
| Взаимодействие элементов | Не определяет | Определяет |
| Цель | Один победитель | Лучшая комбинация |
MVT нужен когда: изменения взаимозависимы, трафика достаточно, нужно понять взаимодействие заголовок + CTA + изображение.
Планирование MVT эксперимента
Пример: тестировать на странице товара
- Заголовок: 2 варианта (A, B)
- Изображение: 3 варианта (A, B, C)
- CTA кнопка: 2 варианта (A, B)
Итого: 2 × 3 × 2 = 12 комбинаций. Каждая комбинация — отдельный вариант.
Расчёт требуемого трафика
def mvt_sample_size(n_combinations, baseline_cr, mde=0.05, alpha=0.05, power=0.8):
"""Каждая комбинация требует столько же трафика, сколько AB тест"""
from scipy import stats
import math
p1 = baseline_cr
p2 = baseline_cr * (1 + mde)
p_avg = (p1 + p2) / 2
z_a = stats.norm.ppf(1 - alpha / 2)
z_b = stats.norm.ppf(power)
n_per_combo = ((z_a * math.sqrt(2 * p_avg * (1-p_avg)) +
z_b * math.sqrt(p1*(1-p1) + p2*(1-p2))) / (p2-p1)) ** 2
total = n_per_combo * n_combinations
print(f"Per combination: {math.ceil(n_per_combo):,}")
print(f"Total needed: {math.ceil(total):,}")
print(f"At 1000 daily visitors: {math.ceil(total/1000)} days")
mvt_sample_size(n_combinations=12, baseline_cr=0.04, mde=0.15)
# Per combination: 4,519
# Total needed: 54,228
# At 1000 daily visitors: 55 days
Если трафика недостаточно для полного MVT — использовать fractional factorial design (тестировать подмножество комбинаций).
Реализация через Optimizely
// Optimizely Snippet (добавить в <head>)
<script src="https://cdn.optimizely.com/js/PROJECT_ID.js"></script>
// Программный вариант
const optimizely = window.optimizely || []
// Получить вариацию для конкретного эксперимента
const variationKey = optimizely.get('state').getVariationMap()['mvt_homepage_elements']
// variationKey = "headline_B_image_C_cta_A"
// Реализация без Optimizely
function getMVTVariant(userId, elements) {
const variants = {}
for (const [element, options] of Object.entries(elements)) {
const hash = cyrb53(`${userId}_${element}`)
variants[element] = options[hash % options.length]
}
return variants
}
const elements = {
headline: ['Купите сегодня', 'Скидка 20% для новых клиентов'],
image: ['lifestyle', 'product-white', 'product-action'],
cta: ['Добавить в корзину', 'Купить сейчас'],
}
const variants = getMVTVariant(userId, elements)
// variants = { headline: 'Купите сегодня', image: 'product-action', cta: 'Купить сейчас' }
// Применить варианты к DOM
applyVariants(variants)
// Зафиксировать в аналитике
gtag('event', 'mvt_assignment', {
experiment: 'product_page_mvt',
headline: variants.headline,
image: variants.image,
cta: variants.cta,
combination: Object.values(variants).join('_')
})
Анализ результатов MVT
import pandas as pd
from scipy import stats
def analyze_mvt(data):
"""data: DataFrame с колонками combination, visitors, conversions"""
data['cvr'] = data['conversions'] / data['visitors']
data = data.sort_values('cvr', ascending=False)
# Найти лучшую комбинацию
best = data.iloc[0]
control = data[data['combination'] == 'baseline'].iloc[0]
print(f"\nTop combinations:")
print(data.head(5).to_string())
# Статистическая значимость лучшей vs контроль
from scipy.stats import proportions_ztest
_, p_value = proportions_ztest(
[best['conversions'], control['conversions']],
[best['visitors'], control['visitors']]
)
print(f"\nBest: {best['combination']} CVR={best['cvr']:.2%}")
print(f"Control: CVR={control['cvr']:.2%}")
print(f"P-value: {p_value:.4f}")
# Анализ главных эффектов (main effects)
# Насколько каждый элемент в отдельности влияет на конверсию
for element in ['headline', 'image', 'cta']:
effect = data.groupby(element)['cvr'].mean()
print(f"\nMain effect of {element}:")
print(effect.sort_values(ascending=False))
Fractional Factorial Design
Если нельзя тестировать все 12 комбинаций:
# Использовать Latin Square или Taguchi метод
# Тестировать 4 комбинации вместо 12, покрывая взаимодействия
combinations_to_test = [
{'headline': 'A', 'image': 'A', 'cta': 'A'}, # контроль
{'headline': 'A', 'image': 'B', 'cta': 'B'},
{'headline': 'B', 'image': 'A', 'cta': 'B'},
{'headline': 'B', 'image': 'B', 'cta': 'A'},
]
# Уменьшает трафик в 3 раза, но теряет часть взаимодействий
Срок выполнения
Планирование и реализация MVT с анализом главных эффектов — 5–7 рабочих дней.







