Въведение

Веднъж на всеки няколко дни Starbucks изпраща оферта до потребителите на мобилното приложение. Офертата може да бъде само реклама за напитка или реална оферта, например отстъпка или BOGO (купете едно, вземете едно безплатно) или просто информационна оферта, която включва информация за продукта. Някои потребители може да не получават оферти през определени седмици. По тази линия Starbucks най-вероятно може да изгради възможността клиентът да отвори офертата, след като я получи, и неизбежно да завърши транзакцията. Освен това ще помогне за подобряване на лоялността на клиентите, като им напомня за най-новата информация за продукта. Но въпросът тук е как да изпратите офертата по по-интелигентен начин, което означава как да увеличите максимално възможността клиентът да отвори офертата и да завърши транзакциите. Затова ще се опитаме да разбием набора от данни за историята на Starbucks, за да проверим дали можем да разберем нещо от него.

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

Бизнес контекст

  • Решението тук има за цел да анализира как хората вземат решения за покупка и как тези решения се влияят от промоционални оферти.
  • Всеки индивид в набора от данни има някои скрити атрибути, които влияят на техните модели на покупка и са свързани с техните забележими характеристики. Индивидите създават различни събития, включително приемане на оферти, отваряне на оферти и правене на покупки.
  • Има три вида оферти, които могат да бъдат изпратени: купи едно-получи едно (BOGO), отстъпка и информационни. В оферта на BOGO потребителят трябва да похарчи определена сума, за да получи награда, равна на тази прагова сума. При отстъпка потребителят получава награда, равна на част от изразходваната сума. В информационна оферта няма награда, но няма и необходима сума, която потребителят трябва да похарчи. Офертите могат да се доставят по множество канали.

Цел на проекта

Въз основа на контекста по-горе, този проект ще се опита да зададе въпросите по-долу

  1. Кои са основните характеристики, влияещи върху ефективността на оферта в приложението Starbucks?
  2. Могат ли предоставените данни, а именно характеристиките на офертата и демографията на потребителите, да предскажат дали потребителят ще приеме оферта?

Речник на данни

Данните се съдържат в три файла:

  • portfolio.json — файлът описва характеристиките на всяка оферта, включително нейната продължителност и сумата, която клиентът трябва да похарчи, за да я изпълни (трудност).
  • profile.json — файлът съдържа демографски данни за клиентите, включително тяхната възраст, пол, доход и кога са създали акаунт в мобилното приложение за награди Starbucks.
  • transcript.json — файлът описва покупките на клиенти и кога са получили, прегледали и завършили оферта. Една оферта е успешна само когато клиентът я види и отговаря или надвишава нейната трудност в рамките на продължителността на офертата.

Ето схемата и обяснението на всяка променлива във файловете:

portfolio.json

  • id (низ) — идентификатор на оферта
  • offer_type (низ) — тип оферта, т.е. BOGO, отстъпка, информационна
  • трудност (int) — минимално необходими разходи за изпълнение на оферта
  • награда (int) — награда, дадена за изпълнение на оферта
  • duration (int) — време за отваряне на офертата в дни
  • канали (списък от низове)

profile.json

  • възраст (int) — възраст на клиента
  • Postal_member_on (int) — дата, когато клиентът е създал акаунт в приложението
  • gender (str) — пол на клиента (обърнете внимание, че някои записи съдържат „O“ вместо M или F)
  • id (str) — идентификатор на клиента
  • доход (float) — доход на клиента

transcript.json

  • събитие (str) — описание на запис (т.е. транзакция, получена оферта, прегледана оферта и т.н.)
  • person (str) — идентификатор на клиента
  • време (int) — време в часове от началото на теста. Данните започват в момент t=0
  • стойност — (дикт от низове) — или идентификатор на оферта, или сума на транзакцията в зависимост от записа

Изследване на данни

За да анализираме по-добре проблема в следващите раздели, първо трябва да проучим наборите от данни, което включва проверка на липсващата стойност, визуализиране на разпределението на данните и т.н. По този начин можем да разберем по-добре как изглежда наборът от данни и как можем да представим данните, за да ги направим готови за моделиране.

Както е показано по-горе, няма липсващи стойности в набора от данни за портфолиото. Колоните на каналите изискват да бъдат еднократно кодирани. трябва да преименуваме името на колоната за id на offer_id.

