Знакомство с tidyverse

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

Библиотека tidyverse — огромная библиотека для обработки и визуализации данных, которая состоит сразу из нескольких более маленьких библиотек. Откроем главную страницу tidyverse и зайдем в раздел Packages. Какие составные части есть у tidyverse?

Итак, мы познакомились с основными частями библиотеки tidyverse, теперь самое время ее установить. Воспользуемся функцией install.packages():

install.packages("tidyverse")

Теперь обратимся к библиотеке, чтобы R понимал, откуда брать функции для работы:

library(tidyverse)

Все готово к работе. Загрузим данные из файла CPI2019.csv (его можно найти в материалах к уроку). Этот файл содержит значения индекса восприятия коррупции (Corruption Perception Index) за 2019 год. Чем больше значение индекса, тем свободнее страна от коррупции. Загрузим csv-файл в R (обратите внимание, что разделителем столбцов является точка с запятой):

#setwd("/Users/allat/Desktop")
cpi <- read.csv("CPI2019.csv", sep = ";")

Посмотрим на содержимое файла:

View(cpi)

Пояснения по столбцам:

В библиотеке tidyverse есть особый оператор %>% (pipe operator), который позволяет выполнять операции пошагово, друг за другом. Смысл этого оператора такой: возьми, то, что слева от %>% и передай это на вход функции, стоящей справа от %>%. Посмотрим на простом примере:

cpi %>% View

Взять датафрейм cpi и подать ее на вход функции View. Как можно заметить, во View уже нет ни скобок, ни названия датафрейма, потому что они и не нужны – R и так знает, с чем ему работать. Рассмотрим другой пример. Выберем первые несколько строк в датафрейме cpi и выведем их в отдельном окне в режиме View:

cpi %>% head %>% View

Благодяря оператору %>%, R понимает, что к датафрейму cpi нужно применить функцию head(), а к полученному в head() результату — функцию View(). Таким образом, в одной строке мы «наслаиваем» функции друг на друга, что выглядит компактно и удобно.

Работа с данными с библиотекой tidyverse: часть 1

Для выбора столбцов по названию используется функция select(). Например, выведем на экран столбец country:

cpi %>% select(country) %>% head
##       country
## 1     Denmark
## 2 New Zealand
## 3     Finland
## 4   Singapore
## 5      Sweden
## 6 Switzerland

Если нам нужно выбрать несколько столбцов, их названия необходимо перечислить через запятую в select(), при этом оформлять их в вектор совсем необязательно. Выберем столбцы country и cpi_score и сохраним в маленький датафрейм small1:

small1 <- cpi %>% select(country, cpi_score)
View(small1)

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

# с iso3 по cpi_score
small2 <- cpi %>% select(iso3:cpi_score)
View(small2)

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

small3 <- cpi %>% select(-iso3)
View(small3)

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

small4 <- cpi %>% select(-c(iso3, region))
View(small4)

Если названия у столбцов слишком длинные, и мы не хотим их писать, а хотим выбирать столбцы по номеру, функцию select() также можно использовать:

cpi %>% select(1, 3) %>% head
##       country region
## 1     Denmark  WE/EU
## 2 New Zealand     AP
## 3     Finland  WE/EU
## 4   Singapore     AP
## 5      Sweden  WE/EU
## 6 Switzerland  WE/EU

Итак, мы разобрали различные варианты выбора столбцов. Перейдем к выбору строк. Строки мы чаще всего выбираем по условию или условиям. Для выбора строк по условиям или, другими словами, для построения фильтров, используется функция с говорящим названием filter(). Выберем строки, соответствующие странам со значением индекса больше 80:

cpi %>% filter(cpi_score > 80)
##       country iso3 region cpi_score cpi_rank n_sources
## 1     Denmark  DNK  WE/EU        87        1         8
## 2 New Zealand  NZL     AP        87        1         8
## 3     Finland  FIN  WE/EU        86        3         8
## 4   Singapore  SGP     AP        85        4         9
## 5      Sweden  SWE  WE/EU        85        4         8
## 6 Switzerland  CHE  WE/EU        85        4         7
## 7      Norway  NOR  WE/EU        84        7         7
## 8 Netherlands  NLD  WE/EU        82        8         8

