4 заметки с тегом

аналитика

How to: YouTube API

Время чтения текста – 9 минут

Современным аналитикам необходимо обладать навыком сбора информации из социальных сетей, ведь сейчас контент социальных сетей очень точно отражает реальную ситуацию в мире, помогает быстро распространить новости и позволяет анализировать аудиторию — подписчиков. В предыдущих постах мы уже описывали кейсы с использованием различных API: Vkontakte API, Facebook API, GitHub API. Сегодня мы расскажем вам о том, что представляет из себя YouTube API, как получить ключ API, а также наглядно покажем, какую информацию можно собрать с его помощью. В двух словах, с помощью YouTube API можно находить каналы по ключевым словам, выгружать данные канала, а также статистику по видео, опубликованным на этих каналах.

Подготовительный этап для работы с YouTube API

Для начала, нужно разобраться в том, как получить доступ к API. Этот процесс подробно изложен на сайте для разработчиков, на который вы можете перейти по ссылке. Если коротко, то необходимо иметь или завести аккаунт Google, войти в профиль для разработчиков, создать проект, получить ключ API и подключить к нему API YouTube Data API v3. Далее, с использованием этого ключа вам будет доступен весь необходимый функционал.
После того, как вы успешно получили ключ, можно открывать любой удобный ноутбук (Jupyter Notebook, Collab и т. д.), устанавливать и подключать нужные для работы библиотеки.

# установка библиотек
	pip install --upgrade google-api-python-client
	pip install --upgrade google-auth-oauthlib google-auth-httplib2
	# импорт необходимых библиотек
import googleapiclient.discovery
import time

Квоты

Один важный момент, который важно знать при использовании Youtube API — это наличие дневных квот на использование функций YouTube API в бесплатном режиме. На день дается квота 10000 юнитов, вызов функции поиска стоит 100 юнитов, вызов информации по объекту — 1 юнит, загрузка видео на YouTube стоит 1600 юнитов. Если вам недостаточно дневной квоты, то вы можете подать запрос в Google на её увеличение, в котором нужно подробно указать цели вашей деятельности c YouTube API.

Поиск YouTube-каналов по ключевым словам

Для начала заведем несколько переменных, которые понадобятся нам в процессе сбора информации.

channels_data = {}
channels_data_full = {}
video_data = {}

Дальше написан скрипт, который можно использовать для поиска перечня каналов по ключевым словам. Мы искали каналы, в названии или описании которых используются следующие слова: s_query = ’аналитика данных data’. Сначала выводятся каналы, в названии или описании которых присутствуют все три слова, затем хотя бы любые два, затем хотя бы одно. Чем больше ключевых слов по теме мы укажем, тем точнее будет результат.

api_service_name = "youtube"
api_version = "v3"
DEVELOPER_KEY = "" #тут нужно указать ключ, который вы получите при подключении YouTube API
 
youtube = googleapiclient.discovery.build(
   api_service_name, api_version, developerKey = DEVELOPER_KEY)
#строка поиска
s_query = 'аналитика данных data'
next_token = ''
 
while(True): 
 time.sleep(0.2)
 request = youtube.search().list(
     part="snippet",
     q=s_query,
     relevanceLanguage="ru",
     type="channel",
     maxResults=25,
     access_token=DEVELOPER_KEY,
     pageToken = next_token
 )
 response = request.execute()
 for item in response['items']:
   channels_data[item['snippet']['channelId']] = [item['snippet']['title'], item['snippet']['description']
   ]
 #берем только первые 25 результатов
 break

Добавим пару важных пояснений относительно скрипта. В начале цикла в этом скрипте (как и в двух последующих) мы вызываем функцию time.sleep(), чтобы инициировать двухсекундную задержку между вызовом функций. Это нужно для того, чтобы запросы к YouTube не были чересчур частыми (и вообще, это считается правилом хорошего тона в программировании, так что советуем взять на заметку).
Для простоты нашего примера мы сохранили только 25 первых каналов из всех подходящих под условия поиска. Если вам хочется найти все каналы, в которых упоминается хотя бы одно из ключевых слов, то нужно использовать следующее свойство:

try:
    next_token = response["nextPageToken"]
  except:
    break

Сбор полной информации по всем выбранным каналам

Теперь, когда названия и описания выбранных каналов собраны, можно переходить к следующему этапу, а именно — выгрузке всей информации об этих каналах, в том числе: количество подписчиков канала, количество видео, общее количество просмотров всех видео канала и страна в которой живет, автор канала.

scount = ''
for channel in channels_data:
   #получаем данные по каждому каналу
   time.sleep(0.2)
   r = youtube.channels().list(
         part="snippet, statistics",
         id=channel,
         access_token=DEVELOPER_KEY
   )
   resp = r.execute()
        
   try:
     if resp['items'][0]['statistics']['hiddenSubscriberCount']:
       scount = 'hidden'
     else:
       scount = resp['items'][0]['statistics']['subscriberCount']
  
     channels_data_full[channel] = [resp['items'][0]['snippet']['title'],
                                  resp['items'][0]['snippet']['description'],
                                  scount,
                                  resp['items'][0]['statistics']['videoCount'],
                                  resp['items'][0]['statistics']['viewCount'],
                                  resp['items'][0]['snippet']['country']
     ]
      
   except:
     pass