Преглеждайки първите няколко реда от набора от данни, той очевидно показва липсващи стойности в колоната за възраст, която е кодирана като 118, и следователно трябва да:

  • Пуснете редове без данни за пол и доход

Очевидно в редовете, чиято възраст е равна на 118, също липсват пол и доход, което означава, че вероятно е добре просто да изпуснете редовете в следващите стъпки, за да подпомогнете внедряването на модела.

Вижте бързо как изглежда разпределението на доходите и разпределението по възраст в набора от данни.

Графиката на разпределение по възраст изобразява, че средната възраст на клиента е 60 и повечето клиенти принадлежат към възрастовия диапазон между 40 и 70. Графиката на разпределение на доходите показва, че броят на клиентите, чиято средна заплата е под 70 000, е висок от другия считайки 70K за медиана на разпределението на доходите. Графиките също така заключават, че минималният и максималният доход както за мъжете, така и за жените са приблизително еднакви, но броят на мъжете клиенти с ниски доходи е малко по-висок от този на жените клиенти

След това разгледайте бързо набора от данни за преписи.

Почистването и предварителната обработка на преписа може да се извърши по следния начин:

  • Преобразувайте времето в часове във време в дни
  • Обработете колоната със стойност, т.е. отделете я в различна колона въз основа на колона за събитие.
  • Разделете данните за офертите и транзакциите

Тъй като колоните със стойности включват множество информации, които трябва да бъдат извлечени за по-ясен и по-лесен анализ, първо извършваме някои основни манипулации върху набора от данни.

Предварителна обработка на данни

За да идентифицирам основните двигатели на една ефективна оферта, първо трябва да дефинирам какво е „ефективна“ оферта в приложението Starbucks. Също така трябва да обработим данните, за да обединим събитията от всяка изпратена конкретна оферта, за да разберем коя оферта е получена, прегледана и накрая завършена с транзакция.

Всички наши клиенти можем да разделим на 4 основни групи:

  1. Хора, които са повлияни и успешно завършени — ефективни оферти:
- `offer received` -> `offer viewed` -> `transaction` -> `offer completed` (BOGO/discount offers)
— `offer received` -> `offer viewed` -> `transaction` (informational offers — must be within validity period of offer)

2. Хора, които са получили и прегледали оферта, но не са завършили успешно — неефективни оферти:

- `offer received` -> `offer viewed`

3. Хора, които купуват/завършват оферти, независимо дали са запознати с оферти:

- `transaction`
- `offer received` -> `transaction` -> `offer completed` -> `offer viewed`
- `transaction` -> `offer received` -> `offer completed` -> `offer viewed`
- `offer received` -> `transaction` -> `offer viewed` -> `offer completed`
- `offer received` -> `transaction` (informational offers)
- `offer received` -> `transaction` -> `offer viewed` (informational offers)

4. Хора, които са получили оферти, но не са предприели действия:

- `offer received`

Ще трябва да отделя хората в група 2 от хората в група 4, тъй като хората в група 2 може да са прегледали оферта, но не са предприели никакви действия, докато хората в група 4 дори не са имали събитие за преглед на оферта.

Разделянето на хората от група 1 (ефективни оферти) и хората, които купуват/завършват оферти, независимо от осведомеността за оферти (група 3) е особено трудно. За хората в група 3 преобразуването е невалидно (т.е. неуспешно преобразуване от оферта), ако офертата е завършена или транзакцията е извършена преди прегледана оферта. Възможно е също така да има сценарии, при които офертата е завършена, след като офертата е прегледана, но транзакция е извършена преди офертата да бъде прегледана. В този случай офертата може да е изпълнена, но също така не е валидна реализация.

Определяне на целевата променлива ефективна оферта:

Знаем, че клиентите от група 1 ще бъдат нашата целева променлива „effective_offer“ = 1, но има много дефиниции на неефективни оферти за групи 2–4.

И така, какво бихме определили като неефективна оферта? Както вече беше посочено по-горе, група 2 би била в рамките на нашето определение за неефективна оферта; когато потребителят знае за оферта, но офертата е неефективна, тъй като не превръща потребителя в клиент. Така че група 2 може да се дефинира като нашата целева променлива „effective_offer“ = 0.