Условие формулируется как обычно и указывается в скобках внутри filter(). Сформулируем более сложное условие — выберем страны со значением индекса более 80 и при этом находящиеся в Западной Европе:

cpi %>% filter(cpi_score > 80 & region == "WE/EU")
##       country iso3 region cpi_score cpi_rank n_sources
## 1     Denmark  DNK  WE/EU        87        1         8
## 2     Finland  FIN  WE/EU        86        3         8
## 3      Sweden  SWE  WE/EU        85        4         8
## 4 Switzerland  CHE  WE/EU        85        4         7
## 5      Norway  NOR  WE/EU        84        7         7
## 6 Netherlands  NLD  WE/EU        82        8         8

Два условия выполняются одновременно, поэтому их мы объединили с помощью оператора &. Однако в filter() эту запись можно упростить, эта функция автоматически объединяет условия, записанные через запятую:

# опускаем & и получаем то же самое
cpi %>% filter(cpi_score > 80, region == "WE/EU")
##       country iso3 region cpi_score cpi_rank n_sources
## 1     Denmark  DNK  WE/EU        87        1         8
## 2     Finland  FIN  WE/EU        86        3         8
## 3      Sweden  SWE  WE/EU        85        4         8
## 4 Switzerland  CHE  WE/EU        85        4         7
## 5      Norway  NOR  WE/EU        84        7         7
## 6 Netherlands  NLD  WE/EU        82        8         8

А вот для условия «или» нам понадобится оператор в явном виде. Выберем строки, соответствующие странам в регионе Западная Европа или Восточная Европа и Центральная Азия:

cpi %>% filter(region == "WE/EU" | region == "ECA")

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

cpi %>% filter(region %in% c("WE/EU", "ECA"))

Базовые случаи использования функций select() и filter() мы обсудили. Но это еще не все. Эти функции можно сочетать с другими полезными функциями tidyverse. Например, с функцией starts_with(), которая позволяет отобрать наблюдения или столбцы, которые начинаются определенным образом. Выберем столбцы, которые начинаются со слова cpi:

cpi %>% select(starts_with("cpi")) %>% head
##   cpi_score cpi_rank
## 1        87        1
## 2        87        1
## 3        86        3
## 4        85        4
## 5        85        4
## 6        85        4

В нашем датафрейме два таких столбца, cpi_score и cpi_rank, они и были выбраны. Если мы запросим help по функции starts_with() [запрашиваем], мы увидим, что по умолчанию аргумент ignore.case равен TRUE. Это означает, что R ищет совпадения вне зависимости от регистра, в независимости от того, большие буквы или маленькие. При желании этот аргумент можно изменить на FALSE.

Аналогичным образом можно воспользоваться функцией ends_with(). Найдем столбец, который заканчивается на score:

cpi %>% select(ends_with("score")) %>% head
##   cpi_score
## 1        87
## 2        87
## 3        86
## 4        85
## 5        85
## 6        85

Если нам не важно, где стоит слово или последовательность символов, в начале, в конце, в середине, мы можем воспользоваться функцией contains(), которая просто проверяет, содержит ли строка другую строку:

cpi %>% select(contains("n_")) %>% head
##   n_sources
## 1         8
## 2         8
## 3         8
## 4         9
## 5         8
## 6         7

При работе со строками пригодится функция str_detect(), которая также проверяет, входит ли указанная строка в другую строку. Например, выберем все страны, названия которых содержат слово Guinea:

cpi %>% filter(str_detect(country, "Guinea"))
##             country iso3 region cpi_score cpi_rank n_sources
## 1            Guinea  GIN    SSA        29      130         8
## 2  Papua New Guinea  PNG     AP        28      137         6
## 3     Guinea Bissau  GNB    SSA        18      168         6
## 4 Equatorial Guinea  GNQ    SSA        16      173         4

