---
title: "Загрузка статистики из рекламного аккаунта Яндекс Директ"
author: "Alexey Seleznev"
output: rmarkdown::html_vignette
date: "`r Sys.Date()`"
vignette: >
  %\VignetteIndexEntry{ryandexdirect: Загрузка статистики из рекламного аккаунта Яндекс Директ}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  eval = FALSE,
  collapse = TRUE,
  comment = "#>"
)
```

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

```{r setup}
library(ryandexdirect)
```

Для загрузки статистики  =в пакете `ryandexdirect` предназначена функция `yadirGetReport`. Данная функция взаимодействует с API 'Сервис Reports', подробно о нём можно узнав в офйициальной [документации](https://yandex.ru/dev/direct/doc/reports/reports-docpage), в текущей виньетке так же используется материал официальной спавки по работе с API сервиса 'Reports'.

## Аргументы функции yadirGetReports

* ReportType - Текстовое значение, тип отчёта. Возможные значения: ACCOUNT_PERFORMANCE_REPORT, CAMPAIGN_PERFORMANCE_REPORT, ADGROUP_PERFORMANCE_REPORT, AD_PERFORMANCE_REPORT, CRITERIA_PERFORMANCE_REPORT, CUSTOM_REPORT, SEARCH_QUERY_PERFORMANCE_REPORT. Более подробно о типах отчёта будет рассказано ниже.
* DateRangeType - Строковое значение, тип временного диапазона. Возможные значения: TODAY, YESTERDAY, LAST_3_DAYS, LAST_5_DAYS, LAST_7_DAYS, LAST_14_DAYS, LAST_30_DAYS, LAST_90_DAYS, LAST_365_DAYS, THIS_WEEK_MON_TODAY ,THIS_WEEK_SUN_TODAY, LAST_WEEK, LAST_BUSINESS_WEEK, LAST_WEEK_SUN_SAT, THIS_MONTH, LAST_MONTH, ALL_TIME, CUSTOM_DATE, AUTO. По умолчанию LAST_30_DAYS.
* DateFrom - Дата начала отчётного периода в формате ГГГГ-ММ-ДД. Аргумент используется только если DateRangeType равен CUSTOM_DATE.
* DateTo - Дата завершение отчётного периода в формате ГГГГ-ММ-ДД. Аргумент используется только если DateRangeType равен CUSTOM_DATE.
* FieldNames - Текстовый вектор содержащий названия полей статистику по которым вы хотите получить. Пример:  `c("Date","CampaignName","Impressions","Clicks")`. Актуальный список полей можно найти по [ссылке](https://yandex.ru/dev/direct/doc/reports/fields-list-docpage).
* FilterList - Текстовый вектор содержащий логические выражения для фильтрации данных. Например `c("Clicks GREATER_THAN 99","Impressions LESS_THAN 1000")`.
* Goals - Целочисленный вектор содержащий идентификаторы целей Яндекс.Метрики по которым вы планируете получить статистики. Пример `c(182453, 182452, 23458860)`. Получить список идентификаторов целей можно с помозью функции `rym_get_goals` входящей в пакет `rym`.
* AttributionModels - Текстовое значение содержащее аббревиатуру названия нужной модели атрибуции для расчёта количества достигнутых целей. Пример ` c("LSC", "LC", "FC")`. Более подробно можно узнать в разделе "Модели атрибуции".
* IncludeVAT - Текстовое значение. Включать ли НДС в денежные суммы в отчете. Возможные вариенты: YES, NO. Влияет на расчёт данных в полях AvgCpc, AvgCpm, Cost, CostPerConversion, а также Profit и Revenue.
* IncludeDiscount - Текстовое значение. Учитывать ли скидку при расчёте денежных данных. Возможные значения: YES, NO.
* FetchBy - Строковое значение. Позволяет разбивать запрос на подзапросы по временному интервалу.
* Login - Текстовый вектор, содержащий логины аккаунтов из которых необходимо получить статистику.
* AgencyAccount - Текстовое значение, логин агентского аккаунта, к которому подключены аккаунты перечисленные в Login.
* TokenPath - Текстовое значение, путь к папке в которой храняться, или будут сохраненны учётные данные для работы с API.
* Token - Текстовое значение или объект полученный с помощью функции `yadirAuth` или `yadirGetToken`. Авториа=зационный токен для работы с API Яндекс.Директ.
* SkipErrors - Логическое значение, используется как правило при загрузке статистики из множества аккаунтов, и позволяет игнорировать ошибки полученные в ходе загрузки данных из некоторых аккаунтов из списка. При этом в консоль будут выводиться сообщения об ошибках.

## Тип отчета
В параметре ReportType укажите тип отчета. Тип отчета влияет на набор доступных полей и группировку данных.

Например, если выбран тип отчета SEARCH_QUERY_PERFORMANCE_REPORT, то данные в отчете будут сгруппированы по идентификатору группы AdGroupId и поисковому запросу Query. Обратите внимание, что добавление группировок данных не приводит к автоматическому добавлению соответствующих полей в отчет: отчет содержит только поля, явным образом перечисленные в параметре FieldNames.

Наиболее общий тип отчета — CUSTOM_REPORT. Он не добавляет никаких дополнительных группировок.

Типы отчетов представлены в таблице.

```{r, eval = TRUE, results = "asis", echo=FALSE}
library(magrittr)
table_report_types <- data.frame(reptype = c("ACCOUNT_PERFORMANCE_REPORT", 
                                             "CAMPAIGN_PERFORMANCE_REPORT", 
                                             "ADGROUP_PERFORMANCE_REPORT",
                                             "AD_PERFORMANCE_REPORT",
                                             "CRITERIA_PERFORMANCE_REPORT",
                                             "CUSTOM_REPORT",
                                             "REACH_AND_FREQUENCY_PERFORMANCE_REPORT",
                                             "SEARCH_QUERY_PERFORMANCE_REPORT"), 
                                 descr    = c("Статистика по аккаунту рекламодателя",
                                              "Статистика по кампаниям",
                                              "Статистика по группам объявлений",
                                              "Статистика по объявлениям",
                                              "Статистика по условиям показа",
                                              "Статистика с произвольными группировками",
                                              "Статистика по медийным кампаниям. Отчет содержит только данные по кампаниям с типом «Медийная кампания», кампании остальных типов игнорируются",
                                              "Статистика по поисковым запросам"),
                                 grouping = c("–", 
                                              "CampaignId", 
                                              "AdGroupId",
                                              "AdId",
                                              "AdGroupId, CriteriaId, CriteriaType",
                                              "–",
                                              "В запросе на формирование отчета необходимо указать в поле FieldNames значение CampaignId", 
                                              "AdGroupId, Query"))