Какво ще кажете за група 3 и група 4? Група 3 се състои от потребители, които може да са получили оферти, но независимо от това биха закупили. От бизнес гледна точка не бихме искали да им изпращаме оферти.

Междувременно потребителите от група 4 ще се считат за клиенти с нисък приоритет, тъй като те не извършват никакви действия, независимо дали получават оферти или не.

Знаем, че има 4 вида събития: завършена оферта, получена оферта, прегледана оферта и транзакция. Но ние видяхме, че нашите данни показват, че нямаме offer_id, свързан с транзакциите, тъй като те не са записани в данните за събитието на преписа. По този начин първата цел при предварителната обработка на данни е да се дефинира методология за присвояване на offer_ids на конкретни транзакции

Освен това офертите BOGO и отстъпките имат събитие за завършена оферта, когато офертите са завършени. Информационните оферти обаче не свързват това събитие с него.
Така,

Освен това офертите BOGO и отстъпките имат събитие за завършена оферта, когато офертите са завършени. Информационните оферти обаче не свързват това събитие с него.
Така,

1) За BOGO и оферта за отстъпка ефективна оферта е тази, ако следните събития са записани в правилната последователност във времето:

получена оферта -› прегледана оферта -› транзакция -› завършена оферта

2) За информационна оферта, ефективна оферта:

получена оферта -› прегледана оферта -› транзакция

След това, след като съберем данните заедно след присвояване на идентификатори на оферта към транзакции, трябва да извлечем транзакциите, които са били завършени след получаването и прегледа на офертата. Тъй като вече сме попълнили идентификатора на офертата на цялата транзакция, можем да извлечем транзакциите, конвертирани от оферти, като проверим дали идентификаторът на офертата преди транзакцията е същият като идентификатора на офертата на транзакцията.

# join back the 'offer received' events which was filtered out in the previous step
offer_received = transcript_processed[transcript_processed['event']=='offer received']
offer_received['pre_offer_id']=np.nan
offer_received['completed_offer']=np.nan
transcript_processed = offer_received.append(transactions_after_viewed).sort_values(['person','time'])

Накрая, както в горния код, ние присъединяваме обратно получените данни за оферта, за да формираме окончателно обработения набор от данни за препис.

Тъй като различната оферта има различни последици от завършването, например за информационната оферта, няма да има награди. Затова разделяме данните за преписа по тип оферта за по-лесен анализ.

В рамките на всеки тип оферта вече можем успешно да отделим всеки уникален person-offer_id в група 1 от останалите, използвайки нашата колона completed_offer. Тъй като сме маркирали всички събития за реализация (транзакция или събитие за завършена оферта в зависимост от типа на офертата), възникващи след събитие за преглед на оферта, можем да бъдем сигурни, че които и събития за реализация да са маркирани с completed_offer=1, са поне в рамките на първата група (Хора, които са повлиян и успешно конвертиран - ефективни оферти).

За BOGO и оферти за отстъпка, ние ще считаме само завършени събития на оферти като събития за реализация, докато можем да считаме събитие за транзакция като събитие за реализация за информационните оферти.

Сега можем да разгледаме отделянето на group 2 и group 4 уникални person-offer_ids за BOGO и оферти с отстъпка. Така че ще отделим клиентите, които са прегледали само офертите без транзакция и завършване в края, и клиентите, които са получили само офертата, без да я видят.

def not_converted(df):
#subset offer ids that have transactions or conversions by person and offer_id
    conversion_ids=df[['person','offer_id']][(df['event']=='transaction') | (df['event']=='offer completed') ].groupby(['person','offer_id']).count().reset_index()
#check for unique person-offer_id pairs that consist of offers received 
    offers_received_only=df[['person','offer_id']][df['event']=='offer received'].groupby(['person','offer_id']).count().reset_index()
#create merged dataset to diffrentiate groups
    check_merge=conversion_ids.merge(offers_received_only,how='right',on=['person','offer_id'],indicator=True)
    return check_merge
#check how many are in either group
check_merge_bogo=not_converted(bogo)
print('For BOGO offers:')
print(check_merge_bogo.groupby(['_merge']).count())
check_merge_discount=not_converted(discount)
print('For Discount offers:')
print(check_merge_discount.groupby(['_merge']).count())

