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

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

install.packages("dplyr")
library(dplyr)

Теперь мы готовы к работе. Загрузим базу с результатами плебисцита в Чили, с которой мы работали на прошлом семинаре.

chile <- read.csv("Chile.csv") 

Основные функции dplyr и оператор %>%

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

sh_chile <- select(chile, sex, age, income, vote)
View(sh_chile) 

Также с помощью select() можем исключить некоторые столбцы, которые нас не интересуют, поставив перед вектором столбцов минус (так же, как и раньше!):

sh_chile2 <- select(chile, -c(X, region, population))
View(sh_chile2)

Столбцы можно выбирать по названиям, если столбцы идут подряд:

head(select(chile, sex:vote)) # столбцы от sex до vote
##   sex age education income statusquo vote
## 1   M  65         P  35000   1.00820    Y
## 2   M  29        PS   7500  -1.29617    N
## 3   F  38         P  15000   1.23072    Y
## 4   F  49         P  35000  -1.03163    N
## 5   F  23         S  35000  -1.10496    N
## 6   F  28         P   7500  -1.04685    N

Если хотим отобрать интересующие нас наблюдения, нам потребуется другая функция - filter(). Отберем, например, респондентов не моложе 45 лет:

old_ch <- filter(chile, age >= 45)
View(old_ch)

А теперь отберем респондентов мужского пола, не моложе 45 лет:

old_ch <- filter(chile, age >= 45 & sex == "F")
View(old_ch)

Казалось бы, зачем использовать библиотеку dplyr, если результаты пока несильно отличаются от того, что мы делали на прошлом занятии без всяких библиотек? На самом деле, смысл использовать ее есть. И сейчас мы переходим к самому интересному.

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

chile %>% View

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

Рассмотрим другой пример. Возьмем базу chile, сначала выберем столбцы sex, age, income и vote, а потом запросим несколько первых строк базы:

chile %>% 
  select(sex, age, income, vote) %>% 
  head
##   sex age income vote
## 1   M  65  35000    Y
## 2   M  29   7500    N
## 3   F  38  15000    Y
## 4   F  49  35000    N
## 5   F  23  35000    N
## 6   F  28   7500    N

В библиотеке dplyr есть несколько других интересных и полезных функций. Например, arrange() – функция, которая сортирует базу данных в соответствии со значениями переменной (или переменных), расположенных по возрастанию (если переменная текстовая, то по алфавиту). Отсортируем базу по показателю statusquo и посмотрим на первые несколько строк:

chile %>% arrange(statusquo) %>% head
##      X region population sex age education income statusquo vote
## 1  788      C     175000   F  64         P     NA  -1.80301    U
## 2 2660      M      25000   M  27         S   7500  -1.74401 <NA>
## 3 2074     SA     250000   F  21        PS  35000  -1.72594    N
## 4 2445     SA     250000   F  42         S  35000  -1.48144 <NA>
## 5 1956     SA     250000   M  27         S   7500  -1.34392    N
## 6  464      C     250000   F  22         S   7500  -1.33198    N

А теперь на последние:

chile %>% arrange(statusquo) %>% tail
##         X region population sex age education income statusquo vote
## 2695 1569      S     125000   F  59         P     NA        NA    Y
## 2696 1774     SA     250000   F  63         P     NA        NA    U
## 2697 1777     SA     250000   M  49      <NA>     NA        NA <NA>
## 2698 1789     SA     250000   F  28        PS  75000        NA    U
## 2699 1988     SA     250000   F  21        PS  35000        NA    A
## 2700 2548     SA     250000   F  42         P  15000        NA    U

Другая полезная функция – mutate() – используется для создания и добавлению в базу данных новой переменной. Создадим переменную log_income – натуральный логарифм дохода респондентов.

chile %>% 
  mutate(log_income = log(income)) %>%
  View

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

View(chile)

Переменной log_income в базе нет! Почему? Дело в том, что когда мы проделываем что-то с базой с помощью dplyr и не сохраняем результат, изменения в самой базе не происходят. Как сохранить изменения? Очень просто: как всегда, сохранить результат в переменную, в которой хранится база:

chile <- chile %>% 
  mutate(log_income = log(income))