names(table_report_types) <- c("Тип отчёта", "Описание", "Добавляется группировка")
table_report_types <- kableExtra::kable(table_report_types)
kableExtra::kable_styling(table_report_types, bootstrap_options = c("striped", "hover"))
```

Во всех типах отчетов применяется единичная атрибуция (single attribution): каждый показ и клик относится только к одному условию показа, региону, возрасту пользователя и т.д.

## Период отчёта
* TODAY — текущий день;
* YESTERDAY — вчера;
* LAST_3_DAYS, LAST_5_DAYS, LAST_7_DAYS, LAST_14_DAYS, LAST_30_DAYS, LAST_90_DAYS, LAST_365_DAYS — указанное количество предыдущих дней, не включая текущий день;
* THIS_WEEK_MON_TODAY — текущая неделя начиная с понедельника, включая текущий день;
* THIS_WEEK_SUN_TODAY — текущая неделя начиная с воскресенья, включая текущий день;
* LAST_WEEK — прошлая неделя с понедельника по воскресенье;
* LAST_BUSINESS_WEEK — прошлая рабочая неделя с понедельника по пятницу;

![Последняя рабочая неделя](http://img.netpeak.ua/alsey/155897903366_kiss_10kb.png)

* LAST_WEEK_SUN_SAT — прошлая неделя с воскресенья по субботу;
* THIS_MONTH — текущий календарный месяц;
* LAST_MONTH — полный предыдущий календарный месяц;
* ALL_TIME — вся доступная статистика, включая текущий день;
* CUSTOM_DATE — произвольный период. При выборе этого значения необходимо указать даты начала и окончания периода в параметрах DateFrom и DateTo.
* AUTO — период, за который статистика показов и кликов могла измениться. Период выбирается автоматически в зависимости от того, произошла ли в предыдущий день корректировка статистики. 

## Поля отчёта
Полный список допустимых полей можно найти в официальной [документации](https://yandex.ru/dev/direct/doc/reports/fields-list-docpage).

Поля указываются в следующих параметрах отчета:

* FieldNames — поля, которые выводятся в отчете (столбцы);
* Field в структуре Filter — поля, которые используются для фильтрации данных в отчете;
* Field в структуре OrderBy — поля, которые используются для сортировки строк в отчете.

Наборы допустимых полей в этих параметрах различаются. Например, поле *CampaignName* может быть добавлено как столбец в отчете, но не может использоваться для фильтрации данных, а поле *Keyword* — наоборот, используется только для фильтрации данных и в отчете не выводится.

Тип отчета также влияет на набор допустимых полей и их назначение, смотрите таблицу по [ссылке](https://yandex.ru/dev/direct/doc/reports/fields-list-docpage).

Каждое поле в зависимости от выбранного типа отчёта может иметь свой тип:


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

Например, поле *CampaignId* для типа отчета *CUSTOM_REPORT* является сегментом: если его добавить в отчет, данные будут сгруппированы по кампаниям. А для типа отчета *ADGROUP_PERFORMANCE_REPORT* поле *CampaignId* является атрибутом: данные уже сгруппированы по *AdGroupId*, а идентификатор кампании является для каждой группы фиксированным значением.

## Фильтрация данных
Для фильтрации данных в отчете используйте аргумент `FilterList`. Каждый фильтр представляет собой критерий отбора данных. Фильтры объединяются по условию AND: в отчет попадают данные, для которых выполнены все фильтры. Фильтр состоит из трех параметров:

* Field — значение какого поля сравнивается;
* Operator — каким образом сравнивается;
* Values — массив символьных значений, с которыми выполняется сравнение.

Например, чтобы отобрать в отчет строки, в которых количество целевых визитов больше 10, используйте фильтр `FilterList = "Conversions GREATER_THAN 10"`. Для применения нескольких фильтров перечислите их выражения в векторе, например `FilterList = c("Clicks GREATER_THAN 99","Impressions LESS_THAN 1000")` оставит строки в которых более 99 кликов и менее 1000 показов.

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

```{r, eval = TRUE, results = "asis", echo=FALSE}
library(magrittr)
table_report_types <- data.frame(field = c("AdNetworkType, CampaignId, CampaignType", 
                                             "AdFormat, AdGroupId, AdId, Age, AudienceTargetId, CarrierType, ClickType, CriteriaType, CriterionType, Device, DynamicTextAdTargetId, ExternalNetworkName, Gender, LocationOfPresenceId, MatchType, MobilePlatform, Placement, RlAdjustmentId, Slot, SmartBannerFilterId, TargetingLocationId", 
                                             "Clicks, Conversions, ImpressionReach, Impressions",
                                             "AvgClickPosition, AvgCpc, AvgCpm, AvgImpressionFrequency, AvgImpressionPosition, AvgPageviews, AvgTrafficVolume, BounceRate, ConversionRate, Cost, CostPerConversion, Ctr, GoalsRoi, ImpressionShare, Profit, Revenue, WeightedCtr, WeightedImpressions, ",
                                             "Keyword, MatchedKeyword, Query"), 
                                 operators    = c("EQUALS, IN",
                                              "EQUALS, IN, NOT_EQUALS, NOT_IN",
                                              "EQUALS, IN, GREATER_THAN, LESS_THAN",
                                              "GREATER_THAN, LESS_THAN",
                                              "EQUALS, IN, NOT_EQUALS, NOT_IN, STARTS_WITH_IGNORE_CASE, STARTS_WITH_ANY_IGNORE_CASE, DOES_NOT_START_WITH_IGNORE_CASE, DOES_NOT_START_WITH_ALL_IGNORE_CASE"))