Има голям брой уникални двойки person-offer_id, които имат получени събития за оферта, но нямат събития за реализация. Те ще се считат за оферти в група 2 и 4 в рамките на всеки тип оферта.

След това, въз основа на обединения набор от данни по-горе, можем да отделим клиентите, които са прегледали офертата само след като са я получили, и клиентите, които дори не са отворили офертата, след като са я получили.

grpgroup 24_bogo = check_merge_bogo[check_merge_bogo['_merge'] == 'right_only']
grpgroup 24_bogo  = grpgroup 24_bogo.merge(transcript_processed,how='left',on=['person','offer_id'])
grpgroup 2bogo = grpgroup 24_bogo[['person','offer_id']][grpgroup 24_bogo['event'] == 'offer viewed'].groupby(['person','offer_id']).count().reset_index()
grpgroup 24_bogo.drop(['_merge'], axis=1, inplace=True)
grp_4_bogo=grpgroup 24_bogo.merge(grpgroup 2bogo[['person','offer_id']],how='left',indicator=True)
grp_4_bogo=grp_4_bogo[grp_4_bogo['_merge']=='left_only'].copy()

За тези стъпки ще направи една и съща манипулация както за BOGO, така и за офертата за отстъпка.

Хората от група 3 са всички в преобразуваните идентификационни номера, които нямат предишна прегледана оферта — следователно, те биха били хора с транзакция и offer_completed събития, но без предишно събитие, прегледана на оферта. За BOGO и оферти за отстъпки, те ще бъдат хора със завършени събития с оферта, които имат completed_offer != 1.

# subset the offer which has no correction with offer
grp3_bogo = bogo[['person','offer_id']][(bogo['event']=='offer completed') & (bogo['completed_offer']!=1)].groupby(['person','offer_id']).count().reset_index()
grp3_discount = discount[['person','offer_id']][(discount['event']=='offer completed') & (discount['completed_offer']!=1)].groupby(['person','offer_id']).count().reset_index()

След това трябва да разгледаме ефективните и неефективните оферти в зависимост от типа на групата. Както вече беше разработено по-горе, всеки уникален person-offer_id, принадлежащ към група 1, може да се разглежда в нашата целева променлива ефективна_оферта=1 група. Междувременно група 2 е в нашата целева променлива, ефективна_оферта=0 група.

Сега успешно подготвихме целевите променливи за нашите набори от данни за BOGO и отстъпки.

Що се отнася до информационната оферта, офертата може да се счита за отговорена само при действието на офертата, когато транзакцията приключи в рамките на срока на офертата. Можете да проверите цялата логика в бележника на python тук.

Сега, след като сме подгрупирали всички наши набори от данни в ефективни и неефективни оферти в зависимост от типа на офертата, можем да добавим наборите от данни съответно в набори от данни за моделиране.

Инженеринг на функциите

След основна обработка, следващата стъпка трябва да разгледаме функциите и да видим как да бъдем креативни в създаването на нови функции.

  • Колоната Postal_member_on беше във формат на дата. Следователно, за да извлечем смислени прозрения от тази функция, можем да я преобразуваме като характеристика, указваща мандат на членство. Това може да има някакъв ефект върху прогнозирането дали клиентът ще приеме дадена оферта или не

  • Като част от допълнително проучване на данни открих, че може да има множество оферти, получени на човек. Броят пъти, когато всяка оферта е получена от клиента, също може да има ефект върху това дали офертите са ефективни или не.
#get count of offers received per person, put into separate dataset
df_offer_received_cnt=transcript_processed[transcript_processed['event']=='offer received'].groupby(['person','offer_id','time']).count()['event'].reset_index()
#rename columns
df_offer_received_cnt.rename(columns={'event':'offer_received_cnt'},inplace=True)
#drop unnecessary columns
df_offer_received_cnt.drop(['time'], axis=1, inplace=True)
#ensure only unique person-offer_id pairs
df_offer_received_cnt=df_offer_received_cnt.groupby(['person','offer_id']).sum().reset_index()

  • извадете транзакциите, които не са свързани с офертата
