2 Введение в R

2.1 Основы

2.1.1 Типы данных

В R есть несколько типов данных, которые нам будут важны на наших занятиях:

  • числа
5
## [1] 5
8.23
## [1] 8.23
  • строки
"hi"
## [1] "hi"
"тро-ло-ло"
## [1] "тро-ло-ло"
"שלום"
## [1] "שלום"

Важно отметить, что числа также могут быть строкой: "5".

  • логические операторы
TRUE
## [1] TRUE
FALSE
## [1] FALSE
  • пропущенные значения
NA
## [1] NA

Набор значений можно при помощи функции c() объединить в единицу, которая называется вектор:

c(4, 9)
## [1] 4 9
c("first name", "фамилия")
## [1] "first name" "фамилия"

2.1.2 Переменные

Любое значение можно записать в переменную. Для этого используется оператор присваивания =1:

x = 2021
x
## [1] 2021
y = c("имя", "last name")

Переменные можно спользовать в манипуляциях:

x + 3
## [1] 2024

Однако она останется не изменной, пока мы не сделаем новое присваивание:

x
## [1] 2021
x = x + 3
x
## [1] 2024

2.1.3 Функции

Любые действия в R происходят при помощи функций:

x = c(1, 3, 5, 7)
mean(x)
## [1] 4
cumsum(x)
## [1]  1  4  9 16

Используя функцию sqrt() найдите квадратный корень числа 152399025.

2.1.4 Пакеты

Большая часть преимуществ R находится в его пакетах — наборах функций. Сегодня мы будем использовать пакет tidyverse, а завтра пакеты leaflet и leaflet.minicharts. Первое что имеет смысл сделать, это научиться устанавливать пакеты:

install.packages(c("tidyverse", "leaflet", "leaflet.minicharts"))

R может попросить при первой установке выбрать зеркало – это не особенно важно, можете выбрать любое. Перед использованием пакета его нужно включить:

library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
## ✓ ggplot2 3.3.5     ✓ purrr   0.3.4
## ✓ tibble  3.1.5     ✓ dplyr   1.0.7
## ✓ tidyr   1.1.4     ✓ stringr 1.4.0
## ✓ readr   2.0.2     ✓ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()

Пакет выдал какое-то сообщение: такое бывает. Главное чтобы не выдал ошибки.

Если Вы еще не скачали пакет, запустите его скачивание и включите библиотеку tidyverse.

2.1.5 Как получить помощь?

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

?sqrt()

2.2 Введение в tidyverse

В R существуют свои поддиалекты: есть базовый R, есть tidyverse, есть data.table. В этих материалах мы будем работать с tidyverse.

2.2.1 Чтение файлов

Люди придумали достаточно много способов хранить табличные данные (мы будем смотреть только на такие данные). Всем известны таблицы из Excel/LibreOffice/Numbers и самые распространенные форматы .xls и .xlsx, c которыми можно работать в R при помощи пакетов readxl и writexl. На наших занятиях мы рассмотрим более простой формат, с которым предпочитают работать при анализе данных — .csv. Этот формат предполагает использование как машинно-, так и человеко-читаемый формат, в котором значения разделяются некоторым разделителем. Чаще всего в качестве разделителя используют запятую (поэтому .csv расшифровывается как comma separated values). Важным условием для работы является, чтобы значения в одном столбце были одного типа. Первой строчкой в таком формате данных обычно идет название столбцов. Этот формат можно открыть и редактировать в привычном редакторе однако для пользователей Excel это, к сожалению, требует дополнительных операций, а для пользователей Windows еще и нужно непрырывно следить, чтобы была верная кодировка.

df = read_csv("https://tinyurl.com/yzfgony9")
df

В нашем датасете следующие переменные:

  • tombstone_code — код надгробия (BSH0141)
  • place — место (Бешенковичи)
  • tombstone_id — уникальный номер надгробия (141)
  • latitude — широта (55.0455800198435)
  • longitude — долгота (29.4838749171489)
  • last_name — фамилия (Фридман)
  • name — имя (Ицхак Менаше)
  • fathers_name — имя отца (Зув Вольф)
  • gender — гендерная принадлежность (m)
  • year — год смерти (1919)
  • tags — тэги, проставленные разметчиками (юноша)
  • epitaph_language — язык эпитафии (HE)
  • decor_type — тип декора (O — архитектурно-орнаментальный; F — растительный; Z — зооморфный; S — традиционная символика)
  • tombstone_type — тип памятника (M — стела, L — стела с саркофагом, P — саркофаг/плита, O — охель, S — индивидуальной или сложной формы; N — не определен)
  • tombstone_material_code — материал надгробия (S - камень: SS-песчаник, SC - известняк, SG - гранит, SB - габбро-диорит, SL - лабрадорит, SM - мрамор, AS - искусственный камень, M - металл, W - дерево, O - другое)