names(table_report_types) <- c("Имя поля", "Доступные операторы")
table_report_types <- kableExtra::kable(table_report_types)
kableExtra::kable_styling(table_report_types, bootstrap_options = c("striped", "hover"))
```

Все денежные значения в фильтрах следует указывать в виде целых чисел: сумм в валюте, умноженных на 1 000 000.

## Цели
Вы можете запрашивать количество достижений каждой отдельно взятой цели с помощью аргумента *Goals*.

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

* С помощью пакета `rym` и входящей в него функции `rym_get_goals`;
* В веб интерфейсе Яндекс Метрики: Настройка -> Цели -> Номер цели (в таблице целей).

Если параметр указан, то в отчете вместо полей *ConversionRate*, *Conversions*, *CostPerConversion*, *GoalsRoi* и *Revenue* с агрегированными данными по всем целям будут выведены аналогичные поля с именами вида *<поле>_<id_цели>_<модель_атрибуции>* и данными по каждой цели в отдельности.

## Модели атрибуции
Модель атрибуции — это правило, какой переход считать источником визита:

* **Первый переход** (FC) — источником любых визитов посетителя считается его первый переход на сайт за последние 180 дней. Эта модель позволяет отследить источник рекламы, который впервые привел клиента и тем самым повлиял на все последующие взаимодействия с сайтом.
* **Последний переход** (LC) — источником визита считается переход, в результате которого посетитель в данный момент пришел на сайт, без учета истории визитов. Эта модель может использоваться при техническом анализе сайта. Для оценки эффективности работы рекламных кампании используйте модель Последний значимый переход.
* **Последний значимый переход** (LSC) — все источники переходов за последние 90 дней условно разделяются на значимые (ваши объявления) и незначимые (переходы с сохраненных страниц, внутренние переходы или прямые заходы на сайт). Источником визита считается переход по объявлению. Если визит произошел после незначимого перехода, то его источником считается последний переход по объявлению. Эта модель позволяет учитывать конверсии, которые теряются в модели Последний переход из-за технического ограничения продолжительности визита.
* **Последний переход из Директа** (LYDC) - из всех последних значимых переходов учитывается только Директ. Если пользователь хотя бы раз перешел на сайт по объявлению в Директе, то именно этот переход считается источником всех последующих визитов — пока пользователь не перейдет по объявлению еще раз. Эта модель помогает увидеть все визиты, связанные с Директом, в том числе те, которые в других моделях атрибуции были бы отнесены к другим источникам.

Модели атрибуции, используемые при расчете данных по целям Яндекс.Метрики. Аргумент *AttributionModels* можно указать, только если указан параметр Goals. Если параметр Goals указан, а параметр AttributionModels — нет, по умолчанию используется значение LSC.

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

## FetchBy разбивка запросов по времени
В сервисе 'API Reports' есть недокументированное ограничение на максимальное количество строк которое можно получить в ответе. По умолчанию оно равняется 1 000 000 строк. В большинстве случаев это незначительное ограничение, но при загрузке отчётов из больших аккаунтов с глубокой детализацией, за длительный период скорее всего вы столкнётесь с этой проблемой, и даже её не заметите.

Функция `yadirGetReports` столкнувшись с этим ограничением выведет уведомление `'You have reached the limits of Yandex.Direct API. Try to use "FetchBy" parameter with DateRangeType = "CUSTOM_DATE", "DateFrom" and "DateTo". If you are already using it, try to choose a smaller value.'`.


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

Возможные значения: "DAY", "WEEK", "MONTH", "QUARTER", "YEAR"

Загрузка в таком случае потребует большего времени но вернёт полные данные.

Помимо уведомления, таблица которую вы получите в рзельтате работы функции `yadirGetReports` будет иметь атрибут *limit_reached*. В данном атрибуте хранится список логинов тех аккаунтов по котором был достигнул лимит при загрузке данных. Получить этот список можно с помощью `attr(data, "limit_reached")`, в том случае если объект с полученной статистикой имеет имя *data*, в другом случае `attr(имя_полученного_объекта, "limit_reached")`.

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

1. Создаём результирующий дата фрейм.
2. Внутри цикла `while` запускает сбор статистики из любого колличества аккаунтов. Первый раз без разбивки запроса на временные интервалы.
3. После загрузки данных проверяется атрибут *limit_reached*, на наличие аккаунтов достигших лимита.
4. Из полученной таблицы со статистикой по всем аккаунтам исключаются данные по аккаунтам достигшим лимита.
5. В результирующий фрем дописываются данные по аккаунтам НЕ достигшим лимита.
6. Включаем следующий уровень временной разбивки, рекомедуемая последовательность: МЕСЯЦ -> НЕДЕЛЯ -> ДЕНЬ.
7. Переходим на следующую итерации, запуская сбор статистики из аккаунтов которые без разбивки запроса достигли лимита.

Данный цикл должен работать до тех пор пока не будет выполненно одно из следующих условий:

1. Мы получим данные в которых ни один аккаунт не достигнет лимита, и атрибут *limit_reached* будет пустым.
2. При запуске сбора данных с подневной разбивкой отчёта всё равно будут аккаунты достигшие лимита.

Ниже приведён пример кода реализующего описанный выше механизм.

```{r}
library(ryandexdirect)