Теперь вся нужная информация о канале хранится в переменнной channels_data_full.

Получение информации о видео

Если у вас есть необходимость получить статистику по видео из выбранных каналов, то ниже приведен скрипт на этот случай. В итоге, вы получите словарь video_data с подробной информацией о каждом видео из плейлиста (список всех видео каждого канала): название канала, дата публикации, название и описание видео, количество просмотров, лайков/дизлайков и комментариев.

# получаем информацию по всем видео ранее найденных каналов
for channel in channels_data:
   #анализируем каналы
   time.sleep(0.2)
   r = youtube.channels().list(
           part="contentDetails",
           id=channel,
           access_token=DEVELOPER_KEY
     )
   resp = r.execute()           
   try:
     #получаем плейлист из видео для одного канала из списка
     id_playlist = resp['items'][0]['contentDetails']['relatedPlaylists']['uploads']     
     #получаем набор элементов плейлиста (видео)
     next_token = ''
     while(True):     
       time.sleep(0.2)
       r = youtube.playlistItems().list(
             part="contentDetails",
             playlistId=id_playlist,
             access_token=DEVELOPER_KEY,
             pageToken = next_token
       )
       resp = r.execute()
       for i in resp['items']:
         id_videos = i['contentDetails']['videoId']
         r = youtube.videos().list(
               part="snippet, statistics",
               id=id_videos,               
               access_token=DEVELOPER_KEY
         )
         resp1 = r.execute()       
         video_data[id_videos] = [channel,
                                   resp1['items'][0]['snippet']['publishedAt'],
                                   resp1['items'][0]['snippet']['title'],
                                   resp1['items'][0]['snippet']['description'],
                                   resp1['items'][0]['statistics']['viewCount'],
                                   resp1['items'][0]['statistics']['likeCount'],
                                   resp1['items'][0]['statistics']['dislikeCount'],
                                   resp1['items'][0]['statistics']['commentCount']
          ]
       break

В конце мы ставим break, то есть обрабатываем только одну часть видео из плейлиста. Если вы хотите обработать все видео, то нужно использовать функцию nextpagetoken, которую мы предложили в конце первого скрипта.
В итоге, если трансформировать словарь в привычный датафрейм, мы получим таблицу, которая содержит подробную информацию про все обработанные видео.

d = {'id': [x for x in video_data],
      'channel_id': [video_data[x][0] for x in video_data],
       'published_at': [video_data[x][1] for x in video_data],
      'title': [video_data[x][2] for x in video_data],
      'description': [video_data[x][3] for x in video_data],
      'viewCount': [video_data[x][4] for x in video_data],
      'likeCount': [video_data[x][5] for x in video_data],
      'dislikeCount': [video_data[x][6] for x in video_data],
      'commentCount': [video_data[x][7] for x in video_data]
   }
df = pd.DataFrame(d)
df.head()

Выводы

Конечно, это не все способы работы с YouTube API, однако, мы надеемся, что вы получили представление о том, как сильно расширяются возможности аналитика для получения и обработки информации с помощью этого инструмента.

 1 комментарий    876   2021   api   python   аналитика

Парсим вакансии для аналитиков из Indeed

Время чтения текста – 8 минут

В этом материале мы расскажем, как парсить вакансии с сайта Indeed. Indeed — это крупнейший в мире поисковик вакансий. Этим текстом мы начинаем большой проект по анализу и визуализации показателей оплаты труда в области Data Science в разных странах.
Подобный анализ рынка вакансий, но только в России, мы проводили в материале Анализ рынка вакансий аналитики и BI: дашборд в Tableau, когда парсили данные с сайта HeadHunter.

А еще у нас можно почитать материал Парсим данные каталога сайта, используя Beautiful Soup и Selenium

Импорт библиотек
Библиотека fake_useragent имитирует реальный User-Agent, чтобы преодолеть защиту сайта от парсинга. Таким образом мы сможем пройти проверку HTTP заголовка User-Agent.
Модуль urllib.parse разбирает URL-адрес на компоненты и записывает его как кортеж. Он пригодится для перехода на карточки вакансий. BeautifulSoup поможет разобраться в структуре html-страницы и добыть нужную нам информацию.

import requests
from datetime import timedelta, datetime
import urllib.parse
from fake_useragent import UserAgent
from bs4 import BeautifulSoup
import pandas as pd
import time
from lxml.html import fromstring
from clickhouse_driver import Client
from clickhouse_driver import errors
import numpy as np
from funcs import check_title, get_skills_row, parse_salary, get_sheetname, create_table

Создадим таблицу в Clickhouse
Данные, которые мы собираемся собрать, будем хранить в базе Clickhouse.

