Към съдържанието
wannacode

A/B тест

Накратко: A/B тестът сравнява два варианта върху случайно разделени посетители и проверява дали разликата в конверсията е истинска, или е шум.

Проблем

„Новата кошница по-добра ли е?“

Екипът направи нова страница на кошницата: по-кратка, с по-малко полета. Не знаем дали е по-добра. Затова две седмици всяко посещение на сайта на случаен принцип вижда или старата (old), или новата (new) кошница. Колоната ordered е 1, ако посещението завършва с поръчка:

Pythonданни: таблиците на магазина

Това е A/B тест: две версии, случайно разделени посетители, една мярка. Мярката тук е конверсия: делът на посещенията, които завършват с поръчка. Старата кошница има 3,10%, новата 3,72%.

Разликата е 0,62 процентни пункта: разлика между два процента. Това е около една пета повече поръчки. Но дали не е шум?

Идеята

Шум ли е разликата?

Това е въпросът от урока за хипотезите. Нулевата хипотеза: кошницата няма значение. Ако е вярна, етикетите old и new са без значение и можеш да ги разбъркаш. Колко често разбърканите данни дават разлика поне 0,62 пункта?

Pythonданни: таблиците на магазина

В 2 000 разбърквания най-голямата разлика е 0,76 пункта, но само 6 пъти тя е поне колкото истинската. p е 0,003. Разлика като тази рядко идва от шума.

По-точно, за любопитните

ordered е 0 или 1, затова средната на колоната е точно делът на поръчките. Разбъркването тук е с цикъл: таблицата има 28 176 реда и 2 000 разбърквания наведнъж в една матрица биха заели много памет в браузъра.

Пробвай

На всяко устройство ли?

Подобрението на телефон ли идва, или на компютър? Запиши в rates конверсията в проценти за всяко устройство (редове) и вариант (колони), а в lift разликата new − old за всяко устройство в пунктове.

Pythonданни: таблиците на магазина

Идеята

По-бързият път: chi2_contingency

За два дяла има готова проверка. Първо pd.crosstab брои двойките: колко посещения от всеки вариант са с поръчка и без. После scipy.stats.chi2_contingency казва колко рядко е такава таблица, ако вариантът няма значение:

Pythonданни: таблиците на магазина

p е 0,0046, около 0,005. Разбъркването даде 0,003: двата пътя казват едно и също. Малката разлика е, защото 2 000 разбърквания мерят p грубо (6 случая), а chi2_contingency при таблица 2 × 2 прави малка поправка, която леко вдига p.

Идеята

Колко е подобрението?

p казва само „едва ли е шум“. Управителят пита друго: с колко е по-добра новата кошница? За това ти трябва интервал. Както в урока за интервалите, теглиш с връщане нови извадки от всяка група и гледаш как се мени разликата:

Pythonданни: таблиците на магазина

Подобрението е 0,62 пункта, а 95% интервал е от 0,21 до 1,04 пункта. Нулата е извън интервала: това е същото „едва ли е шум“. Но интервалът казва и колко: може да е малко над 0,2, може да е над 1 пункт.

По-точно, за любопитните

Тук повторенията са 2 000, а не 10 000, за да върви бързо: всяко тегли по 14 000 реда. По формулата интервалът на разлика между два дяла е разликата ± 1,96 × √(p₁(1 − p₁)/n₁ + p₂(1 − p₂)/n₂). Дава почти същото:

Pythonданни: таблиците на магазина

Идеята

Колко посещения ти трябват

Колко дълго да върви тестът? Решаваш го преди да започнеш, от две числа: конверсията досега (3,1%) и най-малкото подобрение, което има смисъл за теб (0,6 пункта). Има правило на палеца за 80% шанс да видиш подобрението при праг 0,05:

посещения на група ≈ 16 × p × (1 − p) / подобрение²

Pythonданни: таблиците на магазина

На група трябват 13 351 посещения, общо 26 701. Шансът тестът да хване истинско подобрение се казва мощност (power). Можеш да го провериш със симулация: измисляш 2 000 теста с конверсия 3,1% и 3,7% и броиш колко пъти p излиза под 0,05. rng.binomial(n, 0.031) дава колко поръчки идват от n посещения, всяко с шанс 3,1%:

Pythonданни: таблиците на магазина

С 2 000 посещения на група тестът хваща подобрението само в 18% от случаите, с 5 000 в 37%. С 13 351 е 78%, близо до 80%-те от правилото. Малкият тест не казва „няма разлика“: той не вижда.

По-точно, за любопитните