#filter dataset by invalid transactions
# subtract the transactions which's not related to the offer
transactions_not_related=transcript_processed[(transcript_processed['event']=='transaction') & (transcript_processed['completed_offer']==0)].groupby(['person','offer_id'])['amount'].sum().reset_index()
transactions_not_related.rename(columns={'amount':'amount_invalid'},inplace=True)
  • Обединете временните данни, създадени по-горе, след това изпуснете липсващите стойности в колоната за пол и създайте фиктивни променливи за колоната за пол и разделете колоната на канала към категориалната променлива.
# merge to get offers received count and invalid amount transacted
offers_bogo=offers_bogo.merge(df_offer_received_cnt[['person','offer_id','offer_received_cnt']],how='left',on=['person','offer_id'])
offers_bogo=offers_bogo.merge(transactions_not_related[['person','offer_id','amount_invalid']],how='left',on=['person','offer_id'])
# fill missing values for amount_invalid with 0
offers_bogo['amount_invalid']=offers_bogo['amount_invalid'].fillna(value=0)
offers_bogo.dropna(inplace=True)

Модел на сградата

След предварителната обработка на данните, следващата стъпка ще започнем да прилагаме модели, за да разберем кои фактори влияят най-много върху това дали клиентът ще отговори на офертата или не. И този проект също се опитва да предвиди дали клиентът ще отговори на различните видове оферти или не.

Тъй като имаме 3 вида оферти, следователно има 3 различни модела, които трябва да бъдат изградени. Това на практика е модел на контролирано обучение с бинарна класификация.

Реших да сравня ефективността на прост модел на класификатор на дърво на решенията като базов модел с модел на класификатор на произволна гора в ансамбъл. Причината, поради която избрахме дървовидни модели, защото искаме и интерпретируемост на модела. И този проект също се опитва да предвиди дали клиентът ще отговори на различните видове оферти или не.

Междувременно избрах и произволна гора като алтернативен модел за сравнение на базовия модел. Random Forest е ансамбъл пакет от дървета на решенията, които целят висока точност при обучението на модела.

Подготовка за внедряване на модел

  • Подгответе набора от дати, задайте променливите функции и целевите колони

  • Разделете данните на набори за обучение и тестове

  • Създайте функция за изпълнение на модела за различни типове оферти

Инициирайте базовата линия на модела

На този етап първо ще използваме параметри по подразбиране за базовия модел и ще настроим параметрите в следващите стъпки за настройка, ако е необходимо.

  • Модел BOGO

Както е показано по-горе, точността и на двата модела е добра за първоначалното имплементиране на модела. Но резултатът от F1 е малко по-нисък от 80%, което може да бъде настроено по-добре в по-късните стъпки.

Въпреки това, по отношение на резултата F1, и двата модела са под 80%, като моделът Random Forest се представя по-добре в сравнение с Decision Tree Classifier. Резултатите показват, че RF моделът се справя малко по-добре в сравнение с DT, като не класифицира погрешно негативните събития като положителни (което означава, че неправилно класифицира хората, за които офертите са неефективни, като хора, за които офертите биха били ефективни).

Нашият модел прогнозира положителния случай (т.е. когато офертата е ефективна) по-точно в сравнение с прогнозирането на отрицателните случаи (т.е. когато офертата е неефективна), което се очаква предвид неравномерните класове. Може би не сме толкова загрижени за тези погрешни класификации, тъй като нямаме нищо против да изпращаме на хората повече оферти, отколкото биха искали; бихме предпочели да не пропуснем никой, за когото офертата би била ефективна.

Следователно тук все още можете да изберете произволната гора с малко по-добра точност в момента.

  • Модел с оферта за отстъпка

Както е показано по-горе, произволната гора се представя малко по-добре от дървото на решенията.

  • Модел на информационна оферта

Една потенциална причина за по-лошото представяне може би се дължи на факта, че имах ключовото предположение да присвоя събитията на реализация като транзакции, които се случват само след като оферта бъде прегледана и в рамките на определената продължителност; Може да съм пропуснал някаква ценна информация, като премахна тези транзакции, които се случват независимо. Можем да видим това от това как общият примерен набор от данни е по-малък (около половината) от наборите от данни за другите 2 оферти, само с около 5K проби в сравнение с около 10K съответно за BOGO и отстъпка.