create_table = '''CREATE TABLE if not exists indeed.vacancies (
    row_idx UInt16,
    query_string String,
    country String,
    title String,
    company String,
    city String,
    job_added Date,
    easy_apply UInt8,
    company_rating Nullable(Float32),
    remote UInt8,
    job_id String,
    job_link String,
    sheet String,
    skills String,
    added_date Date,
    month_salary_from_USD Float64,
    month_salary_to_USD Float64,
    year_salary_from_USD Float64,
    year_salary_to_USD Float64,
)
ENGINE = ReplacingMergeTree
SETTINGS index_granularity = 8192'''

Обход блокировок
Нам нужно обойти защиту Indeed и избежать блокировки по IP. Для этого используем анонимные прокси адреса на сайте free-proxy-list.net. Как собрать свежие прокси, мы писали в нашем предыдущем тексте «Пишем парсер свежих прокси на Python для Selenium». Прокси адреса мы запишем в массив, который понадобится в момент обращения к Indeed, когда запрос будет проверять User-Agent.

Данный метод удаляет IP из списка с прокси в том случае, если ответ от Indeed через него так и не пришел.

def remove_proxy_from_list_and_update_if_required(proxy):
    global _proxies
    _proxies.remove(proxy)
    if len(_proxies) == 0:
        update_proxy_list()

Функция, используя прокси, возвращает нам страницу Indeed, из которой мы впоследствии спарсим данные.

def get_page(updated_url, session):
    proxy = get_proxy()
    proxy_dict = {"http": proxy, "https": proxy}
    logger.info(f'try with proxy: {proxy}')
    try:
        session.proxies = proxy_dict
        return session.get(updated_url, timeout=15)
    except (requests.exceptions.RequestException, requests.exceptions.ProxyError, requests.exceptions.ConnectTimeout,
            requests.exceptions.ReadTimeout, requests.exceptions.SSLError,
            requests.exceptions.ConnectionError, url_ex.MaxRetryError, ConnectionResetError,
            socket.timeout, url_ex.ReadTimeoutError):
        remove_proxy_from_list_and_update_if_required(proxy)
        logger.info(f'try with proxy {proxy}')
        return get_page(updated_url, session)

Методы для парсера
Искомые данные нужно будет искать по тегам и атрибутам верстки с помощью BeautifulSoup. Мы заранее собрали ключевые слова, которые нас будут интересовать в вакансиях, и подготовили с ними отдельный датасет.

В карточках вакансий нет точной даты публикации, указано лишь сколько дней назад она была опубликована. Сохраним точную дату публикации в традиционном формате с помощью timedelta.

def raw_date_to_str(raw_date):
    raw_date = raw_date.lower()
    if '+' in raw_date or "более" in raw_date:
        delta = timedelta(days=32)
        return (datetime.now() - delta).strftime("%Y-%m-%d")
    else:
        parts = raw_date.split()
        for part in parts:
            if part.isdigit():
                delta = timedelta(days=part.isdigit())
                return (datetime.now() - delta).strftime("%Y-%m-%d")
    return ""

Сохраним id вакансии в системе Indeed. Подставляя id в URL страницы, мы сможем получить доступ к полному описанию вакансий.

def get_job_id_from_card(card):
    try:
        return card['id'].split('_')[1]
    except:
        return ""

Данный метод соберет названия вакансий.

def get_title_from_card(card):
    try:
        job_title = card.find('a', {'class': 'jobtitle'}).text
        return job_title.replace('\n', '')
    except:
        return ''

Аналогичным образом напишем методы, которые будут собирать данные о названии компании, времени публикации объявления, местоположении работодателя и рейтинге работодателя на портале.

URL сайта Indeed пишется для разных стран по-разному. Для США это будет просто indeed.com, а локализации для других стран получают префиксом xx.indeed.com. Список с префиксами мы собрали в массив заранее из https://opensource.indeedeng.io/api-documentation/docs/supported-countries/ списка Indeed.

def get_link_from_card(card, card_country):
    try:
        if card_country == 'us':
            return f"https://indeed.com{card.find('a', {'class': 'jobtitle'})['href']}"
        else:
            return f"https://{card_country}.indeed.com{card.find('a', {'class': 'jobtitle'})['href']}"
    except:
        return ""

Спарсим описание вакансии, которое можно найти по тегу ’summary’. Именно там содержатся требования, которые предъявляют к кандидату.

def get_summary_from_card_and_transform_to_skills(card):
    try:
        smr = card.find('div', {'class': 'summary'}).text
        return get_skills_row(smr)
    except:
        return ""
Необходимые hard-skills из описания вакансий будем сверять со списком 'skills'. 
skills = ["python", "tableau", "etl", "power bi", "d3.js", "qlik", "qlikview", "qliksense",
          "redash", "metabase", "numpy", "pandas", "congos", "superset", "matplotlib", "plotly",
          "airflow", "spark", "luigi", "machine learning", "amplitude", "sql", "nosql", "clickhouse",
          'sas', "hadoop", "pytorch", "tensorflow", "bash", "scala", "git", "aws", "docker",
          "linux", "kafka", "nifi", "ozzie", "ssas", "ssis", "redis", 'olap', ' r ', 'bigquery', 'api', 'excel']