Если вы знакомы с регулярными выражениями, их тоже можно использовать в сочетании с функцией str_detect(). Про регулярные выражения в R и tidyverse в частности можно почитать в статьях по ссылкам в дополнительных материалах к уроку.

Работа с данными с библиотекой tidyverse: часть 2

Для добавления нового столбца используется функция mutate(). Например, добавим в датафрейм cpi столбец cpi_perc, который будет содержать значения индекса в шкале от 0 до 1. Чтобы получить такой набор значений, нам нужно поделить столбец cpi_score на 100:

cpi %>% mutate(cpi_perc = cpi_score / 100)

Давайте проверим, добавился ли столбец:

cpi %>% colnames
## [1] "country"   "iso3"      "region"    "cpi_score" "cpi_rank"  "n_sources"

Новый столбец не добавился! Это ожидаемо, поскольку функция mutate() не изменяет исходный датафрейм, а возвращает обновленную копию датафрейма с добавленными столбцами. Чтобы сохранить изменения, нужно записать результат в переменную с тем же названием:

cpi <- cpi %>% mutate(cpi_perc = cpi_score / 100)

Теперь все на месте, функция mutate() добавляет столбец в конец датафрейма:

cpi %>% colnames
## [1] "country"   "iso3"      "region"    "cpi_score" "cpi_rank"  "n_sources"
## [7] "cpi_perc"

Используя mutate(), можно добавлять больше одного столбца за раз. Например, добавим столбец с индексом в шкале от 0 до 1 (у нас такой столбец уже создан, поэтому новый запишется поверх старого) и столбец eu со значениями 0 и 1, где 1 соответствует региону Западная Европа.

cpi <- cpi %>% mutate(cpi_perc = cpi_score / 100, 
                      eu = ifelse(region == "WE/EU", 1, 0))

Проверим:

cpi %>% head
##       country iso3 region cpi_score cpi_rank n_sources cpi_perc eu
## 1     Denmark  DNK  WE/EU        87        1         8     0.87  1
## 2 New Zealand  NZL     AP        87        1         8     0.87  0
## 3     Finland  FIN  WE/EU        86        3         8     0.86  1
## 4   Singapore  SGP     AP        85        4         9     0.85  0
## 5      Sweden  SWE  WE/EU        85        4         8     0.85  1
## 6 Switzerland  CHE  WE/EU        85        4         7     0.85  1

Все записалось.

Если мы хотим добавить новый столбец или новые столбцы в определенное место датафрейма, понадобится другая функция — add_column(). В нее можно добавить аргументы .before или .after, в которых указать, после какого столбца или перед каким столбцом добавить новый столбец или столбцы. Добавим столбец asia перед столбцом eu:

# регион AP или ECA
cpi <- cpi %>% add_column(asia = ifelse(cpi$region %in% c("AP", "ECA"), 1, 0), .before = "eu")

Обратите внимание на точку перед before или перед after, без точки R поймет нас неправильно, и будет считать, что это название нового столбца. Кроме того, название столбца в .before или .after вводится в кавычках, иначе R этот столбец не найдет. Вместо названия столбца можно просто указать номер столбца, уже без кавычек, как обычное целое число. Если опустить аргумент .before или .after, столбец будет записан в конец. И еще одно важное отличие add_column() от mutate(): эта функция не поддерживает выражения, связанные с уже существующими данными, поэтому внутри ifelse() нам пришлось вызывать столбец region через $ вместо того, чтобы просто написать region, как раньше.

Раз можно добавить новый столбец, можно добавить и новую строку. Для этого существует функция add_row(). Внутри этой функции нужно перечислить пары «название столбца-значение в этом столбце», причем перечислять можно в любом порядке. Добавим строку с данными по Люксембургу после третьей строки:

cpi <- cpi %>% add_row(country = "Luxembourg", iso3 = "LUX", region = "WE/EU", 
        cpi_score = 80, cpi_rank = 9, n_sources = NA, 
        eu = 1, asia = 0, .after = 3)
