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

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

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

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

df <- read.csv("http://math-info.hse.ru/f/2018-19/comm-math/marketing.csv")

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

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

df_small <- dplyr::select(df, MarketID, Promotion, SalesInThousands)
#View(df_small) 

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

df_small2 <- dplyr::select(df, -c(Week, LocationID))
#View(df_small2)

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

df_small3 <- dplyr::select(df, AgeOfStore:Week) # с AgeOfStore по Week
#View(df_small3)

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

medium <- filter(df, MarketSize == "Medium") # фирмы среднего размера

Можем прописывать сложные условия, например, выберем фирмы среднего размера, которые находятся на рынке более 5 лет:

df2 <- filter(df, MarketSize == "Medium" & AgeOfStore > 5)

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

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

df %>% View

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

Рассмотрим другой пример. Возьмем базу df, сначала выберем столбцы MarketID, Promotion, и SalesInThousands, а потом запросим несколько первых строк базы:

df %>% select(MarketID, Promotion, SalesInThousands) %>%
  head %>% View

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

df %>% arrange(SalesInThousands) %>% head
##   MarketID MarketSize LocationID AgeOfStore Promotion Week
## 1        6     Medium        507          5         2    2
## 2        6     Medium        506         12         2    4
## 3        1     Medium          6         10         3    2
## 4        1     Medium          5         10         2    4
## 5        6     Medium        507          5         2    4
## 6        1     Medium         10          5         2    3
##   SalesInThousands
## 1            17.34
## 2            19.26
## 3            22.18
## 4            23.35
## 5            23.44
## 6            23.93

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

df %>% arrange(desc(SalesInThousands)) %>% head
##   MarketID MarketSize LocationID AgeOfStore Promotion Week
## 1        3      Large        218          2         1    1
## 2        3      Large        220          3         1    3
## 3        3      Large        209          1         1    4
## 4        3      Large        208          1         3    1
## 5        3      Large        209          1         1    2
## 6        3      Large        216          4         3    1
##   SalesInThousands
## 1            99.65
## 2            99.12
## 3            97.61
## 4            96.48
## 5            96.01
## 6            94.89

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

df %>% mutate(log_sales = log(SalesInThousands))

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

View(df)

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

df <- df %>% mutate(log_sales = log(SalesInThousands))
#View(df)

Добавлять можно и более одной переменной за раз: достаточно перечислить их через запятую внутри mutate().

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

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

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

df %>% summarise(total = n())
##   total
## 1   548

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

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

df %>% summarise(avg_sales = mean(SalesInThousands), 
          min_sales = min(SalesInThousands), 
          max_sales = max(SalesInThousands))
##   avg_sales min_sales max_sales
## 1        NA        NA        NA

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

df %>% summarise(avg_sales = mean(SalesInThousands, na.rm = TRUE), 
          min_sales = min(SalesInThousands, na.rm = TRUE), 
          max_sales = max(SalesInThousands, na.rm = TRUE))
##   avg_sales min_sales max_sales
## 1  53.46596     17.34     99.65

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

df %>% group_by(MarketSize) %>% summarise(count = n())
## # A tibble: 4 x 2
##   MarketSize count
##   <fct>      <int>
## 1 ""             1
## 2 Large        167
## 3 Medium       320
## 4 Small         60

Так как у одной фирмы не указан размер и значение не является полноценным пропущенным (NA), вместо трех групп фирм мы получили четыре. Поправим:

df <- filter(df, MarketSize != "") # удалить строки с "" в MarketSize

df %>% group_by(MarketSize) %>% summarise(count = n())
## # A tibble: 3 x 2
##   MarketSize count
##   <fct>      <int>
## 1 Large        167
## 2 Medium       320
## 3 Small         60

А теперь посмотрим на среднее число продаж разных типов фирм:

df %>% group_by(MarketSize) %>% summarise(avg_sales = mean(SalesInThousands, na.rm = TRUE))
## # A tibble: 3 x 2
##   MarketSize avg_sales
##   <fct>          <dbl>
## 1 Large           70.0
## 2 Medium          44.0
## 3 Small           57.4

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

df %>% group_by(MarketSize) %>% tally()
## # A tibble: 3 x 2
##   MarketSize     n
##   <fct>      <int>
## 1 Large        167
## 2 Medium       320
## 3 Small         60