p_value е проверката на два дяла по формула (z-тест). Тя работи върху цели масиви наведнъж, затова 2 000 теста отнемат миг. За таблица 2 × 2 дава почти същото като chi2_contingency. Числото 16 в правилото идва от прага 0,05 и мощност 80%: (1,96 + 0,84)² × 2 ≈ 16.

Пробвай

По-голямо подобрение

Продуктовият екип казва: „Интересува ни само подобрение от поне 1 пункт.“ Колко посещения на група трябват по правилото? Запиши ги в per_group като цяло число.

Pythonданни: таблиците на магазина

Идеята

Не надничай преди края

Изкушението е да гледаш резултата всеки ден. Ето p, сметнато от всички посещения до съответния ден:

Pythonданни: таблиците на магазина

На третия ден p е 0,053, на четвъртия 0,077, на петия 0,041. Ако беше спрял на петия ден, щеше да обявиш победа. Тук новата кошница наистина е по-добра, но това се вижда от целия тест. Самото правило „спирам, щом p падне под 0,05“ е грешката.

Защо? Провери го с A/A тест: двете групи виждат едно и също, и разлика няма. Симулираме 1 000 такива теста по 14 дни и гледаме p всеки ден:

Pythonданни: таблиците на магазина

Ако гледаш само в края, фалшивите „победи“ са 4,9%, колкото обещава прагът 0,05. Ако гледаш всеки ден и спираш при първото p под 0,05, те са 21,7%: четири пъти повече. Шумът има 14 шанса да слезе под линията.

1. Тестът е планиран за 14 дни. На петия ден p е 0,041. Колегата казва: „Под 0,05 е, спираме и пускаме новата кошница.“ Какво не е наред?

Идеята

Много метрики, много сегменти

Новата кошница дава повече поръчки. А по-големи ли са те? Сравни сумата на поръчка:

Pythonданни: таблиците на магазина

26,30 € при новата и 26,71 € при старата, p = 0,73. Няма доказателство, че кошницата мени сумата. Това не е „доказахме, че са равни“: малка разлика може да има, но този тест не я вижда.

Сега си представи отчет с 20 метрики: поръчки, сума, връщания, време на страницата… Всяка метрика без истинска разлика има 5% шанс да излезе с p под 0,05. Колко често поне една „печели“?

Pythonданни: таблиците на магазина

Една метрика „печели“ в 5,1% от случаите, както се очаква. Но поне една от 20 „печели“ в 64,1% от тестовете. Същото е с сегментите: телефон, компютър, нови клиенти, всеки ден от седмицата. Затова главната метрика се избира преди теста. Случайна „победа“ в 20-тата метрика е идея за следващ тест, не извод.

Идеята

Защо тестът казва „причинява“

Защо вярваш, че кошницата причинява повече поръчки, а не само върви с тях? Защото вариантът е даден на случаен принцип. Случайността изравнява всичко, което не мериш. Ето устройствата в двете групи:

Pythonданни: таблиците на магазина

И в двете групи компютрите са 35%, а телефоните 65%. Същото важи за часа, деня, навиците на хората: групите се различават само по кошницата. Затова разликата в поръчките идва от нея.

Когато данните не са от тест, това не е така. В следващия урок един банер изглежда, че вдига поръчките, а на всяко устройство поотделно не ги вдига.

Упражнение

Доклад за управителя

Управителят пита: „Носи ли новата кошница повече пари на посещение?“ Запиши в per_visit средния оборот на посещение за всеки вариант (всички посещения, и тези без поръчка), а в p p-стойността на сравнението с scipy.stats.ttest_ind.

Pythonданни: таблиците на магазина

Ако го планираше отначало: колко дни трябваше да върви тестът? Посещенията на ден са средно len(visits) / 14. Запиши в per_group посещенията на група по правилото (подобрение 0,6 пункта при 3,1%), в per_day посещенията на ден, а в days дните, закръглени нагоре.

Pythonданни: таблиците на магазина

Тест

Провери се

1. Проверката на новата кошница дава p = 0,005. Какво значи това?
2. Искаш да видиш подобрение от 0,3 пункта вместо 0,6. Колко посещения ти трябват?
3. Отчетът следи 20 метрики. Една от тях е с p = 0,04, останалите не. Какво казваш?
4. Средната поръчка е 26,30 € при новата кошница и 26,71 € при старата, p = 0,73. Кой извод е верен?
5. Защо при A/B теста можеш да кажеш „новата кошница води до повече поръчки“, а не само „двете вървят заедно“?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·