head(cpi)
##       country iso3 region cpi_score cpi_rank n_sources cpi_perc asia eu
## 1     Denmark  DNK  WE/EU        87        1         8     0.87    0  1
## 2 New Zealand  NZL     AP        87        1         8     0.87    1  0
## 3     Finland  FIN  WE/EU        86        3         8     0.86    0  1
## 4  Luxembourg  LUX  WE/EU        80        9        NA       NA    0  1
## 5   Singapore  SGP     AP        85        4         9     0.85    1  0
## 6      Sweden  SWE  WE/EU        85        4         8     0.85    0  1

На добавление новых столбцов и строк мы посмотрели. В завершение урока посмотрим на сортировку строк. Для сортировки используется функция arrange(), и сортировка по умолчанию производится по возрастанию. Упорядочим строки по показателю country, то есть по алфавиту по названию стран и сохраним изменения:

cpi <- cpi %>% arrange(country)

Для сортировки по убыванию нужно добавить функцию desc(), от английского descending order. Упорядочим строки по убыванию в соответствии с показателем cpi_rank:

cpi %>% arrange(desc(cpi_rank)) %>% View

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

cpi %>% arrange(cpi_score, country) %>% View

Для сортировки строк в tidyverse есть еще одна опция — функция top_n(). Эта функция позволяет выбрать первые несколько строк, которые являются топовыми (то есть с самыми большими значения) по некоторому показателю. Для примера выберем топ 10 стран по показателю cpi_score, по индексу восприятия коррупции, и сохраним их в датафрейм top10:

top10 <- cpi %>% top_n(10, cpi_score)
top10
##        country iso3 region cpi_score cpi_rank n_sources cpi_perc asia eu
## 1      Denmark  DNK  WE/EU        87        1         8     0.87    0  1
## 2      Finland  FIN  WE/EU        86        3         8     0.86    0  1
## 3      Germany  DEU  WE/EU        80        9         8     0.80    0  1
## 4   Luxembourg  LUX  WE/EU        80        9        NA       NA    0  1
## 5  Netherlands  NLD  WE/EU        82        8         8     0.82    0  1
## 6  New Zealand  NZL     AP        87        1         8     0.87    1  0
## 7       Norway  NOR  WE/EU        84        7         7     0.84    0  1
## 8    Singapore  SGP     AP        85        4         9     0.85    1  0
## 9       Sweden  SWE  WE/EU        85        4         8     0.85    0  1
## 10 Switzerland  CHE  WE/EU        85        4         7     0.85    0  1

Группировка и агрегирование данных

Сгруппируем строки в датафрейме cpi по показателю region и выведем на экран число стран в каждом регионе. Для группировки воспользуемся функцией group_by(), для подсчета числа строк в каждой группе воспользуемся функцией tally():

cpi %>% group_by(region) %>% tally 
## # A tibble: 6 x 2
##   region     n
##   <chr>  <int>
## 1 AME       32
## 2 AP        31
## 3 ECA       19
## 4 MENA      18
## 5 SSA       49
## 6 WE/EU     31

Функция group_by() создает в R маленькие датафреймы, обработанные в tidyverse, так называемые tibbles, соответствующие каждой группы. А функция tally(), благодаря оператору %>% применяется к каждой группе, то есть к каждому объекту tibble.

Вывод сводной информации по группам можно получить с помощью функции summarise(). Внутри этой функции можно перечислять те характеристики по группам, которые нас интересуют, например, минимум, максимум, среднее или медиану. Для простоты начнем с числа наблюдений в каждой группе, но уже без tally(). Укажем внутри функции summarise() функцию n() для подчета числа строк и поместим эту информацию в столбец N:

cpi %>% group_by(region) %>% summarise(N = n()) 
## `summarise()` ungrouping output (override with `.groups` argument)
## # A tibble: 6 x 2
##   region     N
##   <chr>  <int>
## 1 AME       32
## 2 AP        31
## 3 ECA       19
## 4 MENA      18
## 5 SSA       49
## 6 WE/EU     31

Получилось! Теперь посчитаем среднее значения индекса по каждой группе и его стандартное отклонение — меру разброса значений вокруг среднего:

cpi %>% group_by(region) %>% summarise(N = n(), 
                                       `Mean CPI` = mean(cpi_score),
                                       `Sd CPI` = sd(cpi_score)) 
## `summarise()` ungrouping output (override with `.groups` argument)
## # A tibble: 6 x 4
##   region     N `Mean CPI` `Sd CPI`
##   <chr>  <int>      <dbl>    <dbl>
## 1 AME       32       43.4    16.4 
## 2 AP        31       44.9    20.0 
## 3 ECA       19       34.8     8.54
## 4 MENA      18       39      16.9 
## 5 SSA       49       32.2    12.6 
## 6 WE/EU     31       66.1    14.5

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

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

cpi %>% group_by(region) %>% summarise(N = n(), 
                                       `Mean CPI` = mean(cpi_score),
                                       `Sd CPI` = sd(cpi_score),
                                       `Mean N sources` = mean(n_sources))
## `summarise()` ungrouping output (override with `.groups` argument)
## # A tibble: 6 x 5
##   region     N `Mean CPI` `Sd CPI` `Mean N sources`
##   <chr>  <int>      <dbl>    <dbl>            <dbl>
## 1 AME       32       43.4    16.4              6.38
## 2 AP        31       44.9    20.0              6.94
## 3 ECA       19       34.8     8.54             7.11
## 4 MENA      18       39      16.9              6.61
## 5 SSA       49       32.2    12.6              6.94
## 6 WE/EU     31       66.1    14.5             NA

Среднее число источников посчиталось по каждой группе, кроме Европы. На месте европейского региона стоит NA. Почему? Потому что R не умеет расчитывать среднее числового вектора или столбца, если в нем присутствуют пропущенные значения NA. Это наш случай, так как в уроке ранее мы добавили строку для Люксембурга, и там было пропущено число источников n_sources. Как рассчитать средние значения без потерь? Добавить аргумент na.rm от английского NA remove, чтобы пропущенные значения опускались при подсчете среднего.

cpi %>% group_by(region) %>% summarise(N = n(), 
                                       `Mean CPI` = mean(cpi_score),
                                       `Sd CPI` = sd(cpi_score),
                                       `Mean N sources` = mean(n_sources, na.rm = TRUE))
## `summarise()` ungrouping output (override with `.groups` argument)
## # A tibble: 6 x 5
##   region     N `Mean CPI` `Sd CPI` `Mean N sources`
##   <chr>  <int>      <dbl>    <dbl>            <dbl>
## 1 AME       32       43.4    16.4              6.38
## 2 AP        31       44.9    20.0              6.94
## 3 ECA       19       34.8     8.54             7.11
## 4 MENA      18       39      16.9              6.61
## 5 SSA       49       32.2    12.6              6.94
## 6 WE/EU     31       66.1    14.5              8.37

Теперь все на месте, пропущенное значение в столбце n_sources игнорируется при расчете среднего.

На результаты, полученные с помощью summarise(), можно «наслаивать» новые сводные характеристики по группам. Другими словами, на основе столбцов в summarise() можно получать новые столбцы. Например, для оценки разброса данных, их вариации, часто используется показатель коэффициент вариации, который вычисляется как отношение стандартного отклонения к среднему значению. Воспользуемся функцией mutate() и применим ее после summarise() для того, чтобы поделить значения в Sd CPI на значения в Mean CPI:

cpi %>% group_by(region) %>% summarise(N = n(), 
                                       `Mean CPI` = mean(cpi_score),
                                       `Sd CPI` = sd(cpi_score),
                                       `Mean N sources` = mean(n_sources, na.rm = TRUE)) %>% 
  mutate(CV = `Sd CPI` / `Mean CPI`)