Добавлять можно и более одной переменной за раз:

chile <- chile %>% 
  mutate(log_income = log(income), log_population = log(population))
View(chile)

Теперь у нас в базе данных есть две переменные, которые начинаются с log. В dplyr есть функция, которая позволяет выбрать столбцы, названия которых начинаются одинаково.

chile %>% 
  select(starts_with("log_")) %>%
  head 
##   log_income log_population
## 1  10.463103       12.07254
## 2   8.922658       12.07254
## 3   9.615805       12.07254
## 4  10.463103       12.07254
## 5  10.463103       12.07254
## 6   8.922658       12.07254

Чтобы закрепить то, что мы уже успели разобрать, рассмотрим две задачи.

Задача 1. Выбрать строки в базе, для которых значения statusquo не пустые (не NA) в переменной statusquo, выбрать респондентов с доходом свыше 35000, отсортировать строки в базе по возрасту респондентов и посмотреть на базу данных.

Решение.

chile %>% 
  filter(!is.na(statusquo), income > 35000) %>% 
  arrange(age) %>% 
  View

Сначала мы выберем те строки в базе, для которых значения statusquo не пустые (is.na и помним про отриание - восклицательный знак), а заодно выберем респондентов с доходом более 35000. Затем с помощью arrange() отсортируем строки по значениям age. И, наконец, посмотрим на базу данных через View.

Задача 2. Выбрать строки в базе, для которых значения statusquo не пустые (не NA), выбрать тех респондентов, которые голосовали за или против Пиночета (значения ‘Y’ или ‘N’ в vote), выбрать столбцы region, statusquo и vote, а затем вывести на экран первые 10 строк.

chile %>% 
  filter(!is.na(statusquo), vote == "Y",  vote == "N") %>% 
  select(region, statusquo, vote) %>%
  head(10)
## [1] region    statusquo vote     
## <0 rows> (or 0-length row.names)

Функции summarize(), group_by() и tally

Сейчас речь пойдет, пожалуй, о самых полезных функциях dplyr :)

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

chile %>% summarise(total = n())
##   total
## 1  2700

Функция n() универсальна, она используется для подсчета элементов. К ней мы еще вернемся.

Теперь сделаем что-нибудь более интересное. Определим минимальное, максимальное и среднее значение возраста респондентов в этой базе.

chile %>% summarise(avg_age = mean(age), 
                    min_age = min(age), 
                    max_age = max(age))
##   avg_age min_age max_age
## 1      NA      NA      NA

Почему R не хочет ничего считать? Потому что в переменно age есть пропущенные значения! Как справиться с этой проблемой? Самое простое и очевидное – удалить NA из базы. Но это необязательно. У многих функций в R, работающих с переменными, есть параметр na.rm, который позволяет зафиксировать, исключать ли пропущенные значения (rm - remove) при подсчете или нет.

chile %>% summarise(avg_age = mean(age, na.rm = TRUE), 
                    min_age = min(age, na.rm = TRUE), 
                    max_age = max(age,na.rm = TRUE))
##    avg_age min_age max_age
## 1 38.54872      18      70

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

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

chile %>% group_by(region) %>% summarise(count_reg = n())
## # A tibble: 5 x 2
##   region count_reg
##   <fctr>     <int>
## 1      C       600
## 2      M       100
## 3      N       322
## 4      S       718
## 5     SA       960

А теперь посмотрим на средний возраст респондентов из разных регионов:

chile %>% group_by(region) %>% summarise(avg_income = mean(age, na.rm = TRUE))
## # A tibble: 5 x 2
##   region avg_income
##   <fctr>      <dbl>
## 1      C   38.36667
## 2      M   36.66000
## 3      N   38.67702
## 4      S   37.62813
## 5     SA   39.50574

Число наблюдений можно посчитать и по-другому – с помощью функции tally:

chile %>% group_by(sex) %>% summarise(count_sex = n())
## # A tibble: 2 x 2
##      sex count_sex
##   <fctr>     <int>
## 1      F      1379
## 2      M      1321
chile %>% group_by(sex) %>% tally()
## # A tibble: 2 x 2
##      sex     n
##   <fctr> <int>
## 1      F  1379
## 2      M  1321