Работа с датафреймами с использованием dplyr

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

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

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

Теперь мы готовы к работе. Загрузим файл с результатами плебисцита 1988 года в Чили. Почитать про переменные в таблице можно здесь.

dat <- read.csv("http://math-info.hse.ru/f/2017-18/ps-ms/Chile.csv") 

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

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

small1 <- select(dat, sex, age, income, vote)
View(small1) 

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

small2 <- select(dat, -c(X, region, population))
View(small2)

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

head(select(dat, 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 <- filter(dat, age > 45)
View(old)

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

old_m <- filter(dat, age > 45 & sex == "M")
View(old_m)

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

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

dat %>% View

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

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

dat %>% 
  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 и посмотрим на первые несколько строк:

dat %>% 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

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

dat %>% 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))

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

View(dat)

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

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

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

dat <- dat %>% 
  mutate(log_income = log(income), log_population = log(population))
str(dat)
## 'data.frame':    2700 obs. of  11 variables:
##  $ X             : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ region        : Factor w/ 5 levels "C","M","N","S",..: 3 3 3 3 3 3 3 3 3 3 ...
##  $ population    : int  175000 175000 175000 175000 175000 175000 175000 175000 175000 175000 ...
##  $ sex           : Factor w/ 2 levels "F","M": 2 2 1 1 1 1 2 1 1 2 ...
##  $ age           : int  65 29 38 49 23 28 26 24 41 41 ...
##  $ education     : Factor w/ 3 levels "P","PS","S": 1 2 1 1 3 1 2 3 1 1 ...
##  $ income        : int  35000 7500 15000 35000 35000 7500 35000 15000 15000 15000 ...
##  $ statusquo     : num  1.01 -1.3 1.23 -1.03 -1.1 ...
##  $ vote          : Factor w/ 4 levels "A","N","U","Y": 4 2 4 2 2 2 2 2 3 2 ...
##  $ log_income    : num  10.46 8.92 9.62 10.46 10.46 ...
##  $ log_population: num  12.1 12.1 12.1 12.1 12.1 ...

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

dat %>% 
  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

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

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

Решение.

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

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