Эта функция разобьет ’summary’ на слова пробелом и проверит их на соответствие нашему списку. В датасет будут возвращаться совпадения с нашим списком hard-skills.

def get_skills_row(summary):
    summary = summary.lower()
    row = []
    for sk in skills:
        if sk in summary:
            row.append(sk)
    return ','.join(row)

На выходе мы получим таблицу с примерно 30 тысячами строк.

Полный код проекта можно посмотреть в нашем репозитории на GitHub.

Нормализация данных через запрос в SQL

Время чтения текста – 8 минут

Главный принцип анализа данных GIGO (от англ. garbage in — garbage out, дословный перевод «мусор на входе — мусор на выходе») говорит нам о том, что ошибки во входных данных всегда приводят к неверным результатам анализа. От того, насколько хорошо подготовлены данные, зависят результаты всей вашей работы.

Например, перед нами стоит задача подготовить выборку для использования в алгоритме машинного обучения (модели k-NN, k-means, логической регрессии и др). Признаки в исходном наборе данных могут быть в разном масштабе, как, например, возраст и рост человека. Это может привести к некорректной работе алгоритма. Такого рода данные нужно предварительно масштабировать.

В данном материале мы рассмотрим способы масштабирования данных через запрос в SQL: масштабирование методом min-max, min-max для произвольного диапазона и z-score нормализация. Для каждого из методов мы подготовили по два примера написания запроса — один с помощью подзапроса SELECT, а второй используя оконную функцию OVER().

Для работы возьмем таблицу students с данными о росте учащихся.

name height
Иван 174
Петр 181
Денис 199
Ксения 158
Сергей 179
Ольга 165
Юлия 152
Кирилл 188
Антон 177
Софья 165

Min-Max масштабирование

Подход min-max масштабирования заключается в том, что данные масштабируются до фиксированного диапазона, который обычно составляет от 0 до 1. В данном случае мы получим все данные в одном масштабе, что исключит влияние выбросов на выводы.

Выполним масштабирование по формуле:

Умножаем числитель на 1.0, чтобы в результате получилось число с плавающей точкой.

SQL-запрос с подзапросом:

SELECT height, 
       1.0 * (height-t1.min_height)/(t1.max_height - t1.min_height) AS scaled_minmax
  FROM students, 
      (SELECT min(height) as min_height, 
              max(height) as max_height 
         FROM students
      ) as t1;

SQL-запрос с оконной функцией:

SELECT height, 
       (height - MIN(height) OVER ()) * 1.0 / (MAX(height) OVER () - MIN(height) OVER ()) AS scaled_minmax
  FROM students;

В результате мы получим переменные в диапазоне [0...1], где за 0 принят рост самого невысокого учащегося, а 1 рост самого высокого.

name height scaled_minmax
Иван 174 0.46809
Петр 181 0.61702
Денис 199 1
Ксения 158 0.12766
Сергей 179 0.57447
Ольга 165 0.2766
Юлия 152 0
Кирилл 188 0.76596
Антон 177 0.53191
Софья 165 0.2766

Масштабирование для заданного диапазона

Вариант min-max нормализации для произвольных значений. Не всегда, когда речь идет о масштабировании данных, диапазон значений находится в промежутке между 0 и 1.
Формула для вычисления в этом случае такая:

Это даст нам возможность масштабировать данные к произвольной шкале. В нашем примере пусть а=10.0, а b=20.0.

SQL-запрос с подзапросом:

SELECT height, 
       ((height - min_height) * (20.0 - 10.0) / (max_height - min_height)) + 10 AS scaled_ab
  FROM students,
      (SELECT MAX(height) as max_height, 
              MIN(height) as min_height
         FROM students  
      ) t1;

SQL-запрос с оконной функцией:

SELECT height, 
       ((height - MIN(height) OVER() ) * (20.0 - 10.0) / (MAX(height) OVER() - MIN(height) OVER())) + 10.0 AS scaled_ab
  FROM students;

Получаем аналогичные результаты, что и в предыдущем методе, но данные распределены в диапазоне от 10 до 20.

name height scaled_ab
Иван 174 14.68085
Петр 181 16.17021
Денис 199 20
Ксения 158 11.2766
Сергей 179 15.74468
Ольга 165 12.76596
Юлия 152 10
Кирилл 188 17.65957
Антон 177 15.31915
Софья 165 12.76596

Нормализация с помощью z-score

В результате z-score нормализации данные будут масштабированы таким образом, чтобы они имели свойства стандартного нормального распределения — среднее (μ) равно 0, а стандартное отклонение (σ) равно 1.

Вычисляется z-score по формуле:

SQL-запрос с подзапросом:

SELECT height, 
       (height - t1.mean) * 1.0 / t1.sigma AS zscore
  FROM students,
      (SELECT AVG(height) AS mean, 
              STDDEV(height) AS sigma
         FROM students
        ) t1;

SQL-запрос с оконной функцией:

SELECT height, 
       (height - AVG(height) OVER()) * 1.0 / STDDEV(height) OVER() AS z-score
  FROM students;

В результате мы сразу заметим выбросы, которые выходят за пределы стандартного отклонения.

name height zscore
Иван 174 0.01488
Петр 181 0.53582
Денис 199 1.87538
Ксения 158 -1.17583
Сергей 179 0.38698
Ольга 165 -0.65489
Юлия 152 -1.62235
Кирилл 188 1.05676
Антон 177 0.23814
Софья 165 -0.65489

Аналитические метрики здорового маркетолога

Время чтения текста – 29 минут

Введение

Сегодня у нас в выпуске лонгрид при поддержке телеграмм-канала Русский маркетинг на тему аналитических метрик в маркетинге. В рамках статьи обсудим для чего нужна маркетинговая аналитика, какими метриками следует оперировать при расчете эффективности маркетинга, как можно структурировать работу по построению маркетинговой отчетности. Коснемся ключевых верхнеуровневых KPI, обсудим популярный фреймворк и разберемся как считать важные аналитические показатели. Статья получилась довольно объемная и в ее содержании используется множество сокращений, поэтому не обошлось и без глоссария.

  • Глоссарий
    • Revenue / Income / Sales — выручка, доход (руб. / $ / евро)
    • GMV (Margin) — маржа (% / руб. )
    • MAU (monthly active users) — уникальное число активных пользователей за месяц (шт.)
    • WAU (weekly active users) — уникальное число активных пользователей за неделю (шт.)
    • DAU (daily active users) — уникальное число активных пользователей за день (шт.)
    • Requests — запросы (за рекламой) (шт.)
    • Impressions — показы (рекламы) (шт.)
    • Clicks — клики (на рекламу) (шт.)
    • FR (fill rate) — заполняемость ( =Impressions / Requests) (%)
    • CTR (click through rate) — кликабельность ( =Clicks / Impressions) (%)
    • С1 (conversion first purchase) — конверсия в первую покупку (%)
    • R, R1, R3, R7 (retention) — удержание (1го, 3го, 7го дня) (%)
    • RR (rolling retention) (%)
    • Churn — отток (%)
    • ARPU (average revenue per user) — средняя выручка на пользователя (руб. / $ / евро)
    • ARPPU (average revenue per paying user) — средняя выручка на платящего пользователя (руб. / $ / евро)
    • cARPU (cumulative average revenue per users) — накопленная средняя выручка на пользователя (руб. / $ / евро)
    • LTV (lifetime value) / CLV (customer lifetime value) — пожизненная ценность клиента
    • ROI (return of investment) — возврат инвестиций (%)
    • ROAS (return on advertising spend) — окупаемость расходов на рекламу (%)
    • ROMI (return of marketing investment) — возврат маркетинговых инвестиций (%)
    • CPA (cost per action) — стоимость действия (напр., покупка или установка приложения) (руб. / $ / евро)
    • CPC (cost per click) — стоимость клика (руб. / $ / евро)
    • CPO (cost per order) — стоимость заказа (руб. / $ / евро)
    • CPS (cost per sale) — стоимость продажи (руб. / $ / евро)
    • CPM (cost per mille) — стоимость тысячи рекламных показов (руб. / $ / евро)
    • CAC (customer acquisition cost) — стоимость привлечения клиента (руб. / $ / евро)
    • CARC (customer acquision and retention cost) — стоимость привлечения и удержания клиента (руб. / $ / евро)
    • ДРР — доля рекламных расходов (%)

Для чего нужна маркетинговая аналитика?

Чтобы разобраться с аналитическими метриками, для начала следует разобраться зачем вообще нужна маркетинговая аналитика и на какие вопросы она может дать ответ. В целом, маркетинговая аналитика — это изучение и измерение в количественных показателях маркетинговой деятельности. При этом чаще всего цель данных действий — оценить эффективность маркетинга, посчитать окупаемость маркетинговых инвестиций в компанию.
Маркетинговая аналитика помогает найти ответы на следующие вопросы:

  • Насколько эффективно расходуется маркетинговый бюджет?
  • Какой ROMI дают разные маркетинговые каналы?
  • Какая целевая аудитория наиболее эффективно конвертируется?
  • Какие каналы коммуникаций наиболее / наименее прибыльны?
  • Что является наибольшим источником дохода компании?

Маркетинговый анализ следует начинать с определения ключевых показателей бизнеса и связей между ними, об этом мы поговорим чуть позже. В целом, работа над построением маркетинговой аналитики больше похожа на создание системы правильных метрик, их планирования, замеров и реагирования на изменения метрик. Более подробно цикл PDCA описан в книжке У. Деминга "Выход из кризиса", рекомендую для ознакомления.

Ключевые принципы построения правильной аналитики в маркетинге

Имея системный подход к анализу данных, влияющих на маркетинговую деятельность, можно помочь маркетологам решить проблему, устранить боль, предоставить рекомендации для дальнейших маркетинговых стратегических шагов. Системный подход подразумевает соблюдение ряда ключевых принципов, без которых аналитика окажется неполноценной.