## `summarise()` ungrouping output (override with `.groups` argument)
## # A tibble: 6 x 6
##   region     N `Mean CPI` `Sd CPI` `Mean N sources`    CV
##   <chr>  <int>      <dbl>    <dbl>            <dbl> <dbl>
## 1 AME       32       43.4    16.4              6.38 0.378
## 2 AP        31       44.9    20.0              6.94 0.446
## 3 ECA       19       34.8     8.54             7.11 0.246
## 4 MENA      18       39      16.9              6.61 0.433
## 5 SSA       49       32.2    12.6              6.94 0.392
## 6 WE/EU     31       66.1    14.5              8.37 0.220

Получилось! Коэффициент вариации, взятый по модулю, обычно лежит в интервале от 0 до 1 (хотя может быть и больше 1), и чем ближе значение к 1, тем выше разброс значений, тем более они разнообразные.

Помимо выдачи сводной информации по группам нас может интересовать более широкая задача — применение функций к каждой группе, избегая циклы. Например, мы можем захотеть выгрузить строки, соответствующие каждой группе, в отдельные файлы. Для этого мы можем воспользоваться сочетанием функций group_walk() и write_csv(). Функция group_walk() позволяет применить некоторую функцию к каждой группе. Мы запишем функцию для выгрузки датафреймов в файл с помощью формулы с несколькими аргументами. Аргументом .x в рамках group_walk() обозначается группа строк, над которыми мы проделываем операцию, аргументом .y — таблица с названиями столбцов. Формула начинается с символа ~. Реализуем:

cpi %>% group_by(region) %>% 
  group_walk(~write_csv(.x, paste0(.y$region, ".csv")))

Ставим ~, сообщая R, что впереди указывается формула. Пишем функцию write_csv() для выгрузки в строк файл. На первом месте указываем датафрейм, который выгружаем — строки .x, на втором — название файла, которое мы получаем путем склеивания через paste0() названия региона из столбцов .y и расширения .csv.

Однако при запуске кода выше мы получаем ошибку! R не может найти путь WE/EU.csv. Это ожидаемо, это происходит из-за наличия слэша в названии региона. R считает, что это путь к папке WE и файлу EU.csv. Давайте добавим код для замены этого слэша на знак подчеркивания — воспользуемся функцией str_replace():

cpi %>% group_by(region) %>% 
  group_walk(~write_csv(.x, paste0(str_replace(.y$region, "/", "_"), ".csv")))

Готово! Можем проверить, что файлы созданы и что в них действительно хранятся данные по разным регионам. [Проверяем — открываем пару новых файлов в папке.]

Выгрузка сводной информации о данных

Библиотека stargazer часто используется для выгрузки результатов статистических тестов и моделей, значения в которых сопровождаются звездочками, отмечающими уровень статистической значимости результатов. Из-за этого библиотека имеет такое название stargazer, star – «звезда», gaze – «глазеть». Но эту библиотеку можно использовать и для выгрузки таблиц с обычными описательными статистиками. Установим библиотеку и обратимся к ней:

install.packages("stargazer")
library(stargazer)

Для выгрузки описательных статистик используется функция stargazer(). По умолчанию эта функция формирует выдачу в виде кода на языке разметки LaTeX прямо в консоли. Но если вы не знакомы с LaTeX, не стоит беспокоиться: мы сейчас сделаем так, чтобы R выгружал выдачу в виде файла в формате htm, который легко открывается и редактируется в Word или аналогичных редакторах (Libre Office, Open Office). Попросим stargazer сформировать описательные статистики по датафрейму cpi:

stargazer(cpi, type = "html", out = "summary.htm") 
Statistic N Mean St. Dev. Min Pctl(25) Pctl(75) Max
cpi_score 180 43.167 18.960 9 29 56 87
cpi_rank 180 88.967 51.656 1 44 130 180
n_sources 179 7.061 1.796 3.000 6.000 8.000 10.000
cpi_perc 179 0.430 0.188 0.090 0.290 0.560 0.870
asia 180 0.278 0.449 0 0 1 1
eu 180 0.172 0.379 0 0 0 1

Пропишем тип файла html и укажем название файла summary.htm. В консоли отобразился исходный код выдачи, но он нас не интересует, поскольку в рабочей папке появился файл summary.htm. По умолчанию, как и HTML-страницы, с которыми мы сталкиваемся в интернете, этот файл открывается в браузере. Но при желании всегда можно кликнуть правой клавишей и Открыть с помощью, а затем выбрать Word или иной текстовый редактор. Я выберу Libre Office и открою файл в нем.