Настройка на модела

Този раздел ще се опита да настрои параметрите на първоначалния модел, за да постигне по-висока производителност. В секцията за настройка първо ще използваме GridSearch за търсене на параметри, които е вероятно да получат по-добра производителност на модела, преди да експериментираме с премахване или добавяне на функции за подобряване на производителността на модела.

  • Модел Оферта BOGO

Използвайте оптимизирани параметри, за да стартирате повторно модела в предишните стъпки.

Сравнете резултатите с предишния първоначален модел.

Както е показано по-горе в сравнението, след използване на параметри за настройка, точността на теста леко се подобри от 82,8316% на 82,8723%, а резултатът F1 се увеличи от 76,70% на 77,57%.

Направете същите стъпки за данните за офертата за отстъпка.

Както е показано по-горе в сравнението, след използване на параметри за настройка, точността на модела се повиши леко от 87,07% на 87,39%, а резултатът F1 се подобри от 81,71% на 82,08%.

И за информационната оферта направете същата стъпка.

Както е показано по-горе в сравнението, след използване на параметри за настройка, точността на теста леко се подобри от 74,87% на 75,23% и леко намаление на F1 резултата от 68,23% на 67,14%.

И накрая, исках да опитам и да видя дали премахването на променливата сума_инвалид, която бяхме отбелязали като рядка, следователно може да не е полезна при прогнозиране на ефективността на офертите, ще помогне. Премахнах функцията от моята подготовка за данни и преквалифицирах модела, използвайки същите оптимални параметри, намерени чрез GridSearch, с DT модела като базова линия. Резултатите, които получихме обаче, не подобриха точността на модела с много добра сума и затова избрахме настроения модел като наш окончателен приемлив модел.

Вижте важността на функцията

След това ще разгледаме резултата от модела и ще видим дали има някаква представа за основните фактори, които решават дали клиентите ще отговорят на оферти, които можем да получим чрез проучване на важността на функциите.

Показване на важността на функцията въз основа на модела, който имаме.

Както е показано по-горе, можем да видим, че и за трите типа оферти, най-важният фактор, който до голяма степен влияе дали на офертата ще бъде отговорено в крайна сметка, е продължителността на членството. Тоест, колкото по-дълго клиентът е член на Starbucks, толкова по-вероятно е той да отговори на офертата, която получават. Тогава вторият и третият важни фактори, които влияят върху възможността за реакция на клиента, са възрастта и доходите, които имат много смисъл. Освен това броят на офертите, които са получили, също ще повлияе много на отговора.

Заключение и следващи стъпки

Заключение

Като цяло намирам този проект за предизвикателство, главно поради структурата на данните в набора от данни „транскрипт“. Започнах с 2 бизнес въпроса:

1. Кои са основните характеристики, влияещи върху ефективността на дадена оферта в приложението Starbucks?
2. Могат ли предоставените данни, а именно характеристиките на офертата и потребителските демографски данни, да предскажат дали потребителят ще приеме оферта?

а. Отражение:

и. Констатации по въпрос 1:
За въпрос 1 важността на характеристиките, дадена от всичките 3 модела, е, че мандатът на член е най-големият предсказател за ефективността на дадено предложение.

И за трите модела първите 3 променливи бяха едни и същи — продължителност на членството, доход и възраст. Въпреки това доходът и възрастта променят поръчките в зависимост от типа на офертата.

За офертите BOGO и отстъпка разпределението на важността на характеристиките е относително равно. При информационните оферти обаче разпределението е малко по-балансирано, като доходът е втората най-важна променлива.

ii. Констатации по въпрос 2:

Решението ми да използвам 3 отделни модела за прогнозиране на ефективността на всеки тип оферта завърши с добра точност за моделите BOGO и отстъпка (82,87% за BOGO и 87,38% за отстъпка), докато малко по-точна ефективност за информационните оферти (75,23%) . Въпреки това бих считал 75% за приемливо в бизнес среда, тъй като за информационните оферти няма разходи за информиране на потребителите за даден продукт.

Междувременно за моделите BOGO и отстъпките съм доста доволен от точността от 80% и повече, тъй като в бизнес среда, която би била приемлива за показване на оферти на хората, дори ако моделът неправилно класифицира няколко, общото увеличение на приходите може да оправдае малко грешки.