Компетентность
Задачей маркетингового анализа данных должен заниматься профессионал, разбирающийся в основах математической статистики, эконометрики, разумеется, умеющий считать, интерпретировать результаты и делать выводы актуальные для конкретного бизнеса (понимающий предметную область). Только в таком случае, аналитика сможет дать плоды, в противном случае некорректные выводы из данных могут только усугубить ситуацию, вследствие, чего проийзодет не оптимизация бюджета, а его разорение.

Объективность
Необходимо, решая задачу, рассматривать данные, которые влияют на проблему, с разных сторон. Разные показатели, разная агрегация данных позволит взглянуть на проблему объективно, желательно, чтобы один и тот же вывод из данных, повторялся как минимум дважды.

Актуальность
Изучая сегодняшние проблемы не следует оперировать устарелыми ретроспективными данными, мир очень быстро меняется, равно как и ситуация на рынке / в компании. Анализ, произведенный год назад, может дать сегодня совершенно иные результаты, поэтому необходимо регулярно освежать отчеты и данные, содержащиеся в них.

Интерпретируемость
Результаты анализа должны быть понятны человеку из бизнеса, не знакомому с техническими терминами. В идеале — каждый отчет помогает легко разобраться в проблеме и подталкивает читателя на очевидные выводы. Ситуация, при которой не аналитик вынужден копаться в огромной кучей графиков, непонятных диаграмм и страниц с цифрами без выводов недопустима.

Подобные принципы однозначно помогут нанять компетентных аналитиков для построения корректной отчетности.

Как структурировать показатели?

Систему метрик, помогающих оценивать эффективность маркетинга, можно построить исходя из нескольких соображений. Один из ключевых подходов к структуризации — жизненный цикл клиента. Постараемся разобраться в нем и поговорим об одном из интересных фреймворков для работы над такой системой метрик. В жизненном цикле клиента можно выделить основные этапы:
1) Охват аудитории — работа маркетолога начинается еще до того момента, как потенциальная аудитория становится клиентами компании
2) Вовлечение — этап конверсии зашедших пользователей на сайт / в мобильное приложение в зарегистрированных клиентов
3) Монетизация — этап формирования платящих пользователей (из зарегистрированных)
4) Удержание / Отток — мероприятия направленные на развитие и удержание привлеченной аудитории, снижение уровня оттока

Метод AARRR / Pirate Metrics

В 2007-ом году Дейвом МакКлюром был разработан и предложен метод AARRR — система метрик, помогающая стартапам разобраться в бизнес-показателях. Другое название метода, которое также можно встретить, — "пиратские метрики" из-за того, что название произносится на пиратский лад: "ааррр!".
Итак, разберемся в подходе и поговорим о метриках, соответствующих каждому этапу "воронки". Аббревиатура состоит из 5-ти ключевых маркетинговых этапов:

  • Аcquisition — привлечение (соответствует п. 1 выше)
  • Аctivation — активация (соответствует п. 2 выше)
  • Retention — удержание (соответствует п. 4 выше)
  • Revenue — доход / монетизация (соответствует п. 3 выше)
  • Referral — рекомендации (нововведенный этап)

На входе в воронку располагается целевая аудитория, которую мы хотим привлечь. Затем, всеми силами мы стараемся зарегистрировать потенциального покупателя и превратить его в зарегистрированного клиента (к этому моменту человек, зашедший к нам на сайт / в приложение должен осознавать ценность нашего продукта). После, клиент совершает покупки и возвращается к нам снова и снова. В конечном итоге, если ему очень нравится наш продукт, то он порекомендует его своим друзьям / знакомым.

AARRR-воронка, пиратские метрики (источник изображения)

На каждом уровне воронки необходимо выбрать метрики, описывающие переход из одного состояния в другое, которые мы можем подсчитать и проанализировать. Разберемся последовательно с каждым из этапов и соответствующим ему метриками. Будем изучать каждый этап на примере живых организаций, чтобы расчет показателей был максимально понятен в прикладном смысле.

Привлечение

Охват потенциальных покупателей — ключевой этап формирования новой аудитории. Изучим этот важный этап на примере мобильного приложения Grow Food и каналов привлечения трафика. Зачастую, аудитория попадают в приложение Grow Food из нескольких разных источников:

  1. Органический трафик: поиск в Google, Yandex, Bing, etc
  2. Органический мобильный трафик: поиск в Apple Store / Google Play
  3. Коммерческий трафик: реклама в Facebook / Instagram, контекстная реклама (Adwords), мобильные рекламные сети.

