Традиционные методы анализа воронок продаж и моделей атрибуции часто оказываются недостаточными для современных многоканальных маркетинговых стратегий. Пользователи взаимодействуют с брендом через множество точек контакта, и их путь к конверсии может быть длинным и запутанным. Именно поэтому аналитикам и маркетологам нужны более совершенные инструменты для анализа и оптимизации маркетинговых усилий.
Язык программирования Python и его основная библиотека для работы с данными Pandas подходят как нельзя кстати для построения сложных воронок и создания кастомных моделей атрибуции. В этой статье мы рассмотрим, как использовать эти инструменты для построения многоуровневых воронок продаж, анализа ассоциированных конверсий и создания собственных моделей атрибуции. Мы будем работать с реальными данными веб-аналитики и рассмотрим практические примеры кода, которые вы сможете адаптировать под свои задачи.
Подготовка данных
Прежде чем мы перейдем к построению воронок и моделей атрибуции, давайте рассмотрим, как подготовить и очистить данные для анализа. В нашем случае мы будем работать с датасетом, содержащим подробную информацию о посещениях сайта и конверсиях.
Загрузка и предварительный анализ данных
Начнем с загрузки нашего датасета и проведем его первичный анализ:
import pandas as pd
import numpy as np
from datetime import datetime
import matplotlib.pyplot as plt
import seaborn as sns
# Загрузка данных
df = pd.read_csv('web_analytics_data.csv', parse_dates=['HitDateTime', 'VisitDateTime'])
# Просмотр первых строк и информации о датасете
print(df.head())
print(df.info())
# Базовая статистика
print(df.describe())
# Проверка на пропущенные значения
print(df.isnull().sum())
Этот код загружает наш датасет, преобразуя столбцы с датами в формат datetime, и выводит основную информацию о данных. Обратите внимание, что мы используем функцию parse_dates при чтении CSV-файла, чтобы автоматически преобразовать строковые значения дат в объекты datetime.
Очистка и преобразование данных
После первичного анализа мы можем приступить к очистке и преобразованию данных. Вот несколько ключевых шагов, которые обычно необходимо выполнить:
- Обработка пропущенных значений;
- Преобразование типов данных;
- Создание новых признаков.
Давайте рассмотрим каждый из этих шагов подробнее:
# Обработка пропущенных значений
df['Referer'].fillna('Direct', inplace=True)
df['UTMSource'].fillna('unknown', inplace=True)
df['UTMMedium'].fillna('unknown', inplace=True)
df['UTMCampaign'].fillna('unknown', inplace=True)
df['UTMTerm'].fillna('unknown', inplace=True)
# Преобразование типов данных
df['isNewUser'] = df['isNewUser'].astype(bool)
# Создание новых признаков
df['DayOfWeek'] = df['HitDateTime'].dt.dayofweek
df['Hour'] = df['HitDateTime'].dt.hour
df['SessionDuration'] = (df['VisitDateTime'] + pd.to_timedelta(df['VisitDuration'], unit='s') - df['VisitDateTime']).dt.total_seconds()
# Проверка результатов
print(df.dtypes)
print(df[['DayOfWeek', 'Hour', 'SessionDuration']].head())
В этом примере мы выполнили несколько важных преобразований:
- Заполнили пропущенные значения в столбцах с UTM-метками и рефереров;
- Преобразовали столбец isNewUser в логический тип данных;
- Создали новые признаки: день недели, час дня и продолжительность сессии в секундах.
Такие преобразования помогут нам в дальнейшем анализе и построении воронок продаж.
Анализ распределения ключевых метрик
Перед тем как перейти к построению воронок, полезно понять распределение ключевых метрик в наших данных. Это поможет нам выявить аномалии и лучше понять поведение пользователей.
# Анализ распределения длительности сессий
plt.figure(figsize=(12, 6))
sns.histplot(df['SessionDuration'], kde=True, bins=50)
plt.title('Распределение длительности сессий')
plt.xlabel('Длительность сессии (секунды)')
plt.ylabel('Количество сессий')
plt.show()
# Анализ распределения количества просмотров страниц
plt.figure(figsize=(12, 6))
sns.boxplot(x='DayOfWeek', y='Pageviews', data=df)
plt.title('Распределение просмотров страниц по дням недели')
plt.xlabel('День недели')
plt.ylabel('Количество просмотров страниц')
plt.show()
# Анализ конверсий по источникам трафика
conversion_rate = df.groupby('Source')['GoalsID'].apply(lambda x: (x.astype(bool).sum() / len(x)) * 100)
plt.figure(figsize=(12, 6))
conversion_rate.sort_values(ascending=False).plot(kind='bar')
plt.title('Конверсия по источникам трафика')
plt.xlabel('Источник трафика')
plt.ylabel('Конверсия (%)')
plt.xticks(rotation=45)
plt.show()
Этот код создает три визуализации:
- Гистограмму распределения длительности сессий;
- Диаграмму размаха (box plot) для просмотров страниц по дням недели;
- Столбчатую диаграмму конверсий по источникам трафика.
Такой анализ помогает выявить интересные паттерны в данных. Например, мы можем увидеть, в какие дни недели пользователи проявляют наибольшую активность или какие источники трафика приносят наиболее качественных посетителей.
Построение сложных воронок продаж
Теперь, когда мы подготовили и проанализировали наши данные, можем перейти к построению сложных воронок продаж. В отличие от простых линейных воронок, сложные воронки учитывают различные пути пользователей к конверсии и могут включать множество шагов и ветвлений.
Определение ключевых этапов воронки
Первый шаг в построении сложной воронки – определение ключевых этапов, через которые проходит пользователь. В нашем случае, давайте предположим, что мы анализируем воронку продаж для интернет-магазина. Ключевые этапы могут выглядеть так:
- Посещение главной страницы;
- Просмотр категории товаров;
- Просмотр карточки товара;
- Добавление товара в корзину;
- Начало оформления заказа;
- Заполнение данных доставки;
- Выбор способа оплаты;
- Завершение заказа.
Для анализа такой воронки нам понадобится создать функцию, которая будет определять, на каком этапе находится пользователь на основе его действий:
def get_funnel_stage(url, goals):
if '/category/' in url:
return 'Category View'
elif '/product/' in url:
return 'Product View'
elif '/cart/' in url:
return 'Cart'
elif '/checkout/' in url:
if 'shipping' in url:
return 'Shipping Info'
elif 'payment' in url:
return 'Payment'
else:
return 'Checkout Start'
elif 1 in goals: # Предположим, что goal_id=1 означает завершение заказа
return 'Order Complete'
else:
return 'Homepage'
# Применяем функцию к нашим данным
df['FunnelStage'] = df.apply(lambda row: get_funnel_stage(row['URL'], row['PageGoals']), axis=1)
# Анализируем распределение пользователей по этапам воронки
funnel_distribution = df['FunnelStage'].value_counts().sort_index()
print(funnel_distribution)
# Визуализируем воронку
plt.figure(figsize=(12, 6))
sns.barplot(x=funnel_distribution.index, y=funnel_distribution.values)
plt.title('Распределение пользователей по этапам воронки')
plt.xlabel('Этап воронки')
plt.ylabel('Количество пользователей')
plt.xticks(rotation=45)
plt.show()
Этот код создает новый столбец FunnelStage, который определяет этап воронки для каждого действия пользователя. Затем мы анализируем распределение пользователей по этапам и визуализируем результаты.
Анализ переходов между этапами воронки
Следующий шаг – анализ того, как пользователи переходят между этапами воронки. Для этого мы можем использовать метод когортного анализа:
def get_user_journey(group):
return ' > '.join(group['FunnelStage'].unique())
# Получаем уникальные пути пользователей через воронку
user_journeys = df.groupby('VisitID').apply(get_user_journey).value_counts()
print("Топ-10 наиболее распространенных путей через воронку:")
print(user_journeys.head(10))
# Анализ переходов между этапами
transitions = df.groupby('VisitID')['FunnelStage'].apply(lambda x: list(zip(x, x[1:])))
transition_counts = transitions.explode().value_counts()
# Визуализация переходов в виде тепловой карты
transition_matrix = transition_counts.unstack()
plt.figure(figsize=(12, 10))
sns.heatmap(transition_matrix, annot=True, fmt='g', cmap='YlOrRd')
plt.title('Тепловая карта переходов между этапами воронки')
plt.xlabel('Следующий этап')
plt.ylabel('Текущий этап')
plt.show()
Этот код делает две важные вещи:
- Анализирует наиболее распространенные пути пользователей через воронку;
- Создает тепловую карту переходов между этапами воронки.
Такой анализ позволяет выявить узкие места в воронке и понять на каких этапах происходит наибольший отток пользователей.
Расчет конверсий на каждом этапе
Наконец, давайте рассчитаем конверсии на каждом этапе воронки:
def calculate_funnel_conversion(df):
stage_order = ['Homepage', 'Category View', 'Product View', 'Cart', 'Checkout Start', 'Shipping Info', 'Payment', 'Order Complete']
conversions = []
total_users = df['ClientID'].nunique()
for i in range(len(stage_order)):
stage = stage_order[i]
users_at_stage = df[df['FunnelStage'] == stage]['ClientID'].nunique()
conversion_rate = users_at_stage / total_users * 100 if i == 0 else users_at_stage / prev_users * 100
conversions.append({
'Stage': stage,
'Users': users_at_stage,
'Conversion Rate': conversion_rate
})
prev_users = users_at_stage
return pd.DataFrame(conversions)
funnel_conversion = calculate_funnel_conversion(df)
print(funnel_conversion)
# Визуализация конверсий
plt.figure(figsize=(12, 6))
sns.lineplot(x='Stage', y='Conversion Rate', data=funnel_conversion, marker='o')
plt.title('Конверсии на каждом этапе воронки')
plt.xlabel('Этап воронки')
plt.ylabel('Конверсия (%)')
plt.xticks(rotation=45)
plt.show()
Этот код рассчитывает конверсии на каждом этапе воронки и визуализирует результаты в виде линейного графика. Такой подход позволяет нам увидеть, на каких этапах происходит наибольший отток пользователей и где есть потенциал для оптимизации.
Сегментация пользователей по поведению в воронке
Для более глубокого понимания поведения пользователей в воронке продаж, мы можем провести сегментацию на основе их действий. Это поможет выявить различные паттерны поведения и адаптировать маркетинговые стратегии для каждого сегмента.
def segment_users(group):
stages = group['FunnelStage'].unique()
if 'Order Complete' in stages:
return 'Converters'
elif 'Payment' in stages or 'Shipping Info' in stages:
return 'Almost Converters'
elif 'Cart' in stages:
return 'Interested'
elif 'Product View' in stages:
return 'Browsers'
else:
return 'Bounced'
# Применяем сегментацию к нашим данным
df['UserSegment'] = df.groupby('ClientID').apply(segment_users)
# Анализируем распределение пользователей по сегментам
segment_distribution = df['UserSegment'].value_counts()
print("Распределение пользователей по сегментам:")
print(segment_distribution)
# Визуализируем распределение
plt.figure(figsize=(10, 6))
segment_distribution.plot(kind='pie', autopct='%1.1f%%')
plt.title('Распределение пользователей по сегментам')
plt.ylabel('')
plt.show()
# Анализируем характеристики каждого сегмента
segment_analysis = df.groupby('UserSegment').agg({
'SessionDuration': 'mean',
'Pageviews': 'mean',
'GoalsID': lambda x: x.astype(bool).sum() / len(x) * 100 # конверсия
}).reset_index()
print("\nХарактеристики сегментов:")
print(segment_analysis)
# Визуализируем характеристики сегментов
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(18, 6))
sns.barplot(x='UserSegment', y='SessionDuration', data=segment_analysis, ax=ax1)
ax1.set_title('Средняя длительность сессии')
ax1.set_ylabel('Длительность (секунды)')
sns.barplot(x='UserSegment', y='Pageviews', data=segment_analysis, ax=ax2)
ax2.set_title('Среднее количество просмотров страниц')
ax2.set_ylabel('Количество просмотров')
sns.barplot(x='UserSegment', y='GoalsID', data=segment_analysis, ax=ax3)
ax3.set_title('Конверсия')
ax3.set_ylabel('Конверсия (%)')
plt.tight_layout()
plt.show()
Этот код выполняет следующие действия:
- Определяет функцию для сегментации пользователей на основе их поведения в воронке;
- Применяет сегментацию к нашим данным;
- Анализирует распределение пользователей по сегментам и визуализирует его в виде круговой диаграммы;
- Рассчитывает средние характеристики для каждого сегмента (длительность сессии, количество просмотров страниц, конверсию);
- Визуализирует характеристики сегментов в виде столбчатых диаграмм.
Такой анализ позволяет нам лучше понять различия между сегментами пользователей и может служить основой для разработки персонализированных маркетинговых стратегий.
Анализ ассоциированных конверсий
После того как мы построили и проанализировали сложную воронку продаж, давайте перейдем к анализу ассоциированных конверсий. С помощью этого анализа мы поймем какие действия пользователей и какие маркетинговые каналы вносят вклад в конверсии, даже если они не являются последним шагом перед покупкой.
Подготовка данных для анализа ассоциированных конверсий
Для начала нам нужно подготовить данные, группируя действия пользователей в рамках одной сессии:
def prepare_session_data(df):
session_data = df.groupby('VisitID').agg({
'ClientID': 'first',
'Source': lambda x: list(x.unique()),
'UTMSource': lambda x: list(x.unique()),
'UTMMedium': lambda x: list(x.unique()),
'UTMCampaign': lambda x: list(x.unique()),
'FunnelStage': lambda x: list(x),
'GoalsID': lambda x: list(set(x.sum()))
}).reset_index()
session_data['Converted'] = session_data['GoalsID'].apply(lambda x: 1 in x)
return session_data
session_df = prepare_session_data(df)
print(session_df.head())
Эта функция группирует данные по сессиям, сохраняя информацию о всех источниках трафика, utm-метках и этапах воронки, которые прошел пользователь за сессию.
Анализ вклада различных каналов в конверсии
Теперь мы можем проанализировать, как различные каналы и utm-метки связаны с конверсиями:
def analyze_channel_contribution(session_df, channel_column):
channel_contribution = session_df[session_df['Converted']][channel_column].explode().value_counts()
total_conversions = session_df['Converted'].sum()
contribution_df = pd.DataFrame({
'Channel': channel_contribution.index,
'Conversions': channel_contribution.values,
'Contribution': channel_contribution.values / total_conversions * 100
})
return contribution_df.sort_values('Contribution', ascending=False)
# Анализируем вклад различных источников трафика
source_contribution = analyze_channel_contribution(session_df, 'Source')
print("Вклад источников трафика в конверсии:")
print(source_contribution)
# Визуализируем результаты
plt.figure(figsize=(12, 6))
sns.barplot(x='Channel', y='Contribution', data=source_contribution.head(10))
plt.title('Топ-10 источников трафика по вкладу в конверсии')
plt.xlabel('Источник трафика')
plt.ylabel('Вклад в конверсии (%)')
plt.xticks(rotation=45)
plt.show()
# Аналогичный анализ можно провести для UTM-меток
utm_source_contribution = analyze_channel_contribution(session_df, 'UTMSource')
utm_medium_contribution = analyze_channel_contribution(session_df, 'UTMMedium')
utm_campaign_contribution = analyze_channel_contribution(session_df, 'UTMCampaign')
# Визуализация вклада UTM-источников
plt.figure(figsize=(12, 6))
sns.barplot(x='Channel', y='Contribution', data=utm_source_contribution.head(10))
plt.title('Топ-10 UTM-источников по вкладу в конверсии')
plt.xlabel('UTM-источник')
plt.ylabel('Вклад в конверсии (%)')
plt.xticks(rotation=45)
plt.show()
Этот код анализирует вклад различных каналов в конверсии и визуализирует результаты. Мы можем увидеть, какие источники трафика и utm-метки наиболее часто ассоциируются с конверсиями.
Анализ последовательностей действий, приводящих к конверсии
Еще один важный аспект анализа ассоциированных конверсий – это понимание последовательностей действий пользователей сайта, которые чаще всего приводят к конверсии. Для этого мы можем использовать анализ путей:
from collections import Counter
def analyze_conversion_paths(session_df):
converted_paths = session_df[session_df['Converted']]['FunnelStage'].apply(lambda x: ' > '.join(x))
path_counts = Counter(converted_paths)
total_conversions = sum(path_counts.values())
path_df = pd.DataFrame({
'Path': list(path_counts.keys()),
'Count': list(path_counts.values()),
'Percentage': [count / total_conversions * 100 for count in path_counts.values()]
}).sort_values('Count', ascending=False)
return path_df
conversion_paths = analyze_conversion_paths(session_df)
print("Топ-10 путей к конверсии:")
print(conversion_paths.head(10))
# Визуализация топ-5 путей к конверсии
plt.figure(figsize=(12, 6))
sns.barplot(x='Percentage', y='Path', data=conversion_paths.head())
plt.title('Топ-5 путей к конверсии')
plt.xlabel('Процент конверсий')
plt.ylabel('Путь')
plt.show()
Этот код анализирует наиболее распространенные последовательности действий, которые приводят к конверсии, и визуализирует топ-5 путей.
Создание собственных моделей атрибуции
Теперь, когда мы проанализировали сложные воронки и ассоциированные конверсии, давайте перейдем к созданию собственных моделей атрибуции. Модели атрибуции помогают нам понять, как распределить “заслуги” за конверсию между различными маркетинговыми каналами и точками взаимодействия с пользователем.
Реализация базовых моделей атрибуции
Начнем с реализации нескольких базовых моделей атрибуции:
def last_click_attribution(session):
if session['Converted']:
return session['Source'][-1]
return None
def first_click_attribution(session):
if session['Converted']:
return session['Source'][0]
return None
def linear_attribution(session):
if session['Converted']:
return {source: 1/len(session['Source']) for source in set(session['Source'])}
return None
# Применяем модели атрибуции к нашим данным
session_df['LastClickAttribution'] = session_df.apply(last_click_attribution, axis=1)
session_df['FirstClickAttribution'] = session_df.apply(first_click_attribution, axis=1)
session_df['LinearAttribution'] = session_df.apply(linear_attribution, axis=1)
# Анализируем результаты атрибуции
def analyze_attribution(df, attribution_column):
attribution = df[df['Converted']][attribution_column].value_counts()
total_conversions = attribution.sum()
attribution_df = pd.DataFrame({
'Channel': attribution.index,
'Conversions': attribution.values,
'Percentage': attribution.values / total_conversions * 100
}).sort_values('Percentage', ascending=False)
return attribution_df
last_click_results = analyze_attribution(session_df, 'LastClickAttribution')
first_click_results = analyze_attribution(session_df, 'FirstClickAttribution')
print("Результаты атрибуции по последнему клику:")
print(last_click_results)
print("\nРезультаты атрибуции по первому клику:")
print(first_click_results)
# Визуализируем результаты
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(18, 6))
sns.barplot(x='Channel', y='Percentage', data=last_click_results.head(), ax=ax1)
ax1.set_title('Атрибуция по последнему клику')
ax1.set_xlabel('Канал')
ax1.set_ylabel('Процент конверсий')
ax1.tick_params(axis='x', rotation=45)
sns.barplot(x='Channel', y='Percentage', data=first_click_results.head(), ax=ax2)
ax2.set_title('Атрибуция по первому клику')
ax2.set_xlabel('Канал')
ax2.set_ylabel('Процент конверсий')
ax2.tick_params(axis='x', rotation=45)
plt.tight_layout()
plt.show()
# Анализ линейной атрибуции
linear_attribution_results = session_df[session_df['Converted']]['LinearAttribution'].apply(pd.Series).sum()
linear_attribution_df = pd.DataFrame({
'Channel': linear_attribution_results.index,
'Attribution': linear_attribution_results.values,
'Percentage': linear_attribution_results.values / linear_attribution_results.sum() * 100
}).sort_values('Percentage', ascending=False)
print("\nРезультаты линейной атрибуции:")
print(linear_attribution_df)
plt.figure(figsize=(12, 6))
sns.barplot(x='Channel', y='Percentage', data=linear_attribution_df.head(10))
plt.title('Топ-10 каналов по линейной атрибуции')
plt.xlabel('Канал')
plt.ylabel('Процент атрибуции')
plt.xticks(rotation=45)
plt.show()
Этот код реализует три базовые модели атрибуции:
- Атрибуция по последнему клику (Last Click Attribution);
- Атрибуция по первому клику (First Click Attribution);
- Линейная атрибуция (Linear Attribution).
Мы применяем эти модели к нашим данным и визуализируем результаты, что позволяет сравнить, как разные модели атрибуции оценивают вклад различных каналов в конверсии.
Реализация модели атрибуции U-shape
Модель атрибуции U-shape (или “U-образная модель”) придает большее значение первому и последнему взаимодействию в пути пользователя к конверсии, распределяя оставшийся вес равномерно между промежуточными точками контакта. Обычно первому и последнему взаимодействию присваивается по 40% “заслуги” за конверсию, а оставшиеся 20% распределяются между промежуточными точками контакта.
Давайте реализуем эту модель с помощью Python и проанализируем ее результаты:
def u_shape_attribution(session):
if session['Converted']:
touchpoints = session['Source']
n = len(touchpoints)
if n == 1:
return {touchpoints[0]: 1.0}
elif n == 2:
return {touchpoints[0]: 0.5, touchpoints[1]: 0.5}
else:
attribution = {touchpoints[0]: 0.4, touchpoints[-1]: 0.4}
middle_weight = 0.2 / (n - 2)
for tp in touchpoints[1:-1]:
attribution[tp] = attribution.get(tp, 0) + middle_weight
return attribution
return None
# Применяем U-shape атрибуцию к нашим данным
session_df['UShapeAttribution'] = session_df.apply(u_shape_attribution, axis=1)
# Анализ результатов U-shape атрибуции
u_shape_results = session_df[session_df['Converted']]['UShapeAttribution'].apply(pd.Series).sum()
u_shape_df = pd.DataFrame({
'Channel': u_shape_results.index,
'Attribution': u_shape_results.values,
'Percentage': u_shape_results.values / u_shape_results.sum() * 100
}).sort_values('Percentage', ascending=False)
print("Результаты U-shape атрибуции:")
print(u_shape_df)
Теперь давайте построим визуализации модели:
# Визуализация результатов U-shape атрибуции
plt.figure(figsize=(12, 6))
sns.barplot(x='Percentage', y='Channel', data=u_shape_df.head(10))
plt.title('Топ-10 каналов по U-shape атрибуции')
plt.xlabel('Процент атрибуции')
plt.ylabel('Канал')
plt.show()
# Анализ вклада UTM-источников
def analyze_utm_contribution(session_df, attribution_column):
utm_contribution = session_df[session_df['Converted']].apply(
lambda row: {utm: value for utm, value in zip(row['UTMSource'], row[attribution_column].values())},
axis=1
).sum()
total_attribution = sum(utm_contribution.values())
utm_df = pd.DataFrame({
'UTM Source': utm_contribution.index,
'Attribution': utm_contribution.values,
'Percentage': [value / total_attribution * 100 for value in utm_contribution.values]
}).sort_values('Percentage', ascending=False)
return utm_df
utm_u_shape_df = analyze_utm_contribution(session_df, 'UShapeAttribution')
print("\nВклад UTM-источников согласно U-shape атрибуции:")
print(utm_u_shape_df)
# Визуализация вклада UTM-источников
plt.figure(figsize=(12, 6))
sns.barplot(x='Percentage', y='UTM Source', data=utm_u_shape_df.head(10))
plt.title('Топ-10 UTM-источников по U-shape атрибуции')
plt.xlabel('Процент атрибуции')
plt.ylabel('UTM-источник')
plt.show()
# Анализ последовательностей действий, приводящих к конверсии
def analyze_conversion_paths_u_shape(session_df):
converted_paths = session_df[session_df['Converted']]['Source'].apply(lambda x: ' > '.join(x))
path_counts = converted_paths.value_counts()
total_conversions = path_counts.sum()
path_df = pd.DataFrame({
'Path': path_counts.index,
'Count': path_counts.values,
'Percentage': path_counts.values / total_conversions * 100
}).sort_values('Count', ascending=False)
return path_df
conversion_paths_u_shape = analyze_conversion_paths_u_shape(session_df)
print("\nТоп-10 путей к конверсии согласно U-shape модели:")
print(conversion_paths_u_shape.head(10))
# Визуализация топ-5 путей к конверсии
plt.figure(figsize=(12, 6))
sns.barplot(x='Percentage', y='Path', data=conversion_paths_u_shape.head())
plt.title('Топ-5 путей к конверсии (U-shape модель)')
plt.xlabel('Процент конверсий')
plt.ylabel('Путь')
plt.show()
Этот код выполняет следующие действия:
- Создает функцию u_shape_attribution для применения U-shape модели к каждой сессии;
- Применяет U-shape атрибуцию к нашим данным и анализирует результаты;
- Визуализирует топ-10 каналов по U-shape атрибуции;
- Анализирует вклад UTM-источников согласно U-shape модели;
- Анализирует последовательности действий, приводящих к конверсии, с учетом весов U-shape модели.
U-shape модель атрибуции в последние годы входит в число самых популярных среди интернет-маркетологов, так как позволяет учесть важность как первого взаимодействия (привлечение пользователя), так и последнего (непосредственно перед конверсией), не игнорируя при этом промежуточные точки контакта. Это особенно полезно в нишах с долгим циклом продаж и множественными касаниями пользователей с сайтом до заключения сделки.
Создание продвинутой модели атрибуции на основе машинного обучения
Теперь давайте создадим более продвинутую модель атрибуции, используя методы машинного обучения. Мы будем использовать логистическую регрессию для оценки вероятности конверсии на основе последовательности взаимодействий пользователя с различными каналами.
from sklearn.preprocessing import MultiLabelBinarizer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
# Подготовка данных для модели
mlb = MultiLabelBinarizer()
channel_features = mlb.fit_transform(session_df['Source'])
channel_names = mlb.classes_
X = pd.DataFrame(channel_features, columns=channel_names)
y = session_df['Converted']
# Разделение данных на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Обучение модели
model = LogisticRegression(random_state=42)
model.fit(X_train, y_train)
# Оценка качества модели
train_auc = roc_auc_score(y_train, model.predict_proba(X_train)[:, 1])
test_auc = roc_auc_score(y_test, model.predict_proba(X_test)[:, 1])
print(f"AUC на обучающей выборке: {train_auc:.3f}")
print(f"AUC на тестовой выборке: {test_auc:.3f}")
# Анализ коэффициентов модели для оценки вклада каналов
channel_importance = pd.DataFrame({
'Channel': channel_names,
'Coefficient': model.coef_[0]
}).sort_values('Coefficient', ascending=False)
print("\nВажность каналов согласно модели:")
print(channel_importance)
# Визуализация важности каналов
plt.figure(figsize=(12, 6))
sns.barplot(x='Coefficient', y='Channel', data=channel_importance.head(10))
plt.title('Топ-10 каналов по важности (на основе коэффициентов модели)')
plt.xlabel('Коэффициент')
plt.ylabel('Канал')
plt.show()
# Функция для атрибуции на основе модели
def model_based_attribution(session, model, mlb):
if session['Converted']:
channels = mlb.transform([session['Source']])[0]
channel_contributions = channels * model.coef_[0]
total_contribution = channel_contributions.sum()
return {channel: contribution / total_contribution for channel, contribution in zip(mlb.classes_, channel_contributions) if contribution > 0}
return None
# Применяем модельную атрибуцию к нашим данным
session_df['ModelAttribution'] = session_df.apply(lambda x: model_based_attribution(x, model, mlb), axis=1)
# Анализ результатов модельной атрибуции
model_attribution_results = session_df[session_df['Converted']]['ModelAttribution'].apply(pd.Series).sum()
model_attribution_df = pd.DataFrame({
'Channel': model_attribution_results.index,
'Attribution': model_attribution_results.values,
'Percentage': model_attribution_results.values / model_attribution_results.sum() * 100
}).sort_values('Percentage', ascending=False)
print("\nРезультаты модельной атрибуции:")
print(model_attribution_df)
# Визуализация результатов модельной атрибуции
plt.figure(figsize=(12, 6))
sns.barplot(x='Percentage', y='Channel', data=model_attribution_df.head(10))
plt.title('Топ-10 каналов по модельной атрибуции')
plt.xlabel('Процент атрибуции')
plt.ylabel('Канал')
plt.show()
Этот код выполняет следующие шаги:
- Подготовка данных для модели, используя MultiLabelBinarizer для преобразования последовательностей каналов в бинарные признаки;
- Разделение данных на обучающую и тестовую выборки;
- Обучение логистической регрессии для предсказания вероятности конверсии;
- Оценка качества модели с помощью метрики AUC (Area Under the ROC Curve);
- Анализ коэффициентов модели для оценки важности каналов;
- Создание функции модельной атрибуции, которая распределяет “заслуги” за конверсию пропорционально вкладу каждого канала согласно модели;
- Применение модельной атрибуции к данным и анализ результатов.
Такой подход позволяет нам создать более сложную и потенциально более точную модель атрибуции, которая учитывает взаимодействие между различными каналами и их совместное влияние на вероятность конверсии.
Сравнение различных моделей атрибуции
Теперь, когда у нас есть несколько моделей атрибуции, давайте сравним их результаты:
def compare_attribution_models(session_df, models):
results = {}
for model_name, attribution_column in models.items():
if isinstance(session_df[attribution_column].iloc[0], dict):
attribution = session_df[session_df['Converted']][attribution_column].apply(pd.Series).sum()
else:
attribution = session_df[session_df['Converted']][attribution_column].value_counts()
total_attribution = attribution.sum()
results[model_name] = attribution / total_attribution * 100
return pd.DataFrame(results)
attribution_models = {
'Last Click': 'LastClickAttribution',
'First Click': 'FirstClickAttribution',
'Linear': 'LinearAttribution',
'Model-based': 'ModelAttribution',
'U-shape': 'UShapeAttribution'
}
comparison_df = compare_attribution_models(session_df, attribution_models)
# Визуализация сравнения моделей атрибуции
plt.figure(figsize=(15, 8))
comparison_df.head(10).plot(kind='bar', width=0.8)
plt.title('Сравнение моделей атрибуции (топ-10 каналов)')
plt.xlabel('Канал')
plt.ylabel('Процент атрибуции')
plt.legend(title='Модель атрибуции', bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
plt.show()
# Анализ различий между моделями
print("Средние абсолютные различия между моделями атрибуции:")
models = list(attribution_models.keys())
for i in range(len(models)):
for j in range(i+1, len(models)):
diff = (comparison_df[models[i]] - comparison_df[models[j]]).abs().mean()
print(f"{models[i]} vs {models[j]}: {diff:.2f}%")
Этот код сравнивает результаты различных моделей атрибуции и визуализирует их на одном графике. Также мы рассчитываем средние абсолютные различия между моделями, чтобы количественно оценить, насколько сильно различаются их результаты.
Практические рекомендации по использованию сложных воронок и моделей атрибуции
На основе проведенного анализа, давайте сформулируем некоторые практические рекомендации по использованию сложных воронок и моделей атрибуции:
- Используйте многоуровневый подход к анализу воронок: Начните с общей воронки продаж, затем углубитесь в анализ отдельных сегментов пользователей и каналов привлечения. Регулярно отслеживайте изменения в воронке и проводите A/B-тестирование для оптимизации конверсии на каждом этапе;
- Обратите внимание на ассоциированные конверсии: Не ограничивайтесь анализом только последнего взаимодействия перед конверсией. Изучайте полный путь пользователя и вклад различных точек взаимодействия в конверсию;
- Сравнивайте различные модели атрибуции: Не оценивайте источники трафика только по одному варианту атрибуции. Используйте несколько моделей атрибуции для получения более полной картины. Обратите внимание на различия в результатах разных моделей и постарайтесь понять причины этих различий;
- Адаптируйте стратегию на основе результатов анализа: Перераспределяйте бюджет между каналами на основе их вклада в конверсии. Оптимизируйте контент и предложения на различных этапах воронки продаж.
- Регулярно обновляйте и совершенствуйте свои модели: Пересматривайте и обновляйте свои модели атрибуции по мере изменения поведения пользователей и маркетинговых стратегий. Экспериментируйте с более сложными моделями машинного обучения для повышения точности атрибуции;
- Интегрируйте данные из различных источников: Объедините данные из веб-аналитики, CRM-систем и рекламных платформ для создания более полной картины пользовательского пути. Используйте уникальные идентификаторы пользователей для отслеживания их взаимодействий на различных устройствах и каналах;
- Учитывайте особенности вашего бизнеса: Адаптируйте модели воронок и атрибуции к специфике вашего бизнеса и отрасли. Обратите внимание на сезонность, длительность цикла продаж и другие факторы, влияющие на поведение пользователей;
- Не забывайте о качественном анализе: Дополняйте количественный анализ качественными исследованиями, такими как опросы пользователей и анализ отзывов. Используйте эти данные для лучшего понимания мотивации и препятствий на пути к конверсии.
Заключение
В этой статье мы рассмотрели, как использовать Python и библиотеку Pandas для построения сложных воронок продаж, анализа ассоциированных конверсий и создания собственных моделей атрибуции. Мы прошли путь от подготовки и очистки данных до создания продвинутых моделей атрибуции на основе машинного обучения.
Умение работать с нестандартными атрибуциями и ассоциированными конверсиями – важной навык в веб-аналитике. Применение этих методов анализа может значительно повысить эффективность маркетинговых усилий, помочь в оптимизации распределения бюджета и улучшить пользовательский опыт на всех этапах воронки продаж.