Считайте даные к себе в RStudio. Сколько строчек из датасета напечатались в консоле при вызове переменной с данными?

2.2.2 Манипуляция с данными

При анализе данных часто нужно сделать несколько операций. Рассмотрим пример:

x = c(5, 7, 3)

cumsum(x)
## [1]  5 12 15
cumsum(sort(x))
## [1]  3  8 15
sort(cumsum(x))
## [1]  5 12 15

Как видно из примера в зависимости от порядка применения функций получается разный результат. Читать длинные цепочки функций не очень удобно, например, при подготовке к нашим занятиям я написал цепочку из 91 операций над датасетом, который мне прислали. В tidyverse очень распространено использование так называемого конвеера (pipe), который передает результат работы одной функции в другую:

x %>% 
  cumsum() %>% 
  sort()
## [1]  5 12 15
x %>% 
  sort() %>% 
  cumsum() 
## [1]  3  8 15

Для знака конвеера есть своя горячая клавиша: Ctrl/Cmd+Shift+M. Конечно, результат можно при желании записать в переменную:

x2 = 
  x %>% 
  sort() %>% 
  cumsum()
x2
## [1]  3  8 15

2.2.2.1 select()

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

df %>% 
  select(tombstone_code, year, gender)

2.2.2.2 arrange()

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

df %>% 
  select(tombstone_code, year, gender) %>% 
  arrange(year)

Измените предыдущий код, чтобы узнать, где захоронен этот самый ранний усопший?

В функции arrange() можно использовать сразу несколько переменных.

2.2.2.3 count()

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

df %>% 
  count()

Но можно также выбрать какую-то переменную или даже комбинацию переменных:

df %>% 
  count(gender)
df %>% 
  count(place, gender)

Узнайте в каком из кладбищ больше стел с саркофагом (переменная tombstone_type значение L).

2.2.2.4 filter()

Функция filter() позволяет отсортировать какие-то значения в переменной:

df %>% 
  count(place, gender) %>% 
  filter(gender == "f")

Несколько условий можно писать через запятую:

df %>% 
  count(place, gender) %>% 
  filter(gender == "f",
         place == "Бешенковичи")

Если все условия выше предполагают равенство ==, то бывает, что нужно отфильтровать ненужное !=:

df %>% 
  count(place, gender) %>% 
  filter(gender != "n",
         place == "Бешенковичи")

2.2.2.5 mutate()

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

df %>% 
  mutate(tombstone_age = 2021 - year) %>% 
  select(tombstone_code, year, tombstone_age)

В одной функции можно создать и несколько переменных.

2.2.2.6 group_by() %>% summarise()

Данная комбинация позволяет создать аналог сводных таблиц в Excel/LibreOffice. Давайте посчитаем средний возраст надгробий в каждом из населенных пунктов:

df %>% 
  mutate(tombstone_age = 2021 - year) %>% 
  group_by(place) %>% 
  summarise(mean_age = mean(tombstone_age, na.rm = TRUE))

Аргумент na.rm = TRUE отвечает за удаление пропущенных значений. Мы могли бы их отфильтровать используя в самом начале команду filter(is.na(year)). Сгруппировать можно и по нескольким переменным:

df %>% 
  mutate(tombstone_age = 2021 - year) %>% 
  group_by(place, gender) %>% 
  summarise(mean_age = mean(tombstone_age, na.rm = TRUE))
## `summarise()` has grouped output by 'place'. You can override using the `.groups` argument.

Схематично операции, которые происходят в ходе комбинации команд group_by() %>% summarise() можно изобразить так:

2.2.2.7 group_by() %>% mutate()

Если group_by() %>% summarise() создает новую сокращенную табличку, то сочетание команд group_by() %>% mutate() позволяет оставлять структуру таблицы нетронутой, что может быть важно, если какие-то из переменных будут потом использоваться.

df %>% 
  mutate(tombstone_age = 2021 - year) %>% 
  group_by(place, gender) %>% 
  mutate(mean_age = mean(tombstone_age, na.rm = TRUE)) %>% 
  select(tombstone_code, place, gender, tombstone_age, mean_age)

Схематично операции, которые происходят в ходе комбинации команд group_by() %>% mutate() можно изобразить так:


  1. Надо сказать, что в R обычно настаивают на использований операторов <- и ->, однако при нашем беглом знакомстве интуитивнее использовать знак равно.↩︎