Обсудим на примере рекламы в Facebook. Каждое рекламное объявление таргетируется на потенциальную рекламную аудиторию, которая в терминах Facebook называется "Охват". При этом мы можем оптимизировать показы рекламного объявления по кликам / конверсиям / etc. Наша задача получить максимально эффективную аудиторию за минимальные деньги. Следовательно, нужно выбрать метрики, которые помогут нам оценить эффективность, изучим их:

  • Impressions — количество показов рекламного объявления, сам показатель мало о чем скажет и очень тесно связан с объемом потенциальной аудитории, однако потребуется нам для понимания остальных метрик.
  • Clicks — число кликов на рекламное объявление, в абсолютном выражении, опять же зависит от числа показов.
  • Installs — количество клиентов, установивших мобильное приложение
  • CTR — кликабельность, рассчитывается как отношение Clicks / Impressions и показывает насколько эффективно наше объявление с точки зрения заинтересованности аудитории, другими словами, какова кликабельность нашего объявления
  • CR (conversion rate) (= Installs / Clicks) — уровень конверсии, показывает какой процент пользователей установили приложение из тех, кто кликнул на рекламное объявление
  • Spend — число денег, которые мы потратили на данное рекламное объявление
  • CPC (= Spend / Clicks) — показывает нам стоимость одного клика, оперировать показателем следует в сравнении с другими объявлениями / рыночными бенчмарками
  • CPM (= Spend / Impressions * 1000 ) — показывает нам стоимость тысячи показов рекламного объявления, используется для сравненияи с другими объявлениями / бенчмарками
  • CPI (= Spend / Installs) — удельная стоимость одного инсталла
  • Revenue — итоговый доход, который мы получили с данного рекламного объявления / кампании (необходимо иметь инструменты для правильной атрибуции)
  • ROAS (= Revenue / Spend) — возврат инвестиций в рекламу, валовый доход с потраченного доллара, метрика показывает эффективность рекламной кампании с точки зрения вложенных в нее денег. К примеру, ROAS равный 300% говорит о том, что на каждый потраченный 1$ заработано 3$, а ROAS равный 30%, говорит о том, что на вложенный доллар заработано 30 центов.

Итого, мы уже имеем неплохую палитру метрик, с которыми можно работать — изучать их динамику, сравнивать объявления между собой, между разными источниками трафика. Например, простая табличка, содержащая эти показатели уже будет первым приближением к пониманию эффективности рекламы.

Facebook Campaign Efficiency

Advertisement Spend ($) Installs CPI Impressions CPM Clicks CTR CPC ROAS
Creative Grow Food-1 x x x x x x x x x
Creative Grow Food-2 x x x x x x x x x

Данную таблицу можно перестроить таким образом, чтобы по вертикали оказались даты, а кампания выбиралась из фильтра, тогда мы начнем понимать изменения в динамике ключевых показателей привлечения трафика.

Резюме: мы можем измерять CTR разных баннеров и понимать какой из них интереснее для аудитории. Этот показатель можно использовать при A/B тестировании одного и того же баннера, выбирая наиболее эффективный. При подсчете эффективности помимо CTR следует иметь в виду CPC для того, чтобы выбрать не только наиболее кликабельный баннер, но и не самый дорогой.

Ключевые KPI, показатели эффективности с точки зрения денег — CPI / ROAS, первый показывает насколько дешево / дорого мы покупаем трафик, а второй — насколько хорошо купленный трафик монетизируется.

Активация

Предположим, что мы разрабатываем мобильную игру. Подумаем о том, что может являться активацией пользователя в этом случае? Мы привлекли пользователей, которые установили игру себе на смартфон. Наша следующая задача — зарегистрировать пользователя (сделать его игроком), предложить вводный тур для прохождения.
На этом этапе две метрики можно считать ключевыми: конверсия в зарегистрированного пользователя (= Registrations / Installs), конверсия в прошедших обучение (=Tutorial Users / Installs).

Соответственно, эти две метрики покажут нам: не слишком ли многого мы требуем от пользователя на этапе регистрации или, наоборот, регистрация дается крайне легко? Вторая метрика покажет насколько понятно введение в игру, заинтересованы ли пользователи проходить вводный тур, достаточно ли действий мы требуем от пользователя.

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

Удержание

Любая организация хотела бы, чтобы у нее существовала активная база лояльных клиентов, которые регулярно делают повторные заказы. В этой связи, очень важно отслеживать несколько ключевых метрик: Retention rate (или Rolling retention), Churn. Подробно я разбирал построение retention и rolling retention отчетов в одном из прошлых выпусков блога.

Другой важной фундаментальной метрикой можно считать Sticky Factor — степень вовлеченности пользователей. Sticky Factor за неделю достаточно просто рассчитывается: DAU / WAU * 100%. Разберем, более подробно на прошлом примере. У нас как и прежде есть таблица — client_session, в которой по каждому user_id хранятся таймстемпы активности created_at. Тогда расчет Sticky-фактора довольно несложно выполняется следующим SQL-запросом:

SELECT daily.dau/weekly.wau*100 AS sticky
FROM
-- Считаем среднее DAU за неделю
( SELECT avg(dau) AS dau
FROM
(SELECT from_unixtime(cs.created_at, "yyyy-MM-dd") AS event_date,
ndv(cs.user_id) AS dau
FROM client_session cs
WHERE 1=1
AND from_unixtime(cs.created_at)>=date_add(now(), -7)
AND from_unixtime(cs.created_at)<=now()
GROUP BY 1) d) daily,
-- Считаем WAU за неделю
( SELECT ndv(cs.user_id) AS wau
FROM client_session cs
WHERE 1=1
AND from_unixtime(cs.created_at)>=date_add(now(), -7)
AND from_unixtime(cs.created_at)<=now() ) weekly