В полученной таблице по строкам идут названия числовых показателей, а по столбцам – их характеристики: число заполненных значений (N), среднее (Mean), стандартное отклонение (St.Dev.), минимум (Min), нижний квартиль (Pctl25) и верхний квартиль (Pctl75) и максимум (Max). При желании вид выдачи можно модифицировать. Давайте запросим help и посмотрим на доступные опции.

help(stargazer)

Опций много. Для примера давайте сделаем следующее. Добавим заголовок таблицы (аргумент title), комментарий внизу таблицы (аргумент notes), включим медиану (аргумент median).

stargazer(cpi, type = "html", out = "summary.htm", title = "CPI 2019", notes = "Index by Transparency International", median = TRUE)
CPI 2019
Statistic N Mean St. Dev. Min Pctl(25) Median Pctl(75) Max
cpi_score 180 43.167 18.960 9 29 39.5 56 87
cpi_rank 180 88.967 51.656 1 44 88 130 180
n_sources 179 7.061 1.796 3.000 6.000 7.000 8.000 10.000
cpi_perc 179 0.430 0.188 0.090 0.290 0.390 0.560 0.870
asia 180 0.278 0.449 0 0 0 1 1
eu 180 0.172 0.379 0 0 0 0 1
Index by Transparency International

Проверяем изменения в файле. Отлично, все изменения были учтены!

Тут может возникнуть вопрос: а как выгрузить выдачу, полученную нами с помощью tidyverse? Например, выдачу с описательными статистиками по группам? Очень просто. «Выключить» в stargazer() формирование собственного описания, принятого по умолчанию. Давайте сформируем выдачу со сводной информацией и посмотрим, как это делается.

Воспользуемся выдачей из предыдущего урока и сохраним ее в переменную descr:

descr <- cpi %>% group_by(region) %>% summarise(N = n(),
`Mean CPI` = mean(cpi_score),
`Sd CPI` = sd(cpi_score))
## `summarise()` ungrouping output (override with `.groups` argument)
descr
## # A tibble: 6 x 4
##   region     N `Mean CPI` `Sd CPI`
##   <chr>  <int>      <dbl>    <dbl>
## 1 AME       32       43.4    16.4 
## 2 AP        31       44.9    20.0 
## 3 ECA       19       34.8     8.54
## 4 MENA      18       39      16.9 
## 5 SSA       49       32.2    12.6 
## 6 WE/EU     31       66.1    14.5

Теперь выставим аргумент summary = FALSE и сохраним выдачу в новый файл groups.htm:

stargazer(descr, type = "html", out = "groups.htm", summary = FALSE)
region N Mean CPI Sd CPI
1 AME 32 43.375 16.3800626254268
2 AP 31 44.8709677419355 20.0295480652691
3 ECA 19 34.7894736842105 8.54126550191885
4 MENA 18 39 16.8836851288281
5 SSA 49 32.2448979591837 12.6483375262076
6 WE/EU 31 66.0645161290323 14.5165089556017

Готово! Откроем файл и проверим. Все на месте. Осталось навести красоту – сделать число знаков после запятой равное 2, чтобы избавиться от ненужной в данном случае детализации и привести выдачу в более читаемый вид.

descr <- cpi %>% group_by(region) %>% summarise(N = n(),
`Mean CPI` = round(mean(cpi_score), 2),
`Sd CPI` = round(sd(cpi_score), 2))
## `summarise()` ungrouping output (override with `.groups` argument)
stargazer(descr, type = "html", out = "groups.htm", summary = FALSE)
region N Mean CPI Sd CPI
1 AME 32 43.38 16.38
2 AP 31 44.87 20.03
3 ECA 19 34.79 8.54
4 MENA 18 39 16.88
5 SSA 49 32.24 12.65
6 WE/EU 31 66.06 14.52

Теперь все в порядке.