б. Основни предизвикателства и потенциално подобрение:

Когато анализирам и изграждам моделите за машинно обучение, за да отговоря на горните въпроси, моите основни предизвикателства и констатации са следните:

и. Рамка на приписване за присвояване на offer_ids за транзакции:

За да отговоря на въпрос 1, трябваше първо да дефинирам какво означава „ефективна оферта“, използвайки записите на транзакциите. Това се оказа най-сложната част от проекта. Трябваше да дефинирам фуния за това как ще изглежда една ефективна реализация, тъй като имахме данни както за ефективните, така и за неефективните реализации. По този начин проектирах модел на приписване за събитията за реализация (събития „завършена оферта“ и „транзакция“) въз основа на събитията, настъпили преди всеки човек.

В крайна сметка трябваше да разделя потребителите на 4 различни групи въз основа на техните действия в данните за преписа:

- Група 1: Хора, които са повлияни от оферти и по този начин купуват/завършват офертата (успешна/ефективна реализация на оферта)
- Група 2: Хора, които получават и оферта, но не са повлияни и следователно няма събитие за реализация ( неефективно преобразуване на оферта)
- Група 3: Хора, които имат събития на реализация, но всъщност не са били повлияни от оферта
- Група 4: Хора, които получават оферти, но не виждат или предприемат действия

Дори след разделянето на групите беше предизвикателство да се присвоят хората в група 3 въз основа на данните за транзакциите. Трябваше да дефинирам пространството за събития, където ще се случи правилната последователност от събития, преди да мога да присвоя идентификатор на оферта на транзакции (които нямаха offer_id), като по същество проектирах прозорец за приписване, базиран на събитие/последователност.

ii. Инженеринг на функции:

Вземане на решение какви функции да се проектират повторно и как да се проектира за ефективен модел. В крайна сметка нашата преработена характеристика на членството наистина беше най-важната характеристика.

iii. Решения за внедряване на модел:

Бях взел решение да създам 3 отделни модела в зависимост от типовете оферти въз основа на моята дефиниция на формулировката на проблема - тъй като исках да открия какво ще задвижи ефективна оферта, реших, че има по-голям смисъл да премахна шума от данните, като отделя данни в типовете оферти. Решението ми в крайна сметка се оказа доста добро, тъй като единичните модели BOGO и моделите с отстъпка се представиха добре в резултатите от тестването.

За информационния модел точността беше малко по-лоша, тъй като имахме по-малко записи като цяло. Както беше описано по-горе, вярвам, че ако имахме повече данни, можех да постигна по-висока точност.

Допълнителна бележка относно избора на модел — избрах модели, базирани на дърво, тъй като исках да оценя важността на характеристиките, но можех да разширя това проучване допълнително, като тествам параметричен/регресионен модел (напр. логистична регресия за задачи за класификация). Теглата на коефициентите от регресионен модел може да са били интересни за контраст с важността на характеристиките на дървовиден модел, като се има предвид, че и двата модела имат различни начини за анализиране на данните. Характеристиката „membership_tenure_days“ може да не е била най-високо претеглената характеристика, за разлика от това, което беше в това проучване.

Допълнителни подобрения и експерименти

Поради причини, свързани с времето, не можах да получа възможност да опитам друго подобрение в стъпката на настройка на модела. Например, вероятно мога да направя още няколко експеримента върху стъпката на инженеринг на функции, за да видя дали някакви други нови функции могат да подобрят модела, също така мога да опитам да намаля някои функции, за да видя как ще се отрази на производителността на модела.

Също така, досега анализът е фокусиран повече върху клиентите, които успешно завършват транзакцията, след като са получили офертата, трябва да има повече информация за другите случаи, когато клиентът завършва транзакциите независимо от офертата. Ако успеем да разберем тези случаи, може би ще можем да изпратим повече оферти на тези клиенти.

Освен това си мислех дали бих могъл да направя малко безконтролно обучение за групиране на клиентите въз основа на информацията, която ни е дадена, за да видя дали има някакви специфични характеристики на група клиенти, които е по-вероятно да отговорят на офертата.

За да видите повече подробности за анализа, можете да намерите моята връзка в Github тук.