Вместе с фундаментальными метриками следует рассматривать метрики, связанные с инструментами удержания клиентской базы. Такими могут являться инструменты директ-маркетинга: sms, email, push-уведомления. У каждого из инструментов обычно бывают такие описательные метрики: число отправленных сообщений / число доставленных сообщений / количество вернувшихся пользователей. Они показывают эффективность каждого из инструментов.

Монетизация

Наконец, мы добрались до ключевой метрики, которая интересвует всех бизнес-пользователей — деньги. Доход, выручка — денежные средства, которые мы получаем от пользователей при покупке нашего продукта. В абсолютном выражении эта метрика (или результат деятельности компании) не очень показательна, хотя важна для понимания текущих трендов.

Чаще всего оперируют рядом относительных метрик, которые описывают поведение пользователей:
ARPU ( = Revenue / Users )— средняя выручка на одного пользователя
cARPU( = cumulative Revenue / Users ) — накопленная средняя выручка на одного пользователя
ARPPU ( = Revenue / Payers ) — средняя выручка на платящего пользователя
Avg Receipt (= Revenue / Purchases ) — средний чек
LTV / CLV — совокупный доход на одного пользователя (жизненная ценность клиента)

Вопросу LTV я планирую посвятить отдельный пост, поскольку это достаточно обширная тема. В данном посте разберем ARPU, накопленный ARPU и связь c LTV. Метрика ARPU покажет нам сколько мы в среднем зарабатываем с пользователя за какой-то период времени (обычно день или неделя). Это полезная информация, но ее может быть недостаточно. Задача эффективного маркетинга — привлекать таких пользователей, которые приносят компании больше денег, чем затрачивается на их привлечение. Таким образом, если мы модифицируем показатель ARPU и рассмотрим накопленный ARPU, например, за 30, 60, 90, 180 дней, то получим неплохое приближение к LTV пользователя. Еще лучше если мы построим кривую накопленного ARPU по дням.

Кривая накопленного ARPU

Добавив горизонтальной линией CPI, мы получим крайне полезный для понимания график. В точке пересечения двух линий мы получим день, начиная с которого доход от пользователя становится выше, чем затраты на его привлечение (привлечение пользователя становится эффективным). В рассматриваемом выше примере это 56-ой день жизни клиента. Решение этой задачи похоже на поиск точки безубыточности, однако надо помнить, что компания также несет и другие косвенные затраты, которые необходимо заложить, чтобы корректно посчитать точку безубыточности.

Рекомендации

Наилучшим сценарием взаимодействия с клиентами и высшей степенью награды для компании можно считать рекомендацию продуктов компании друзьям, родственникам, знакомым. С точки зрения метрик можно выделить: количество активированных приглашенных новых пользователей на одного клиента и NPS.

Количество активированных рекомендаций позволяет увеличить CAC / CPI. К примеру, мы привлекаем пользователя за $1 и хотим сохранить такую тенденцию. Мы разработали механику реферальных ссылок и выявили, что теперь после внедрения средний пользователь приглашает двух других. Получается, что в таком случае стоимость привлечения пользователя составит $1 / 3 = $0.33. Соответственно, мы можем позволить себе привлекать пользователей за $3, сохранив приемлемое для нас значение CAC.

NPS (Net Promote Score) — метрика, которая показывает уровень потребительской лояльности. Механика расчета подробна описана на Википедии, не будем на ней останавливаться. Скажем лишь о том, что рекомендуем регулярно замерять NPS, используя директ-маркетинговые каналы коммуникаций.

Иерархия метрик в организации

Мы достаточно подробно изучили важные метрики каждого этапа AARRR, осталось разобраться каким образом можно структурировать показатели, чтобы получить идеальный дашборд.

Для решения этой задачи имеет смысл декомпозировать цели компании и соответствующие им метрики на разные уровни. Зачастую каждый следующий уровень соответствует отделу компании и является KPI этого отдела. Упрощенно, мы можем представить главную верхнеуровневую цель компании — Прибыль и декомпозировать ее на составные части: Выручка, Расходы.

Иерархия метрик организации

Хороший пример — школа английского языка SkyEng, на видео можно ознакомиться с детально проработанной структурой метрик SkyEng.

Другой альтернативой может стать построение структуры дашборда на основании разобранного выше фреймворка AARRR. Схематично такой дашборд мог бы выглядеть таким образом:

Заключение

Сегодня мы разобрались с ключевыми маркетинговыми метриками, которые помогут отслеживать изменения на каждом этапе маркетинговой воронки, расскажут об эффективности каждого этапа и станут полезным инструментом деятельности маркетолога.

Ссылки по теме:

 2 комментария    2235   2019   Data Analytics   marketing   аналитика   лонгрид