R для специалиста по контекстной рекламе

про контекстную рекламу, автоматизацию, R

Репортинг / update: сохраняем данные из Яндекс Директа в ClickHouse

Пересмотрел подход в работе с данными.

Сейчас работаю над такой схемой:

  1. R-скрипт выгружает статистику из рекламных аккаунтов 1 раз в день,
  2. данные отправляются в ClickHouse,
  3. скриптами вытаскиваю их из ClickHouse и выгружаю в Google Sheets, Excel или с помощью R Markdown делаю отчеты в html-файлах, которые потом удобно пересылать.

Зачем ClickHouse?

До этого я выгружал статистику по дням с и сохранял с помощью qs (https://cran.r-project.org/web/packages/qs/index.html) или fst (https://cloud.r-project.org/web/packages/fst/index.html). Рабочая схема, но сбор отчетов очень неторопливый. Это мягко говоря. В ClickHouse все грузится молниеносно.

Как и прежде, все работает локально на моем компьютере. Ни на какие сервера данные не загружаю, никому за импорт и аренду сервера не плачу.

Новая схема еще не отработана, поэтому примера скрипта пока не будет.

Выгрузка статистики из нескольких акаунтов

Иногда бывает нужно собрать статистику сразу по нескольким аккаунтам Яндекс Директа. Собирать отдельно — не наш путь. Для выгрузки по всем нужным аккаунтам, воспользуемся таким скриптом:

library(ryandexdirect)
library(tidyverse)
library(writexl)

tokens <- "АДРЕС_ПАПКИ_С_ТОКЕНАМИ"

logins = c(
  "АККАУНТ_1", 
  "АККАУНТ_2", 
  "АККАУНТ_3",
  "АККАУНТ_4",
  "АККАУНТ_5"
)

result <-
  map_df(
    logins, 
    ~
      { yadirGetReport(
        DateRangeType = "LAST_7_DAYS",
        Login = .x,
        FieldNames = c("Clicks","Cost"), 
        IncludeVAT = "YES",
        TokenPath = tokens) %>%  
          mutate(login = .x) }
  )

write_xlsx(result, "result.xlsx")

Здесь мы воспользовались функцией map_df из пакета purrr (входит в tidyverse), чтобы избежать циклов. Готовый результат записали в эксельку.

Смена типа данных по конверсиям и средней позиции показа

В выгрузке статистики из API Директа данные по конверсиям и средней позиции показа выгружаются в текстовом формате.

Чтобы привести их в нормальный числовой формат, использую такой код:

data <- data %>% mutate(across(matches("Conver|AvgImpression"), as.numeric))
data[is.na(data)] <- 0

Не забываем подгружать tidyverse или dplyr

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

Ищем фрод в контекстной рекламе

Выходим на борьбу со скликиванием рекламы

Заголовок кликбейтный! Выводов не будет — просто покажу как мониторить те клики, которые Яндекс считает (или может считать) недействительными и возвращает за них деньги.

В этом, как обычно, нам поможет R.

Форд — больная тема для многих. Рекламодатели страдают от скликивания и теряют много денег. Можно обратиться к сторонним сервисам, которые отсекают такой трафик, а можно просто ничего не делать и довериться Яндексу. Яндекс тоже каким-то образом определяет фрод и потом возвращает деньги за «левые» клики.

А правильно ли Яндекс определяет такие клики?

Давайте обратимся к логам Яндекс Метрики, с помощью пакета rym (в очередной раз говорю спасибо Алексею Селезневу).

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

library(rym)
library(tidyverse)

tidyverse загружаю уже на автомате — тяжело представить, как без него можно что-то делать.

Далее укажем логин и папку с токенами (удобно хранить токены в одной папке — пригодится для других проектов) и номер счетчика Метрики. Если папки нет, то создайте.

login <- "ЛОГИН_МЕТРИКИ"
token <- "АДРЕС_ПАПКИ_С_ТОКЕНАМИ"
counter <- НОМЕР_СЧЕТЧИКА_МЕТРИКИ

Теперь выгружаем данные из Метрики и сохраняем в переменной data:

data <- rym_get_logs(counter = counter,
                         token.path = token,
                         login = login,
                         date.from = "2023-09-01",
                         date.to = "2023-09-07",
                         fields = 
                           "ym:s:visitID,
                           ym:s:lastDirectClickOrder,
                         ym:s:visitDuration",
                         source = "visits")

Вот, что мы выгрузили:
ym:s:visitID — уикальный ID визита;
ym:s:lastDirectClickOrder — номер рекламной кампании — понадобится, чтобы оставить только визиты из cpc;
ym:s:visitDuration — продолжительность визита в секундах.

Создаем новую переменную, где будут только визиты с номером кампании, то есть — из рекламы:

data2 <- data %>% 
  filter(!is.na(ym.s.lastDirectClickOrder))

Теперь посмотрим на графике:

ggplot(data2 %>% filter(ym.s.visitDuration<1000),aes(ym.s.visitDuration))+
  geom_histogram(bins = 500,fill="darkblue")+
  theme_minimal()

Приблизим — уберем длительные визиты:

ggplot(data2 %>% filter(ym.s.visitDuration<30),aes(ym.s.visitDuration))+
  geom_histogram(bins = 75,fill="darkblue")+
  theme_minimal()

Странное распределение визитов. Если отсечь все визиты до 15 секунд, то график бы выглядел более привычным. До 15 секунды количество визитов падает и затем резко растет.

Посмотрим на количество этих коротких визитов:

data2 %>% filter(ym.s.visitDuration<15) %>% nrow()

В моем случае получилось столько:

[1] 13035

Далее идем в кабинет директа и смотрим статистику:

Очень близко. И такая картина видна по другим проектам. О чем это может говорить? Да ни о чем. Просто информация для размышления. Уверен, что внутри логики Яндекса алгоритмы гораздо сложнее.

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

Весь скрипт:

library(rym)
library(tidyverse)


login <- "ЛОГИН_МЕТРИКИ"
token <- "АДРЕС_ПАПКИ_С_ТОКЕНАМИ"
counter <- НОМЕР_СЧЕТЧИКА_МЕТРИКИ

data <- rym_get_logs(counter = counter,
                         token.path = token,
                         login = login,
                         date.from = "2023-09-01",
                         date.to = "2023-09-07",
                         fields = 
                           "ym:s:visitID,
                           ym:s:lastDirectClickOrder,
                         ym:s:visitDuration",
                         source = "visits")

data2 <- data %>% 
  filter(!is.na(ym.s.lastDirectClickOrder))

ggplot(data2 %>% filter(ym.s.visitDuration<30),aes(ym.s.visitDuration))+
  geom_histogram(bins = 75,fill="darkblue")+
  theme_minimal()

data2 %>% filter(ym.s.visitDuration<15) %>% nrow()

Выгрузка объявлений Яндекс.Директа с помощью R

Столкнулся с проблемой, при работе с ryandexdirect. Когда пытаюсь выгрузить группы объявлений или сами объявления с помощью функций yadirGetAdGroups и yadirGetAds на большом аккаунте, работа скрипта длится несколько минут и в итоге заканчивается ошибкой.

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


campaigns <- yadirGetCampaign(Logins = login,TokenPath = token,States = "ON")

ad_groups <-
  map_df(
    campaigns$Id, 
    ~       
      { yadirGetAdGroups(Login = login,TokenPath = token,CampaignIds = .x)}
  )

ads <- 
  map_df(
    campaigns$Id,
    ~
      {yadirGetAds(Login = login,TokenPath = token,CampaignIds = .x)}
  )

Выгрузка конверсий по поисковым запросам из Яндекс.Директа

Рекламные системы, в том числе Яндекс.Директ, позволяют просматривать поисковые запросы, по которым были показаны ваши объявления. Это очень полезная функция. С ее помощью можно искать новые ключевые слова и обновлять список минус-слов.

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

На помощь к нам приходит R и ryandexdirect. Я уже писал как устанавливать RStudio и делать выгрузку по ключевым словам. Теперь попробуем выгрузить поисковые запросы.

# проверяем, установлен ли пакет, если нет - устанавливаем его
if(!'ryandexdirect' %in% rownames(installed.packages())){
  install.packages('ryandexdirect')
}

# подключаем пакет
library(ryandexdirect)

# устанавливаем логин в Директе
login <- "ЛОГИН_В_ДИРЕКТЕ"

# выгружаем статистику
report <- yadirGetReport(ReportType = "SEARCH_QUERY_PERFORMANCE_REPORT",
                         DateFrom = Sys.Date() - 30, # начало даты отчета - 30 дней назад
                         DateTo = Sys.Date() - 1,  # по вчера
                         FieldNames = c("Query",
                                        "Impressions",
                                        "Clicks",
                                        "Cost",
                                        "Conversions"),
                         Goals = c("ID_ЦЕЛИ_В_МЕТРИКЕ_1","ID_ЦЕЛИ_В_МЕТРИКЕ_2"), # указываем id целей
                         Login = login,
                         IncludeVAT = "YES")

# преобразовываем столбцы со 2 по 6 в числовой формат; 
# если бы у нас было 3 цели, 
# то столбцов было бы больше и мы бы указывали их так [, 2:7]
report[, 2:6] <- sapply(report[, 2:6], as.numeric)

# меняем все Na на 0
report[is.na(report)] <- 0

# записываем результат в Excel-файл
writexl::write_xlsx(report, "report.xlsx")

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

К сожалению, Алексей (автор ryandexdirect) отказался от дальнейшей работы над пакетом. Тем не менее поисковые запросы чаще выгружаются нормально — баг достаточно редкий.

Подготовка данных для аналитики контекстной рекламы с помощью R

Привет!

Ранее я писал как сделать простую выгрузку данных из Яндекс.Директа с помощью ryandexdirect и нарисовать график изменения трафика. Теперь давайте выгрузим статистику по ключевым словам для последующего анализа.

Запустим RStudio и проверим установлены ли необходимые библиотеки ryandexdirect и tidyverse. Если нет, то устанавливаем. Следующий код проверяет, устанавливает и загружает библиотеки:

if(!'ryandexdirect' %in% rownames(installed.packages())){
  install.packages('ryandexdirect')
}
if(!'tidyverse' %in% rownames(installed.packages())){
  install.packages('tidyverse')
}

library("ryandexdirect")
library("tidyverse")

Теперь создаем таблицу report, в которую выгружаем данные из Директа:

report <- yadirGetReport(ReportType = "CUSTOM_REPORT",
                          DateFrom = Sys.Date() - 30,
                          DateTo = Sys.Date(),
                          FieldNames = c(
                                         "Criteria",
                                         "CampaignName",
                                         "Impressions",
                                         "Clicks",
                                         "Cost",
                                         "Conversions",
                                         "AvgImpressionPosition"),
                          Goals = c(ID_ЦЕЛИ_В_МЕТРИКЕ),
                          IncludeVAT = "YES",
                          Login = "ВАШ_ЛОГИН_В_ДИРЕКТЕ",
                          FilterList = ("Impressions GREATER_THAN 0"))

В FieldNames мы добавили конверсии (Conversions), поэтому в параметре Goals надо указать какие именно конверсии нас интересуют.

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

Это происходит из-за того, что в этих столбцах данные со строковым типом. Давайте проверим тип данных в наших столбцах:

lapply(report, class)

Все верно, два последних столбца — это не числа, а текст.

С текстом работать не получится. Будем делать преобразование типа данных:

report$AvgImpressionPosition <- as.numeric(report$AvgImpressionPosition)
report$Conversions_ID_ЦЕЛИ_В_МЕТРИКЕ_LSC <- as.numeric(report$Conversions_ID_ЦЕЛИ_В_МЕТРИКЕ_LSC)

в обоих случаях мы скорее всего получим предупреждения:
NAs introduced by coercion

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

При преобразовании в числовой формат мы получаем такое предупреждение. Давайте заменим эти Na на 0:

report[is.na(report)] <- 0

Было

Стало

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

Создадим новую таблицу report_2 и добавим туда новые столбцы:

report_2 <- report %>% 
  mutate(CTR = round((Clicks/Impressions)*100,2),
         CPC = round(Cost/Clicks,2),
         CR = round((Conversions_ID_ЦЕЛИ_В_МЕТРИКЕ_LSC/Clicks)*100,2),
         CPA = round(Cost/Conversions_ID_ЦЕЛИ_В_МЕТРИКЕ_LSC,0))

Наши показатели добавлены в новую таблицу.

Кажется, снова нужно их поправить. Теперь еще и Inf добавился — из-за деления на ноль.
Следующий код поможет нам зачистить эти значения:

is.na(report_2)<-sapply(report_2, is.infinite)
report_2[is.na(report_2)]<-0

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

Построение графиков в R с помощью функции plot

В предыдущем посте мы получили данные из Директа. А что если нам хочется их визуализировать?

Давайте возьмем скрипт из предыдущего поста и потренируемся на нем. Заменим в нашем скрипте периоды отчета: с 7 до 30 дней. Это чтобы график был интереснее.

library(ryandexdirect)
report <- yadirGetReport(ReportType = "CUSTOM_REPORT",
                         DateRangeType = "LAST_30_DAYS",
                         FieldNames = c("Date", "Clicks", "Cost"),
                         Login = "ВАШ_ЛОГИН_В_ДИРЕКТЕ")

Теперь нарисуем график, который отражает изменение трафика по дням. В R особой популярностью пользуется пакет ggplot2, но мы воспользуемся встроенной функцией plot:

plot(report$Date, # столбец с данными для оси x
     report$Clicks, # столбец с данными для оси y
     type = "l", # тип визуализации - линия
     xlab = "Days", # Название оси x
     ylab = "Clicks", # Название оси y
     main = "Clicks from Yandex Direct", # Название графика
     ylim = c(0,4000), # ограничение оси y
     col = "blue", # цвет линии
     lwd = 3) # толщина линии

Каждую строку параметров я подписал. Все, что написано в строке после знака # не воспринимается как код и используется как заметки.

В результате у нас получился такой график, на котором хорошо заметен недельный цикл нашего трафика:

Подробнее о том, как пользоваться функцией plot, можно прочитать тут.

Быстрый способ выгрузки статистики из Яндекс.Директа с помощью R

Давайте представим — вы управляете рекламным кабинетом в Янденс.Директе и каждый день просматриваете отчеты по эффективности рекламы. Можно это делать через веб-интерфейс, воспользоваться Яндекс.Метрикой либо сторонним сервисом аналитики. Но что делать если вы хотите больше контроля и гибкости?

На помощь приходит API Директа, с помощью которого можно выгружать статистику для последующего анализа. Самым простым способом является язык программирования R. Он создан для анализа данных и успел обрасти огромным количеством пакетов, которые позволяют делать очень многое.

Одним из таких пакетов является ryandexdirect. Его создал Алексей Селезнев из агентства Netpeak. К сожалению, Алексей отказался от дальнейшей работы над пакетом, тем не менее ryandexdirect остается самой простой точкой входа в API Директа.

Итак, что же нужно сделать, чтобы начать пользоваться R и выгружать аналитику из рекламного кабинета? Во-первых, нужно установить сам R и RStudio (из Википедии: «RStudio — свободная среда разработки программного обеспечения с открытым исходным кодом для языка программирования R, который предназначен для статистической обработки данных и работы с графикой»).

Скачиваем R и RStudio

После установки RStudio запускаем его.
Перед нами окно программы, в которой мы будем работать. Слева — консоль, справа окна, в которых будет много полезной информации. Слева в меню нажимаем на плюсик и выбираем создание нового файла, а именно R scritp. Появляется блокнот, в котором мы будем писать код.

Давайте попробуем что-нибудь написать и запустить.

a <- 7
b <- 8
c <- a + b
c

мы создали 3 переменные: a, b, c.

<- — это знак присваивания. Мы присвоили переменной a значение 7, а переменной b — 8.
c мы сделали суммой a и b. И в конце вывели полученное значение c. Чтобы запустить код, надо выделить его и нажать на Run либо сочетанием клавиш Ctr + Enter (Cmd + Enter для мака). Запускаем код.
Теперь в окне справа мы можем видеть текущие значения переменных.

Выгрузка данных из Директа

Теперь переходим непосредственно к импорту статистики из Директа.
Во-первых, необходимо установить ryandexdirect. Запускаем такой код:

install.packages("ryandexdirect")

Больше нам эта строчка не понадобится — ryandexdirect установлен в R. Ее можно удалить.

Пишем код для импорта статистики:

library(ryandexdirect)
report <- yadirGetReport(ReportType = "CUSTOM_REPORT",
                         DateRangeType = "LAST_7_DAYS",
                         FieldNames = c("Date", "Clicks", "Cost"),
                         Login = "ВАШ_ЛОГИН_В_ДИРЕКТЕ")

Первая строка кода означает загрузку пакета ryandexdirect. Далее мы создаем переменную report, в которую помещаем наш отчет. Отчет генерируется функцией yadirGetReport. В параметрах мы указываем, что это статистика с произвольными группировками. В FieldNames перечисляем поля нашего отчета.

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

В итоге мы получаем таблицу в 3 столбцами, которые перечислили в FieldNames. В нашем случае это: Дата, Клики, Стоимость. Поля, которые можно использовать в выгрузке, описаны тут. Там же указана и совместимость с типом отчета (в нашем примере — это был «CUSTOM_REPORT»).

Наш отчет содержит данные за 7 дней. Даты отчета можно указывать произвольно. Тогда вместо DateRangeType нужно указывать параметры DateFrom и DateTo. Даты указываются в кавычках в формате ГГГГ-ММ-ДД. Например:

DateFrom = "2022-08-01",
DateTo = "2022-08-07"

Спасибо Алексею за его работу и возможность так удобно выгружать данные из Директа.

Привет!

Меня зовут Артём. Я — специалист по контекстной рекламе. В данный момент работаю руководителем направления контекстной рекламы в СберЗдоровье.

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

Я не программист. Мой код точно можно улучшить, но он работает — я пользуюсь скриптами каждый день. Надеюсь, этот блог будет полезен еще кому-нибудь.

По любым вопросам можно писать мне в Телеграм.