# создаём результирующий фрейм
res   <- data.frame()

# список логинов
log_list <- c("login1", "login2","login3", "login4")

# проверка лиситов
# отмечаем что это первый запуск
check <- "first"

# создаём последовательность уровней временной разбивки запросов
fetching_seq <- c("OFF", "MONTH", "WEEK", "DAY")

# счётчик последовательностей разбивки
fetch_id <- 1

# запускаем цикл загрузки данных с проверкой лимитов
while ( ! is.null( log_list ) ) {
  
  # определяем уровень разбивки запроса
  if ( fetching_seq[fetch_id] == "OFF" ) fetching <- NULL else fetching <- fetching_seq[fetch_id]
  
  # запускаем сбор данных
  data <- yadirGetReport(DateRangeType = "CUSTOM_DATE", 
                         DateFrom      = "2018-06-01", 
                         DateTo        = "2019-05-31", 
                         FieldNames    = c("Date","CampaignName","Impressions","Clicks"),
                         Login         = log_list,
                         FetchBy       = fetching)
  
  # если загрузка была по одному аккаунту добавляем его логин
  if ( length(log_list) == 1 ) {
    data$Login <- log_list
  }
  
  # проверяем список аккаунтов достигших лимита
  log_list <- attr(data, "limit_reached")
  
  # выводим список аккаунтов достигших лимита
  print(log_list)
  
  # если есть аккаунты достигшие лимита
  if ( length(log_list) > 0 ) {
    # очищаем от них общую таблицу
    data <- data[ ! data$Login %in% log_list, ]
    # переключаем уровень разбивки на более мелкий
    fetch_id <- fetch_id + 1
  } 
  
  # дописываем в результирующий фрейм данные
  # по тем аккаунтам которые не упёрлись в лимит
  if ( nrow(data) > 0 ) {
    res <- dplyr::bind_rows(res, data)
  }
  
  # проверяем модно ли разбить запрос на более мелкие части
  if ( fetch_id > length(fetching_seq) && length(log_list) > 0 ) {
    message("Запрос невозможно разбить на меньшие части")
    message("Аккаунты которые достигли лимита при загрузке данных по дням: ", paste(log_list, collapse = ", "))
    limits_login <- log_list
    break
  }
}
```

## Аргументы доступа к API Login, AgencyAccount, Token, TokenPath
Все перечисленные в заголовке аргументы используются для авторизации в API, хранении и использовании учётных данных. Более подробно о них можно узнать из виньетке посвящённой процессу авторизации, с помощью `vignette("yandex-direct-auth", package = "ryandexdirect")`.
