Пакет tidyselect - это серверная часть таких функций, как dplyr::select() или dplyr::pull(), а также нескольких глаголов tidyr. Это позволяет создавать глаголы выбора, которые совместимы с другими пакетами tidyverse.
Конечно логичнее было разместить раздел tidyselect в части выборки данных -> Столбцы, но tidyselect имеет гораздо большее значение и может применяться не только в select.
tidyselect поддерживает базовые функции R по выборке:
: для выбора диапазона последовательных переменных.
! для получения дополнения к набору переменных.
& и | для выбора пересечения или объединения двух наборов переменных.
c() для объединения выделений.
Также можно использовать функции помощи в выборке, для конкретных столбцов
everything() - выбирает все столбцы, обычно применяется с другими операторами tidyselect
last_col() - выбирает последнюю переменную
Для выборки столбцов сопоставляя шаблоны в их именах:
starts_with: название столбца начинается с точного префикса
ends_with: название столбца заканчивается на точный суффикс
contains: название столбца содержит символ
matches: название столбца соответствует регулярному выражению
num_range: поиск занумерованных столбцов, например, «V1, V2, V3…»
all_of(): точный поиск по значениям, проверяет наличие значений
any_of(): поиск без проверки наличия значений, используется, чтобы убедиться, что столбец удален
one_of: название столбца соответствует одному из вариантов
where(): условие функции должно быть True
Сделать строки с блоками кода на подобии тех, что использую в соединениях и наглядно показать как работают и чем отличаются функции помощи
Рассмотрим подробнее функции помощи
Функции выбора
everything
everything(vars = NULL) - выбирает все столбцы, обычно применяется с другими операторами tidyselect
vars - Символьный вектор имен переменных. Если не указано, переменные берутся из текущего контекста выбора (как установлено такими функциями, как select() или pivot_longer()).
starwars %>%select(everything())
ABCDEFGHIJ0123456789
name
<chr>
height
<int>
mass
<dbl>
hair_color
<chr>
Luke Skywalker
172
77.0
blond
C-3PO
167
75.0
NA
R2-D2
96
32.0
NA
Darth Vader
202
136.0
none
Leia Organa
150
49.0
brown
Owen Lars
178
120.0
brown, grey
Beru Whitesun lars
165
75.0
brown
R5-D4
97
32.0
NA
Biggs Darklighter
183
84.0
black
Obi-Wan Kenobi
182
77.0
auburn, white
last_col
last_col(offset = 0L, vars = NULL) - выбирает последнюю переменную
offset - устанавливает какое количество столбцов с конца нужно пропустить
starwars %>%select(1:last_col(9))
ABCDEFGHIJ0123456789
name
<chr>
height
<int>
mass
<dbl>
Luke Skywalker
172
77.0
C-3PO
167
75.0
R2-D2
96
32.0
Darth Vader
202
136.0
Leia Organa
150
49.0
Owen Lars
178
120.0
Beru Whitesun lars
165
75.0
R5-D4
97
32.0
Biggs Darklighter
183
84.0
Obi-Wan Kenobi
182
77.0
starwars %>%select(last_col(9))
ABCDEFGHIJ0123456789
skin_color
<chr>
fair
gold
white, blue
white
light
light
light
white, red
light
fair
Функции поиска по шаблону
Аргументы функций поиска по шаблону:
match - Вектор символов. Если длина > 1, берется объединение совпадений. Для starts_with(), ends_with() и contains() это точное совпадение. Для matches() это регулярное выражение и может быть шаблоном stringr.
ignore.case - Если значение по умолчанию равно TRUE, регистр игнорируется при сопоставлении имен
vars - Символьный вектор имен переменных. Если не указано, переменные берутся из текущего контекста выбора (как установлено такими функциями, как select() или pivot_longer()).
range - Последовательность целых чисел, например 1:5
width - Необязательный аргумент, “ширина” числового диапазона. Например, диапазон из 2 дает “01”, диапазон из трех “001” и т.д
starts_with
starts_with() - отбирает те столбцы название которых начинается с точного префикса
starts_with(match, ignore.case = TRUE, vars = NULL)
В функции starts_with() есть возможность задать мульти префикс, в этом случае порядок столбцов будет зависеть от порядка указания префиксов.
# отберем столбцы, название которых начинается на символ «h».starwars %>%select(starts_with("h"))
ABCDEFGHIJ0123456789
height
<int>
hair_color
<chr>
homeworld
<chr>
172
blond
Tatooine
167
NA
Tatooine
96
NA
Naboo
202
none
Tatooine
150
brown
Alderaan
178
brown, grey
Tatooine
165
brown
Tatooine
97
NA
Tatooine
183
black
Tatooine
182
auburn, white
Stewjon
# отберем столбцы, название которых начинается на символы "b" и «h».starwars %>%select(starts_with(c("b", "h")))
ABCDEFGHIJ0123456789
birth_year
<dbl>
height
<int>
hair_color
<chr>
homeworld
<chr>
19.0
172
blond
Tatooine
112.0
167
NA
Tatooine
33.0
96
NA
Naboo
41.9
202
none
Tatooine
19.0
150
brown
Alderaan
52.0
178
brown, grey
Tatooine
47.0
165
brown
Tatooine
NA
97
NA
Tatooine
24.0
183
black
Tatooine
57.0
182
auburn, white
Stewjon
ends_with
ends_with(match, ignore.case = TRUE, vars = NULL) - отбирает те столбцы название которых заканчивается на точный суффикс
В функции ends_with() есть возможность задать мульти суффикс, в этом случае порядок столбцов будет зависеть от порядка указания суффиксов.
# отберем столбцы, название которых заканчивается на слово «color».starwars %>%select(ends_with("color"))
ABCDEFGHIJ0123456789
hair_color
<chr>
skin_color
<chr>
eye_color
<chr>
blond
fair
blue
NA
gold
yellow
NA
white, blue
red
none
white
yellow
brown
light
brown
brown, grey
light
blue
brown
light
blue
NA
white, red
red
black
light
brown
auburn, white
fair
blue-gray
# отберем столбцы, название которых заканчивается на слова "year" и «color».starwars %>%select(ends_with(c("year", "color")))
ABCDEFGHIJ0123456789
birth_year
<dbl>
hair_color
<chr>
skin_color
<chr>
19.0
blond
fair
112.0
NA
gold
33.0
NA
white, blue
41.9
none
white
19.0
brown
light
52.0
brown, grey
light
47.0
brown
light
NA
NA
white, red
24.0
black
light
57.0
auburn, white
fair
contains
contains(match, ignore.case = TRUE, vars = NULL) - отбирает те столбцы название которых содержит в названии символ/ы
В функции contains() есть возможность задать несколько символьных шаблонов, в этом случае порядок столбцов будет зависеть от порядка указания символов.
# отберем столбцы, название которых содержит букву «а».starwars %>%select(contains('a'))
ABCDEFGHIJ0123456789
name
<chr>
mass
<dbl>
Luke Skywalker
77.0
C-3PO
75.0
R2-D2
32.0
Darth Vader
136.0
Leia Organa
49.0
Owen Lars
120.0
Beru Whitesun lars
75.0
R5-D4
32.0
Biggs Darklighter
84.0
Obi-Wan Kenobi
77.0
# отберем столбцы, название которых содержит буквы «m» и "f".starwars %>%select(contains(c('m', 'f')))
ABCDEFGHIJ0123456789
name
<chr>
mass
<dbl>
homeworld
<chr>
Luke Skywalker
77.0
Tatooine
C-3PO
75.0
Tatooine
R2-D2
32.0
Naboo
Darth Vader
136.0
Tatooine
Leia Organa
49.0
Alderaan
Owen Lars
120.0
Tatooine
Beru Whitesun lars
75.0
Tatooine
R5-D4
32.0
Tatooine
Biggs Darklighter
84.0
Tatooine
Obi-Wan Kenobi
77.0
Stewjon
matches
Функции starts_with(), ends_with() и contains() не используют регулярные выражения. Для выбора с помощью регулярного выражения нужно использовать matches()
matches(match, ignore.case = TRUE, perl = FALSE, vars = NULL) - отбирает те столбцы название которых соответствует регулярному выражению
# отберем столбцы, название которых соответствует регулярному выражениюstarwars %>%select(matches('[rne]_color'))
ABCDEFGHIJ0123456789
hair_color
<chr>
skin_color
<chr>
eye_color
<chr>
blond
fair
blue
NA
gold
yellow
NA
white, blue
red
none
white
yellow
brown
light
brown
brown, grey
light
blue
brown
light
blue
NA
white, red
red
black
light
brown
auburn, white
fair
blue-gray
num_range
num_range(prefix, range, suffix = "", width = NULL, vars = NULL) - отбирает те столбцы название которых соответствует префиксу и числовому диапозону
Функции starts_with() и num_range() похожи, только первая ищет по префиксу, то num_range() отбирает по числовому диапозону внутри этого префикса.
Сравним эти функции на фрейме данных billboard, который содержит столбцы одиннаковым префиксом + номер столбца
# отбираем столбцы с префиксом "wk"billboard %>%select(starts_with("wk"))
ABCDEFGHIJ0123456789
wk1
<dbl>
wk2
<dbl>
wk3
<dbl>
wk4
<dbl>
wk5
<dbl>
wk6
<dbl>
wk7
<dbl>
wk8
<dbl>
wk9
<dbl>
87
82
72
77
87
94
99
NA
NA
91
87
92
NA
NA
NA
NA
NA
NA
81
70
68
67
66
57
54
53
51
76
76
72
69
67
65
55
59
62
57
34
25
17
17
31
36
49
53
51
39
34
26
26
19
2
2
3
97
97
96
95
100
NA
NA
NA
NA
84
62
51
41
38
35
35
38
38
59
53
38
28
21
18
16
14
12
76
76
74
69
68
67
61
58
57
# отбираем столбцы с префиксом "wk" и числовым диапозоном от 2 до 5billboard %>%select(num_range("wk", 2:5))
ABCDEFGHIJ0123456789
wk2
<dbl>
wk3
<dbl>
wk4
<dbl>
wk5
<dbl>
82
72
77
87
87
92
NA
NA
70
68
67
66
76
72
69
67
34
25
17
17
39
34
26
26
97
96
95
100
62
51
41
38
53
38
28
21
76
74
69
68
Функции выбора по символьному вектору
all_of
all_of(x) - предназначен для строгого отбора. Если какая-либо из переменных в символьном векторе отсутствует, выдается сообщение об ошибке
var <-c('name', 'mass')starwars %>%select(all_of(var))
ABCDEFGHIJ0123456789
name
<chr>
mass
<dbl>
Luke Skywalker
77.0
C-3PO
75.0
R2-D2
32.0
Darth Vader
136.0
Leia Organa
49.0
Owen Lars
120.0
Beru Whitesun lars
75.0
R5-D4
32.0
Biggs Darklighter
84.0
Obi-Wan Kenobi
77.0
```{r}# Если какая-либо переменная отсутствует во фрейме данных, это ошибкаvar <-c('name', 'mass', 'class')starwars %>%select(all_of(var))# Error in `select()`:# ! Problem while evaluating `all_of(var)`.# Backtrace:# 1. starwars %>% select(all_of(var))# 3. dplyr:::select.data.frame(., all_of(var))# Error in select(., all_of(var)) :```
any_of
any_of(x, ..., vars = NULL) - не проверяет наличие отсутствующих переменных. Это особенно полезно при отрицательном выборе, когда вы хотите убедиться, что переменная удалена
# Проверяем, что столбец отсутствует во фреймеvar <-c('class')starwars %>%select(any_of(var))
ABCDEFGHIJ0123456789
# Удаляем из фрейма столбцы# Даже вызвав одну функцию несколько раз ошибки не будетvar <-c('name', 'mass')starwars %>%select(-any_of(var)) %>%select(-any_of(var))
ABCDEFGHIJ0123456789
height
<int>
hair_color
<chr>
skin_color
<chr>
172
blond
fair
167
NA
gold
96
NA
white, blue
202
none
white
150
brown
light
178
brown, grey
light
165
brown
light
97
NA
white, red
183
black
light
182
auburn, white
fair
Выбор через функцию
where
where(fn) - Применяет функцию ко всем переменным и выбирает те, для которых функция возвращает значение TRUE
Внутри функции можно создавать анонимные функции подобно тем, что создаются в пакете purrr, рассмотрим разные варианты реализации одной и той же логики
# отбираем только числовые столбцыiris %>%select(where(is.numeric))
ABCDEFGHIJ0123456789
Sepal.Length
<dbl>
Sepal.Width
<dbl>
Petal.Length
<dbl>
5.1
3.5
1.4
4.9
3.0
1.4
4.7
3.2
1.3
4.6
3.1
1.5
5.0
3.6
1.4
5.4
3.9
1.7
4.6
3.4
1.4
5.0
3.4
1.5
4.4
2.9
1.4
4.9
3.1
1.5
# отбираем только числовые столбцыiris %>%select(where(function(x) is.numeric(x)))
ABCDEFGHIJ0123456789
Sepal.Length
<dbl>
Sepal.Width
<dbl>
Petal.Length
<dbl>
5.1
3.5
1.4
4.9
3.0
1.4
4.7
3.2
1.3
4.6
3.1
1.5
5.0
3.6
1.4
5.4
3.9
1.7
4.6
3.4
1.4
5.0
3.4
1.5
4.4
2.9
1.4
4.9
3.1
1.5
# отбираем только числовые столбцыiris %>%select(where(~is.numeric(.x)))
ABCDEFGHIJ0123456789
Sepal.Length
<dbl>
Sepal.Width
<dbl>
5.1
3.5
4.9
3.0
4.7
3.2
4.6
3.1
5.0
3.6
5.4
3.9
4.6
3.4
5.0
3.4
4.4
2.9
4.9
3.1
# отбираем только числовые столбцы # у которых стреднее больше 3.5iris %>%select(where(~is.numeric(.x) &&mean(.x) >3.5))
ABCDEFGHIJ0123456789
Sepal.Length
<dbl>
Petal.Length
<dbl>
5.1
1.4
4.9
1.4
4.7
1.3
4.6
1.5
5.0
1.4
5.4
1.7
4.6
1.4
5.0
1.5
4.4
1.4
4.9
1.5
Выборка данных
В R возможно делать выборку столбцов разными стособами. Просто перечислить названия столбцов или их номера, перечислить какие столбцы не нужно выводить или выводить столбцы с именем соответствующим определенному условию.Выбор с использованием tidyselect рассмотрели выше, теперь рассмотрим ещё пару стандартных способов отбора столбцов.
Вернуть вектор
Если нужно вернуть столбец не как таблицу, а вектор, то делаем это через pull
Если нужно указать какой столбец не включать в выборку то ставится знак минус:
starwars %>%select(-c(name, mass))
ABCDEFGHIJ0123456789
height
<int>
hair_color
<chr>
skin_color
<chr>
eye_color
<chr>
172
blond
fair
blue
167
NA
gold
yellow
96
NA
white, blue
red
202
none
white
yellow
150
brown
light
brown
178
brown, grey
light
blue
165
brown
light
blue
97
NA
white, red
red
183
black
light
brown
182
auburn, white
fair
blue-gray
По номерам
Или можно указать номера столбцов
starwars %>%select(1, 2)
ABCDEFGHIJ0123456789
name
<chr>
height
<int>
Luke Skywalker
172
C-3PO
167
R2-D2
96
Darth Vader
202
Leia Organa
150
Owen Lars
178
Beru Whitesun lars
165
R5-D4
97
Biggs Darklighter
183
Obi-Wan Kenobi
182
Упорядочивание столбцов
relocate
relocate(.data, …, .before = NULL, .after = NULL) - смена позиции столбца, использует иснтаксис select(включая tidy-select) чтобы легко перемещать один или несколько столбоц за один раз
.data - указываем, что переместить
.before - перемещение до и указваем столбец или выражение tidy-select
.after - перемещение после и указваем столбец или выражение tidy-select
df <-tibble(a =1, d ="a", b =1, f ="a")df
ABCDEFGHIJ0123456789
a
<dbl>
d
<chr>
b
<dbl>
f
<chr>
1
a
1
a
# ставим стоблец f в началоdf %>%relocate(f)
ABCDEFGHIJ0123456789
f
<chr>
a
<dbl>
d
<chr>
b
<dbl>
a
1
a
1
# ставим стоблец a после ddf %>%relocate(a, .after = d)
ABCDEFGHIJ0123456789
d
<chr>
a
<dbl>
b
<dbl>
f
<chr>
a
1
1
a
# ставим стоблец f перед bdf %>%relocate(f, .before = b)
ABCDEFGHIJ0123456789
a
<dbl>
d
<chr>
f
<chr>
b
<dbl>
1
a
a
1
И ещё несколько вариантов используя tidy-select
# числовые столбцы в конецdf %>%relocate(where(is.numeric), .after =last_col())
ABCDEFGHIJ0123456789
d
<chr>
f
<chr>
a
<dbl>
b
<dbl>
a
a
1
1
# если есть столбцы с такими названиями# то их ставим вначалоdf %>%relocate(any_of(c("a", "e", "i", "o", "u")))
ABCDEFGHIJ0123456789
a
<dbl>
d
<chr>
b
<dbl>
f
<chr>
1
a
1
a
# числовые столбцы после символьныхdf %>%relocate(where(is.numeric), .after =where(is.character))
ABCDEFGHIJ0123456789
d
<chr>
f
<chr>
a
<dbl>
b
<dbl>
a
a
1
1
Строки
Уникальные значения
starwars %>%distinct(sex)
ABCDEFGHIJ0123456789
sex
<chr>
male
none
female
hermaphroditic
NA
Случайные строки
sample_n
Возвращаем n - случайных строк
starwars %>%sample_n(5)
ABCDEFGHIJ0123456789
name
<chr>
height
<int>
mass
<dbl>
hair_color
<chr>
skin_color
<chr>
eye_color
<chr>
Eeth Koth
171
NA
black
brown
brown
Dormé
165
NA
brown
light
brown
Taun We
213
NA
none
grey
black
Poe Dameron
NA
NA
brown
light
brown
Greedo
173
74
NA
green
black
sample_frac
Если нужно указать долю строк из общего числа, которые должны быть в итоговой таблице, то используем sample_frac. Например, при параметре 0.5 вернется половина строк из таблицы, выбранные случайным образом.
starwars %>%sample_frac(0.1)
ABCDEFGHIJ0123456789
name
<chr>
height
<int>
mass
<dbl>
hair_color
<chr>
skin_color
<chr>
Mas Amedda
196
NA
none
blue
Dud Bolt
94
45
none
blue, grey
Shmi Skywalker
163
NA
black
fair
Finn
NA
NA
black
dark
Wicket Systri Warrick
88
20
brown
brown
Chewbacca
228
112
brown
unknown
Obi-Wan Kenobi
182
77
auburn, white
fair
Mace Windu
188
84
none
dark
Jar Jar Binks
196
66
none
orange
Срезы
Функции slice позволяют сделать срез из выборки данных по условию, рассмотрим аргументы функций:
n, prop - задает количество (n) или пропорцию (prop) выбираемых строк, по умолчанию n = 1. Если указано отрицательное значение n или prop, указанное количество или пропорция строк будут удалены. Если n больше, чем количество строк в группе (или prop > 1), результат будет автоматически усечен до размера группы. Если доля размера группы не дает целого числа строк, абсолютное значение prop * nrow(.data) округляется в меньшую сторону.
with_ties - указывает нужно ли включать в выборку дубликаты по выбранному столбцу
weight_by - задает взвешенную случайную выборку фрейма данных т.е. задает вероятность включения каждой строки в результирующее подмножество, которая будет пропорциональна значениям в указанном столбце. Указав вес столбца, можно гарантировать, что более важные строки с большей вероятностью попадут в выборку. Используется когда нужно сделать репрезентативную выборку для исследования.
replace - указывает нужно ли переписывать текущий фрейм, если значение TRUE, то текущий фрейм сразу заменяется результатом выборки, если FALSE, то выборка возвращается как новый фрейм данных, без изменения исходного фрейма.
Создадим набор данных для описания возможностей работы со срезами
Функция slice() позволяет выбирать строки из фрейма данных на основе их положения. Функция принимает два аргумента, первый из которых является фреймом данных, а второй - диапазоном строк для выбора. Диапазон задается с помощью оператора : и может быть одним значением или диапазоном значений.
df %>%slice(1:n())
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
val_x
<dbl>
1
y1
6
2
y2
1
3
y3
3
4
y4
9
5
y5
2
6
y6
7
7
y7
4
8
y8
10
9
y9
5
9
y10
8
df %>%slice(1:4)
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
val_x
<dbl>
1
y1
6
2
y2
1
3
y3
3
4
y4
9
df %>%slice(1L)
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
val_x
<dbl>
1
y1
6
slice_head
slice_head(.data, ..., n, prop)
Функция slice_head() аналогична функции slice(), но выбирает первые n строк фрейма данных. Функция принимает два аргумента, первый из которых является фреймом данных, а второй - количеством строк для выбора.
df %>%slice_head(n =5)
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
val_x
<dbl>
1
y1
6
2
y2
1
3
y3
3
4
y4
9
5
y5
2
df %>%slice_head(prop =0.2)
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
val_x
<dbl>
1
y1
6
2
y2
1
slice_tail
slice_tail(.data, ..., n, prop)
Функция slice_tail() аналогична функции slice(), но выбирает последние n строк фрейма данных. Функция принимает два аргумента, первый из которых является фреймом данных, а второй - количеством строк для выбора.
df %>%slice_tail(n =5)
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
val_x
<dbl>
6
y6
7
7
y7
4
8
y8
10
9
y9
5
9
y10
8
df %>%slice_tail(prop =0.1)
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
val_x
<dbl>
9
y10
8
slice_min
slice_min(.data, order_by, ..., n, prop, with_ties = TRUE)
Функция slice_min() используется для выбора строк с минимальными значениями указанного столбца.
df %>%slice_min(key, n =2)
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
val_x
<dbl>
1
y1
6
2
y2
1
slice_max
slice_max(.data, order_by, ..., n, prop, with_ties = TRUE)
Функция slice_max() используется для выбора строк с максимальными значениями указанного столбца. Функция принимает аргументы, первый из которых является фреймом данных, а второй - столбцом для выбора.
df %>%slice_max(key, n =3)
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
val_x
<dbl>
9
y9
5
9
y10
8
8
y8
10
df %>%slice_max(key, n =1, with_ties = T)
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
val_x
<dbl>
9
y9
5
9
y10
8
df %>%slice_max(key, n =1, with_ties = F)
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
val_x
<dbl>
9
y9
5
slice_sample
slice_sample(.data, ..., n, prop, weight_by = NULL, replace = FALSE)
Функция slice_sample() используется для выбора случайной выборки строк из фрейма данных. Функция принимает аргументы, первый из которых является фреймом данных, а второй - количеством строк для выбора.
df %>%slice_sample(n =4)
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
val_x
<dbl>
9
y9
5
2
y2
1
5
y5
2
6
y6
7
df %>%slice_sample(n =4, weight_by = val_x)
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
val_x
<dbl>
9
y10
8
7
y7
4
4
y4
9
6
y6
7
Фильтрация
По логическому условию
starwars %>%filter(mass >50)
ABCDEFGHIJ0123456789
name
<chr>
height
<int>
mass
<dbl>
hair_color
<chr>
Luke Skywalker
172
77.0
blond
C-3PO
167
75.0
NA
Darth Vader
202
136.0
none
Owen Lars
178
120.0
brown, grey
Beru Whitesun lars
165
75.0
brown
Biggs Darklighter
183
84.0
black
Obi-Wan Kenobi
182
77.0
auburn, white
Anakin Skywalker
188
84.0
blond
Chewbacca
228
112.0
brown
Han Solo
180
80.0
brown
#комбинировать несколько условий можно с помощью & и |:starwars %>%filter(mass >50& height >170)
ABCDEFGHIJ0123456789
name
<chr>
height
<int>
mass
<dbl>
hair_color
<chr>
Luke Skywalker
172
77.0
blond
Darth Vader
202
136.0
none
Owen Lars
178
120.0
brown, grey
Biggs Darklighter
183
84.0
black
Obi-Wan Kenobi
182
77.0
auburn, white
Anakin Skywalker
188
84.0
blond
Chewbacca
228
112.0
brown
Han Solo
180
80.0
brown
Greedo
173
74.0
NA
Jabba Desilijic Tiure
175
1358.0
NA
Конструировать логические условия можно и другими операторами:
Оператор between на самом деле сокращение от следующего условия:
x >= left & x <= right
Чтобы им воспользоваться, нужно указать:
x - переменную по которой надо фильтровать
left - нижнюю границу диапозона
right - верхнюю границу диапозона
Отфильтруем персонажей звездных войн по росту в диапозоне от 100 до 155 сантиметров.
starwars %>%filter(between(height, 100, 155))
ABCDEFGHIJ0123456789
name
<chr>
height
<int>
mass
<dbl>
hair_color
<chr>
skin_color
<chr>
eye_color
<chr>
Leia Organa
150
49
brown
light
brown
Mon Mothma
150
NA
auburn
fair
blue
Watto
137
NA
black
blue, grey
yellow
Sebulba
112
40
none
grey, red
orange
Gasgano
122
NA
none
white, blue
black
near
Оператор near равнозначен оператору сравнения ==, его рекомендуется применять для сравнения чисел в плавающей запятой, из-за возможности указать допуск в точности сравнения.
Допуски в сравнении задаются через атрибут tol с использованием числовых характеристик .Machine, например:
near(x, y, tol = .Machine$double.eps^0.5)
.Machine
.Machine - это переменная, содержащая информацию о числовых характеристиках машины, на которой запущен R, таких как наибольшее двоичное или целое число и точность машины.
Пример использования:
near(sqrt(2) ^2, 2)
[1] TRUE
Сортировка
Для сортировки в языке есть достаточно широкие возможности. Вот самые основные виды сортировки:
По возрастанию
starwars %>%arrange(mass)
ABCDEFGHIJ0123456789
name
<chr>
height
<int>
mass
<dbl>
hair_color
<chr>
Ratts Tyerell
79
15.0
none
Yoda
66
17.0
white
Wicket Systri Warrick
88
20.0
brown
R2-D2
96
32.0
NA
R5-D4
97
32.0
NA
Sebulba
112
40.0
none
Dud Bolt
94
45.0
none
Padmé Amidala
165
45.0
brown
Wat Tambor
193
48.0
none
Sly Moore
178
48.0
none
По убыванию
# сортировка по убываниюstarwars %>%arrange(desc(mass))
ABCDEFGHIJ0123456789
name
<chr>
height
<int>
mass
<dbl>
hair_color
<chr>
Jabba Desilijic Tiure
175
1358.0
NA
Grievous
216
159.0
none
IG-88
200
140.0
none
Darth Vader
202
136.0
none
Tarfful
234
136.0
brown
Owen Lars
178
120.0
brown, grey
Bossk
190
113.0
none
Chewbacca
228
112.0
brown
Jek Tono Porkins
180
110.0
brown
Dexter Jettster
198
102.0
none
По нескольким столбцам
# сортировка по нескольким столбцамstarwars %>%arrange(height, desc(mass))
ABCDEFGHIJ0123456789
name
<chr>
height
<int>
mass
<dbl>
hair_color
<chr>
Yoda
66
17.0
white
Ratts Tyerell
79
15.0
none
Wicket Systri Warrick
88
20.0
brown
Dud Bolt
94
45.0
none
R2-D2
96
32.0
NA
R4-P17
96
NA
none
R5-D4
97
32.0
NA
Sebulba
112
40.0
none
Gasgano
122
NA
none
Watto
137
NA
black
Расширенная сортировка
При сортировке можно использовать вспомогательные функции для select, только внутри функции across
Функция создает новый столбец на основе существующих переменных, а также может изменяет текущий столец (если имена равны) или удалять столбцы (устанавливая их значение равным NULL)
Аргументы:
.by - пока статус в жизненном цикле пакета [Experimental], будет альтернативой group_by()
.before \ .after - указывает место где расположить созданный\измененный столбец, этот агрумент также рассматривался в функции relocate
.keep - указывает какие столбцы останутся в выходных данных после применения функции
all - сохраняет все столбцы из .data, используется по умолчанию
used - сохраняет только столбцы, используемые в функции, чтобы создать новый столбец. Это полезно для проверки работы, так как при этом входные и выходные данные отображаются параллельно
unused - сохраняет только те столбцы, в которые не используется в функции, чтобы создать новые столбцы. Это полезно, если вы создаете новые столбцы, но столбцы, использованные для их создания, больше не нужны
none - сохраняет только группирующие переменные и столбцы созданные с помощью mutate
Рассмотрим простой пример создания нового столбца:
rename(.data, ...) - переименновывает отдельные столбцы
rename_with(.data, .fn, .cols = everything(), ...) - переименновывает несколько столбцов с помощью функции
.cols - использует синтаксис tidy-select
Приведем простые примеры изменения наименований, в первом случае через функцию rename переименуем mass на weight, во втором все имена заканчивающиеся на “…color” сделаем верхним регистром
.cols - столбцы к которым нужно применить функцию, для выбрки доступен tidyselect
.fns - применяемая функция
.names - спецификация имен после применения функции, можно использовать {.col} для обозначения имени выбранного столбца и {.fn} для обозначения имени применяемой функции. По умолчанию “{.col}” для случая с одной функцией и “{.col}_{.fn}” для случая, когда для .fns используется список функций.
Пример с mutate:
Выберем несколько числовых столбцов и применим к ним округление
starwars %>%mutate(across(c(2,3), round) )
ABCDEFGHIJ0123456789
name
<chr>
height
<dbl>
mass
<dbl>
hair_color
<chr>
Luke Skywalker
172
77
blond
C-3PO
167
75
NA
R2-D2
96
32
NA
Darth Vader
202
136
none
Leia Organa
150
49
brown
Owen Lars
178
120
brown, grey
Beru Whitesun lars
165
75
brown
R5-D4
97
32
NA
Biggs Darklighter
183
84
black
Obi-Wan Kenobi
182
77
auburn, white
Пример с summarise:
В этом примере выберем два числовых столбца, применим к ним функции среднего и стандартного отклонения, также зададим спецификацию имен как: “название_столбца.название_функции”
Функции применяют одну и ту же функцию к нескольким столбцам и объединяют результаты в единый логический вектор
if_any(.cols, .fns, ..., .names = NULL) - имеет значение TRUE, когда предикат имеет значение TRUE для любого из выбранных столбцов
if_all(.cols, .fns, ..., .names = NULL) - имеет значение TRUE, когда предикат имеет значение TRUE для всех выбранных столбцов
Выполним три запроса: - базовый запрос, чтобы сформировать первоначальную выборку - второй запрос в котором применим функцию if_any - третий запрос в котором применим функцию if_all
Для обоих функций условия будут идентичные: во всех столбцах с типом double отбираем строки со значениями меньше 40.
Если вы привыкли писать код на SQL, то при упониминании оконной функции в голове возникает следующая модель:
```{sql}Select* ,SUM(col_1) # любая агрегатная функция OVER ( # ключевое слово описания окна PARTITION BY col_2 # формируем группыORDERBY col_3 # сортируем данные внутри группы RANGE | ROWS | GROUPS UNBOUNDED PRECEDING # задаем начало и конец рамки окна )Fromtable```
Переходя на R нужно переключиться на другие концепции, но постоянно будут возникать вопросы, наподобии: понятно как это сделать на SQL, но как это реализовать в концепции языка R?
Попробуем разобраться как переложить на концепцию на синтаксис языка R.
Для этого нужно перевести набор данных во временную таблицу, как будто это таблица из базы данных. У такого преобразования есть особенности, перевести можно набор данных, который содержит столбцы с поддерживаемыми типами данных в базе данных.
Поэтому неполучится перевести во временную таблицу набор starwars как есть из-за того, что он содержит тип list, сначала исключим из выборки столбцы с данным типом и преобразуем набор:
<SQL>
SELECT *
FROM `starwars_db`
WHERE (`species` = 'Human')
ORDER BY `mass`
Функция show_query поможет проверить запрос в более привычном виде если это необходимо.
Формирование окна функции
Хотя функции dplyr обеспечивают больший функционал оконных функций, однако бывает необходимость выполнить более изощеренный сценарий, для таких случаев можно воспользоваться backend пакетом dbplyr.
А имено функциями:
window_order - задает сортировку, можно пользоваться привычным arrange
<SQL>
SELECT
*,
SUM(`mass`) OVER (PARTITION BY `homeworld` ORDER BY `height` ROWS 2 PRECEDING) AS `s`
FROM (
SELECT
*,
AVG(`height`) OVER (PARTITION BY `gender` ORDER BY `mass` ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING) AS `z`
FROM `starwars_db`
)
Далее рассмотрим функции предоставляемые пакетом dplyr
Offset
Функции позволяющие расчитать смещение по строкам
Аргументы функций
x - вектор, который будем перебирать
n - положительное число, задающее смещение относительно текущей строки, по умолчанию единица
default - если при смещении не найдено значение, то по умолчанию ставится Null, можно задать своё значение
order_by - необязательное условие, сортировки вектора по дополнительному вектору, после применения смещения, т.е. сначала применили смещение, а потом отсортировали результат
starwars %>%select(1:3) %>%slice(1:10) %>%mutate(name_lag =lead(name),name_lag2 =lead(name, n =2),name_lag3 =lead(name, n =3, default ='Frodo'),name_lag4 =lead(name, n =3, order_by = mass) )
ABCDEFGHIJ0123456789
name
<chr>
height
<int>
mass
<dbl>
name_lag
<chr>
Luke Skywalker
172
77
C-3PO
C-3PO
167
75
R2-D2
R2-D2
96
32
Darth Vader
Darth Vader
202
136
Leia Organa
Leia Organa
150
49
Owen Lars
Owen Lars
178
120
Beru Whitesun lars
Beru Whitesun lars
165
75
R5-D4
R5-D4
97
32
Biggs Darklighter
Biggs Darklighter
183
84
Obi-Wan Kenobi
Obi-Wan Kenobi
182
77
NA
Cumulative
cumall | cumany
Функции создают логические вектора с накопительным эффектом, т.е. до первого события
Как интерпретировать функции:
cum all(x): все случаи до первого FALSE
cumall(!x): все случаи до первого значения TRUE
cumany(x) : все случаи после первого TRUE
cumany(!x): все случаи после первого FALSE
Применение этих функций полезно с сочетании с фильтром, для того чтобы разделить выборку на до и после какого-то события и оставить либо часть, которая была ДО или часть после
Функция percent_rank подсчитывает общее количество значений, меньших, чем x_i, и делит его на количество наблюдений минус 1
Рассмотрим пример по строчно:
x = 1 - количество значений меньших чем x_i (x_i = 1) равно 0, отсюда 0 / 4 (5-1) = 0.00
x = 3 - количество значений меньших чем x_i (x_i = 3) равно 3, отсюда 3 / 4 (5-1) = 0.75
x = 5 - количество значений меньших чем x_i (x_i = 5) равно 4, отсюда 4 / 4 (5-1) = 1.00
x = 2 - количество значений меньших чем x_i (x_i = 2) равно 1, отсюда 1 / 4 (5-1) = 0.25
df %>%mutate(percent_rank =percent_rank(x))
ABCDEFGHIJ0123456789
x
<dbl>
percent_rank
<dbl>
1
0.00
3
0.75
5
1.00
2
0.25
2
0.25
row_number
Функция row_number присваивает каждой строке уникальный ранг
df %>%mutate(row_number =row_number(x))
ABCDEFGHIJ0123456789
x
<dbl>
row_number
<int>
1
1
3
4
5
5
2
2
2
3
min_rank
Функция min_rank присваивает каждой строке наименьший ранг, в зависимости от значения в строке
df %>%mutate(min_rank =min_rank(x))
ABCDEFGHIJ0123456789
x
<dbl>
min_rank
<int>
1
1
3
4
5
5
2
2
2
2
dense_rank
Функция dense_rank работает как функция min_rank т.е. присваивает каждой строке наименьший ранг, в зависимости от значения в строке, но не делает пропусков в рангах
df %>%mutate(dense_rank =dense_rank(x))
ABCDEFGHIJ0123456789
x
<dbl>
dense_rank
<int>
1
1
3
3
5
4
2
2
2
2
ntile
Функция ntile присваивает каждой строке ранг, разбивая входной вектор на n сегментов. В отличие от других функций ранжирования, ntile() игнорирует связи: она создаст сегменты одинакового размера, даже если одно и то же значение x окажется в разных сегментах.
df %>%mutate(ntile =ntile(x, 2))
ABCDEFGHIJ0123456789
x
<dbl>
ntile
<int>
1
1
3
2
5
2
2
1
2
1
Агрегатные функции
summarise
Функция summarise создает новый фрейм данных. Он возвращает по одной строке для каждой комбинации группирующих переменных; если группирующих переменных нет, в выходных данных будет одна строка, суммирующая все наблюдения во входных данных. Он будет содержать по одному столбцу для каждой группирующей переменной и по одному столбцу для каждой из указанных вами сводных статистических данных.
x - объект числовых/логических векторов и объектов date, date-time и time interval
trim - доля (от 0 до 0,5) наблюдений, которая должна быть обрезана с каждого конца x перед вычислением среднего значения. Значения trim за пределами этого диапазона берутся в качестве ближайшей конечной точки.
na.rm - логическое значение TRUE или FALSE, указывающее, следует ли удалять значения NA перед продолжением вычисления
x <-c(0:10, 50)xm <-mean(x)c(xm, mean(x, trim =0.10))
[1] 8.75 5.50
median
median(x, na.rm = FALSE, ...) - медиана
na.rm - логическое значение TRUE или FALSE, указывающее, следует ли удалять значения NA перед продолжением вычисления
x <-c(0:10, 50)median(x)
[1] 5.5
Spread
sd
sd(x, na.rm = FALSE) - стандартное отклонение
na.rm - логическое значение TRUE или FALSE, указывающее, следует ли удалять значения NA перед продолжением вычисления
x <-c(0:10, 50)sd(x) ^2
[1] 178.75
IQR
IQR(x, na.rm = FALSE, type = 7) - вычисляет межквартильный диапазон значений x
na.rm - логическое значение TRUE или FALSE, указывающее, следует ли удалять значения NA перед продолжением вычисления
type - выбор типа расчета квантиля (подробнее о типах расчета в ?quantile)
x <-c(0:10, 50)IQR(x)
[1] 5.5
mad
mad(x, center = median(x), constant = 1.4826, na.rm = FALSE, low = FALSE, high = FALSE) - вычисляет среднее абсолютное отклонение, т.е. медиану абсолютных отклонений от медианы, и (по умолчанию) корректирует на коэффициент для получения асимптотически нормальной согласованности.
center - опционально можно задать центр, по умолчания используется медиана
constant - коэффициент масштаба
na.rm - логическое значение TRUE или FALSE, указывающее, следует ли удалять значения NA перед продолжением вычисления
low - если значение равно TRUE, вычисляет “lo-median”, т.е. для равномерного размера выборки не усредняет два средних значения, а берет меньшее
high - если TRUE, вычисляет ‘hi-median’, т.е. берет большее из двух средних значений для равномерного размера выборки
x <-c(0:10, 50)c(mad(x, constant =1),mad(x, constant =1, low =TRUE),mad(x, constant =1, high =TRUE))
[1] 3.0 2.5 3.5
Range
min
min(..., na.rm = FALSE) - вычисляет минимальное значение
na.rm - логическое значение TRUE или FALSE, указывающее, следует ли удалять значения NA перед продолжением вычисления
x <-c(0:10, 50)min(x)
[1] 0
max
max(..., na.rm = FALSE) - вычисляет наибольшее значение
na.rm - логическое значение TRUE или FALSE, указывающее, следует ли удалять значения NA перед продолжением вычисления
order_by - необязательный вектор того же размера, что и x, используемый для определения порядка
default - значение по умолчанию, используемое, если позиция не существует в x. Если значение по умолчанию равно NULL, то используется пропущенное значение. Если указано, это должно быть одно значение, которое будет приведено к типу x. Когда x является списком, по умолчанию допускается любое значение. В этом случае нет никаких ограничений по типу или размеру.
na_rm - логическое значение TRUE или FALSE, указывающее, следует ли удалять значения NA перед продолжением вычисления
order_by - необязательный вектор того же размера, что и x, используемый для определения порядка
default - значение по умолчанию, используемое, если позиция не существует в x. Если значение по умолчанию равно NULL, то используется пропущенное значение. Если указано, это должно быть одно значение, которое будет приведено к типу x. Когда x является списком, по умолчанию допускается любое значение. В этом случае нет никаких ограничений по типу или размеру.
na_rm - логическое значение TRUE или FALSE, указывающее, следует ли удалять значения NA перед продолжением вычисления
n - целое число, указывающее позицию. Отрицательные целые числа индексируются с конца (т.е. -1L вернет последнее значение в векторе)
order_by - необязательный вектор того же размера, что и x, используемый для определения порядка
default - значение по умолчанию, используемое, если позиция не существует в x. Если значение по умолчанию равно NULL, то используется пропущенное значение. Если указано, это должно быть одно значение, которое будет приведено к типу x. Когда x является списком, по умолчанию допускается любое значение. В этом случае нет никаких ограничений по типу или размеру.
na_rm - логическое значение TRUE или FALSE, указывающее, следует ли удалять значения NA перед продолжением вычисления
x <-c(0:10, 50)nth(x, 3)
[1] 2
Count
n
n() - возвращает количество элементов в каждой группе в виде набора данных
starwars %>%summarise(n =n())
ABCDEFGHIJ0123456789
n
<int>
87
n_distinct
n_distinct(..., na.rm = FALSE) - подсчитывает количество уникальных элементов
na_rm - логическое значение TRUE или FALSE, указывающее, следует ли удалять значения NA перед продолжением вычисления
x <-c(0:10, 50)n_distinct(x)
[1] 12
Logical
any
any(..., na.rm = FALSE) - проверяет, есть ли в векторе хотя бы одного истинное значение
na_rm - логическое значение TRUE или FALSE, указывающее, следует ли удалять значения NA перед продолжением вычисления
x <-c(0:10, 50)if (any(x ==9)) cat('В векторе есть число равное 9\n')
В векторе есть число равное 9
all
all(..., na.rm = FALSE) - проверяет все ли значения в векторе истинны
na_rm - логическое значение TRUE или FALSE, указывающее, следует ли удалять значения NA перед продолжением вычисления
x <-c(0:10, 50)if (all(x >=0)) cat('В векторе все значения больше или равны нулю\n')
В векторе все значения больше или равны нулю
Условные функции и обработка Null
if_else
if_else векторизованная условная функция с возможность задать правило обработки Null значений
Рассмотрим пример когда относительно роста нужно распределить персонажей по ростовым категориям, а где значение роста равно Null присвоем другое значение
Функция позволяет векторизовать несколько операторов if_else(). Каждый случай оценивается последовательно, и первое совпадение для каждого элемента определяет соответствующее значение в выходном векторе. Если ни один из вариантов не совпадает, используется значение .default.
В примере ниже показано как через одну функцию задать несколько разных условий по разным полям набора данных
starwars %>%select(name, species, height, mass) %>%mutate(type =case_when( height >200| mass >200~"large", species =="Droid"~"robot",.default ="other" ) )
ABCDEFGHIJ0123456789
name
<chr>
species
<chr>
height
<int>
mass
<dbl>
type
<chr>
Luke Skywalker
Human
172
77.0
other
C-3PO
Droid
167
75.0
robot
R2-D2
Droid
96
32.0
robot
Darth Vader
Human
202
136.0
large
Leia Organa
Human
150
49.0
other
Owen Lars
Human
178
120.0
other
Beru Whitesun lars
Human
165
75.0
other
R5-D4
Droid
97
32.0
robot
Biggs Darklighter
Human
183
84.0
other
Obi-Wan Kenobi
Human
182
77.0
other
case_match
Функция позволяет векторизовать несколько операторов switch(). Каждый случай оценивается последовательно, и первое совпадение для каждого элемента определяет соответствующее значение в выходном векторе. Если ни один из вариантов не совпадает, используется значение .default.
Функция находит первое не пропущенное значение и выводит его
coalesce(..., .ptype = NULL, .size = NULL)
В примере в новую колонку пишем первое не равное Null значение, сначала проверяем поле mass, если там Null проверяем поле height, если и в нем Null, то пишем нуль.
Функция group_by() позволяет группировать данные по одному или нескольким столбцам, создавая объект “grouped_df”. Она принимает в качестве аргументов имена столбцов или переменные, по которым нужно провести группировку.
Атрибуты:
.data - набор данных
... - поля по которым необходимо сгруппировать набор
.add = FALSE - при значении FALSE функция group_by() по умолчанию переопределяет существующие группы. Чтобы добавить в существующие группы, используйте .add = TRUE.
.drop = group_by_drop_default(.data) - удаляет группы, софрмированные по неотображаемым в наборе уровням фактора, по умолчанию TRUE
Пример использования:
# Создаем таблицу данныхdf <-tibble(group =rep(c("A", "B"), each =3),x =rnorm(6), y =rnorm(6))df
ABCDEFGHIJ0123456789
group
<chr>
x
<dbl>
y
<dbl>
A
-1.7769139
0.5058644
A
-0.9215965
-0.2958241
A
-0.9654158
1.6599439
B
1.1329398
-0.1320836
B
0.7168614
-1.9929238
B
0.1815643
-0.9442623
# Группируем данные по столбцу "group"df_grouped <- df %>%group_by(group)df_grouped
ABCDEFGHIJ0123456789
group
<chr>
x
<dbl>
y
<dbl>
A
-1.7769139
0.5058644
A
-0.9215965
-0.2958241
A
-0.9654158
1.6599439
B
1.1329398
-0.1320836
B
0.7168614
-1.9929238
B
0.1815643
-0.9442623
# Проверяем наличие группирующих переменныхdf_grouped %>%group_vars()
[1] "group"
В этом примере мы создали таблицу данных df с тремя столбцами: group, x и y. Затем мы использовали функцию group_by() для группировки данных по столбцу “group”, создав объект “grouped_df”. Наконец, мы использовали функцию group_vars чтобы проверить наличие в наборе группирующих переменных.
Метаданные групп
Функции из этого раздела дают дополнительную информацию о сгруппированном наборе данных и каждой отдельной группе внутри него.
group_data
group_data(.data)
Функция возвращает фрейм данных, который определяет структуру группировки. В столбцах приведены значения группирующих переменных. Последний столбец, всегда называемый .rows, представляет собой список целочисленных векторов, который указывает расположение строк в каждой группе. По сути объединяет в себе результат работы функций group_keys и group_rows.
starwars %>%group_by(sex) %>%group_data()
ABCDEFGHIJ0123456789
sex
<chr>
.rows
<list<int>>
female
<list<int>>
hermaphroditic
<list<int>>
male
<list<int>>
none
<list<int>>
NA
<list<int>>
group_keys
group_keys(.tbl, ...)
Функция возвращает набор данных описывающий группы
starwars %>%group_by(sex) %>%group_keys()
ABCDEFGHIJ0123456789
sex
<chr>
female
hermaphroditic
male
none
NA
group_rows
group_rows(.data)
Функция возвращает список целочисленных векторов, содержащих строки, которые содержит каждая группа.
Функция group_vars(x) возвращает вектор содержащий имена группирующих переменных, а функция groups(x) в виде списка
starwars %>%group_by(sex) %>%group_vars()
[1] "sex"
starwars %>%group_by(sex) %>%groups()
[[1]]
sex
group_size
group_size(x)
Функция возвращает количество элементов в каждой группе
starwars %>%group_by(sex) %>%group_size()
[1] 16 1 60 6 4
n_groups
n_groups(x)
Функция возвращает количество групп в наборе данных
starwars %>%group_by(sex) %>%n_groups()
[1] 5
Описание группы
n
n()
Функция возвращает количество элементов в каждой группе в виде набора данных
starwars %>%group_by(sex) %>%summarise(n =n())
ABCDEFGHIJ0123456789
sex
<chr>
n
<int>
female
16
hermaphroditic
1
male
60
none
6
NA
4
cur_group
cur_group()
Функция возвращает ключи группы для каждой группирующей переменной в виде tibble с одной строкой и столбцами количество которых равно количеству группирующих переменных
group_map() - это функция, которая позволяет применить к каждой группе данных заданную пользователем функцию. Результатом функции является список, каждый элемент которого содержит результат выполнения функции .f для соответствующей группы данных. Эта функция может быть полезна, когда требуется выполнить некоторую операцию над каждой группой данных, например, построить график или вычислить статистику.
Аргументы:
.tbl - группированный data frame;
.f - функция, которую требуется применить к каждой группе данных;
… - дополнительные аргументы, которые будут переданы в функцию .f.
К сгруппированному набору применяем функцию quantile и выводим список c результатами работы функции примененной к каждой группе.
group_modify
group_modify(.data, .f, ..., .keep = FALSE)
Эта функция используется для модификации каждой группы набора данных. В примере ниже сгруппируем набор по полю sex и в каждой группе оставим по одной верхней строке.
Функция возвращает данные каждой группы и без изменений передает их дальше. Это можно использовать для выполнения действий с данными из каждой группы внутри процесса не нарушая логику алгоритма. В примере ниже мы выводим на печать первые две строки из каждой группы в виде отдельного tibble, а дальше применяем функцию group_modify как в примере выше.
В примере документации показан вариант, где данные каждой группы сохраняются в отдельный файл:`
# A tibble: 1 × 13
name height mass hair_color skin_color eye_color birth_year gender homeworld
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 Leia… 150 49 brown light brown 19 femin… Alderaan
# ℹ 4 more variables: species <chr>, films <list>, vehicles <list>,
# starships <list>
# A tibble: 1 × 13
name height mass hair_color skin_color eye_color birth_year gender homeworld
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 Jabb… 175 1358 <NA> green-tan… orange 600 mascu… Nal Hutta
# ℹ 4 more variables: species <chr>, films <list>, vehicles <list>,
# starships <list>
# A tibble: 1 × 13
name height mass hair_color skin_color eye_color birth_year gender homeworld
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 Luke… 172 77 blond fair blue 19 mascu… Tatooine
# ℹ 4 more variables: species <chr>, films <list>, vehicles <list>,
# starships <list>
# A tibble: 1 × 13
name height mass hair_color skin_color eye_color birth_year gender homeworld
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 C-3PO 167 75 <NA> gold yellow 112 mascu… Tatooine
# ℹ 4 more variables: species <chr>, films <list>, vehicles <list>,
# starships <list>
# A tibble: 1 × 13
name height mass hair_color skin_color eye_color birth_year gender homeworld
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 Ric … 183 NA brown fair blue NA <NA> Naboo
# ℹ 4 more variables: species <chr>, films <list>, vehicles <list>,
# starships <list>
ABCDEFGHIJ0123456789
sex
<chr>
name
<chr>
height
<int>
mass
<dbl>
hair_color
<chr>
female
Leia Organa
150
49
brown
female
Beru Whitesun lars
165
75
brown
hermaphroditic
Jabba Desilijic Tiure
175
1358
NA
male
Luke Skywalker
172
77
blond
male
Darth Vader
202
136
none
none
C-3PO
167
75
NA
none
R2-D2
96
32
NA
NA
Ric Olié
183
NA
brown
NA
Quarsh Panaka
183
NA
black
group_cols
group_cols(vars = NULL, data = NULL)
Функция позволяет выбирать к поля по которым выполнялась группировка, обычно используется при выборке данных. Таким образом с помощью group_cols можно обратиться ко всем полям по которым выполнялась группировка.
Функция возвращает список отдельных групп данных, каждая из которых содержит только те строки, где значение переменных группировки соответствует данной группе.
В примере группируем набор по полю sex и разбиваем набор сформированным группам.
starwars %>%group_by(sex) %>%group_split()
<list_of<
tbl_df<
name : character
height : integer
mass : double
hair_color: character
skin_color: character
eye_color : character
birth_year: double
sex : character
gender : character
homeworld : character
species : character
films : list
vehicles : list
starships : list
>
>[5]>
[[1]]
# A tibble: 16 × 14
name height mass hair_color skin_color eye_color birth_year sex gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 Leia Or… 150 49 brown light brown 19 fema… femin…
2 Beru Wh… 165 75 brown light blue 47 fema… femin…
3 Mon Mot… 150 NA auburn fair blue 48 fema… femin…
4 Shmi Sk… 163 NA black fair brown 72 fema… femin…
5 Ayla Se… 178 55 none blue hazel 48 fema… femin…
6 Adi Gal… 184 50 none dark blue NA fema… femin…
7 Cordé 157 NA brown light brown NA fema… femin…
8 Luminar… 170 56.2 black yellow blue 58 fema… femin…
9 Barriss… 166 50 black yellow blue 40 fema… femin…
10 Dormé 165 NA brown light brown NA fema… femin…
11 Zam Wes… 168 55 blonde fair, gre… yellow NA fema… femin…
12 Taun We 213 NA none grey black NA fema… femin…
13 Jocasta… 167 NA white fair blue NA fema… femin…
14 Shaak Ti 178 57 none red, blue… black NA fema… femin…
15 Rey NA NA brown light hazel NA fema… femin…
16 Padmé A… 165 45 brown light brown 46 fema… femin…
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
# vehicles <list>, starships <list>
[[2]]
# A tibble: 1 × 14
name height mass hair_color skin_color eye_color birth_year sex gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 Jabba De… 175 1358 <NA> green-tan… orange 600 herm… mascu…
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
# vehicles <list>, starships <list>
[[3]]
# A tibble: 60 × 14
name height mass hair_color skin_color eye_color birth_year sex gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 Luke Sk… 172 77 blond fair blue 19 male mascu…
2 Darth V… 202 136 none white yellow 41.9 male mascu…
3 Owen La… 178 120 brown, gr… light blue 52 male mascu…
4 Biggs D… 183 84 black light brown 24 male mascu…
5 Obi-Wan… 182 77 auburn, w… fair blue-gray 57 male mascu…
6 Anakin … 188 84 blond fair blue 41.9 male mascu…
7 Wilhuff… 180 NA auburn, g… fair blue 64 male mascu…
8 Chewbac… 228 112 brown unknown blue 200 male mascu…
9 Han Solo 180 80 brown fair brown 29 male mascu…
10 Greedo 173 74 <NA> green black 44 male mascu…
# ℹ 50 more rows
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
# vehicles <list>, starships <list>
[[4]]
# A tibble: 6 × 14
name height mass hair_color skin_color eye_color birth_year sex gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 C-3PO 167 75 <NA> gold yellow 112 none masculi…
2 R2-D2 96 32 <NA> white, blue red 33 none masculi…
3 R5-D4 97 32 <NA> white, red red NA none masculi…
4 IG-88 200 140 none metal red 15 none masculi…
5 R4-P17 96 NA none silver, red red, blue NA none feminine
6 BB8 NA NA none none black NA none masculi…
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
# vehicles <list>, starships <list>
[[5]]
# A tibble: 4 × 14
name height mass hair_color skin_color eye_color birth_year sex gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 Ric Olié 183 NA brown fair blue NA <NA> <NA>
2 Quarsh P… 183 NA black dark brown 62 <NA> <NA>
3 Sly Moore 178 48 none pale white NA <NA> <NA>
4 Captain … NA NA unknown unknown unknown NA <NA> <NA>
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
# vehicles <list>, starships <list>
Задача функции заключается в удалении неиспользуемых уровней факторов, которые используются в качестве переменных для группировки, а затем пересчёта структуры группировки.
Эта функция особенно полезна после применения функции filter(), которая выбирает подмножество групп. В результате применения filter() могут появиться неиспользуемые уровни факторов, что может привести к ошибкам или непредсказуемым результатам.
Функция rowwise() позволяет выполнять вычисления для каждой строки входных данных. Это особенно полезно, когда векторизованная функция не подходит для вычислений. Вызов функции rowwise() создает так называемый “row-wise” data frame, в котором вычисления выполняются по каждой строке, сохраняя все переменные в строке.
В примере по строчно вычисляем наименьшее значение из трех числовых столбцов
Функция применяется с rowwise для упрощения агрегирования по строкам. Для формирования выходного результата используется vctrs::vec_c().
df <-tibble(id =1:4, w =runif(4), x =runif(4), y =runif(4), z =runif(4))df %>%rowwise() %>%mutate(sum =sum(c_across(w:z)),sd =sd(c_across(w:z)) )
ABCDEFGHIJ0123456789
id
<int>
w
<dbl>
x
<dbl>
y
<dbl>
z
<dbl>
sum
<dbl>
1
0.9186749
0.5933133
0.9771804
0.576229101
3.065398
2
0.7875776
0.9511442
0.2712798
0.005825474
2.015827
3
0.8378928
0.4818063
0.1610149
0.720769071
2.201483
4
0.4512932
0.7701855
0.7982142
0.230948808
2.250642
ungroup
ungroup(x, ...)
Функция удаляет группировку из набора данных
# группируем набор по двум полямstarwars %>%group_by(sex, gender) %>%# проверяем наличие группирующих переменныхgroup_vars()
[1] "sex" "gender"
# группируем набор по двум полямstarwars %>%group_by(sex, gender) %>%# удаляем группировкуungroup() %>%# проверяем наличие группирующих переменныхgroup_vars()
character(0)
reframe
reframe(.data, ..., .by = NULL)
функция создает новый фрейм данных, применяя функции к столбцам существующего фрейма данных. Отличается от summarise() тем, что может возвращать произвольное количество строк для каждой группы и всегда возвращает несгруппированный фрейм данных. reframe() может быть особенно полезен, когда вам нужно применить сложную функцию, которая не возвращает ни одного суммарного значения.
В процессе объединения таблиц можно выделить операции трех видов:
Mutating joins, которые добавляют новые переменные в один фрейм данных из совпадающих наблюдений в другом.
Filtering joins, которые фильтруют наблюдения из одного фрейма данных на основе того, соответствуют ли они наблюдению в другой таблице.
Set operations, эти операции работают с пересечениями двух фреймов
Для разбора операций соединения, загрузим набор данных nycflights13
```{r}library(nycflights13)```
Ключи соединения
Сопоставление ключей
При соединении фреймов данных нужно указать ключи соединения иногда это может быть один ключ или набор ключей, они могут совпадать по наименованию или различаться. Давайте рассмотрим разные варианты.
Соединить по всем совпадающим полям
Чтобы соединить по всем совпадающим по названию полям, нужно оставить by = NULL
flights2 %>%left_join(weather)
Joining with `by = join_by(year, month, day, origin, hour, time_hour)`
ABCDEFGHIJ0123456789
year
<int>
month
<int>
day
<int>
dep_time
<int>
sched_dep_time
<int>
dep_delay
<dbl>
arr_time
<int>
2013
1
1
517
515
2
830
2013
1
1
533
529
4
850
2013
1
1
542
540
2
923
2013
1
1
544
545
-1
1004
2013
1
1
554
600
-6
812
2013
1
1
554
558
-4
740
2013
1
1
555
600
-5
913
2013
1
1
557
600
-3
709
2013
1
1
557
600
-3
838
2013
1
1
558
600
-2
753
Соединить по одному ключу
Соединение по одному ключу с общим для обоих фреймов названием:
flights2 %>%left_join(planes, by ="tailnum")
ABCDEFGHIJ0123456789
year.x
<int>
month
<int>
day
<int>
dep_time
<int>
sched_dep_time
<int>
dep_delay
<dbl>
arr_time
<int>
2013
1
1
517
515
2
830
2013
1
1
533
529
4
850
2013
1
1
542
540
2
923
2013
1
1
544
545
-1
1004
2013
1
1
554
600
-6
812
2013
1
1
554
558
-4
740
2013
1
1
555
600
-5
913
2013
1
1
557
600
-3
709
2013
1
1
557
600
-3
838
2013
1
1
558
600
-2
753
Соединить по нескольким ключам
by = c(“a” = “b”) -> x$a == y$b - соединить с помощью разных переменных на x и y, используется именованный вектор.
by = c(“a”, “b”) -> x$a == y$a and x$b == y$b - соединить по нескольким переменным
by = c(“a” = “b”, “c” = “d” -> x$a == y$b and x$c == y$d - соединить сопоставив раличные переменные из двух фреймов
flights2 %>%left_join(airports, c("dest"="faa"))
ABCDEFGHIJ0123456789
year
<int>
month
<int>
day
<int>
dep_time
<int>
sched_dep_time
<int>
dep_delay
<dbl>
arr_time
<int>
2013
1
1
517
515
2
830
2013
1
1
533
529
4
850
2013
1
1
542
540
2
923
2013
1
1
544
545
-1
1004
2013
1
1
554
600
-6
812
2013
1
1
554
558
-4
740
2013
1
1
555
600
-5
913
2013
1
1
557
600
-3
709
2013
1
1
557
600
-3
838
2013
1
1
558
600
-2
753
Проблемы с ключами
Не всегда бывает так, что значения в ключевом столбце уникальные. Когда соединяются дублированные ключи, получаются все возможные комбинации, декартово произведение. В функции Join нет никакой обработки таких случаев, поэтому нужно быть внимательным к своим данным и проверять результирующий набор данных. А также при необходимости удалять дублирующие строки.
Убедитесь, что ваши внешние ключи совпадают с первичными ключами в другой таблице. Лучший способ сделать это - с помощью anti_join(). Часто ключи не совпадают из-за ошибок ввода данных. Их устранение часто требует большой работы.
Mutating joins
В принципе это самые обычные и привычные Join-ы, которые мы используем каждый день. Рассмотрим аргументы этих функций:
x, y - пара фреймов данных, которые нужно соединить
by - вектор переменных в котором задаются ключи
suffix - добавляет суффиксы для одноименных не ключевых полей
keep - указывает, нужно ли сохранять ключевые поля в результирующем фрейме данных
na_matches - задает считать или нет равными значения NA и NaN, по умолчанию “na” считаются равными, “never” - исчтать не равными
Чтобы понять суть разных типов соединений, создадим два тестовых фрейма данных и проиллюстрируем на их примере каждый тип:
Внутреннее соединение сопоставляет пары наблюдений всякий раз, когда их ключи равны.Наиболее важным свойством внутреннего соединения является то, что несогласованные строки не включаются в результат. Это означает, что, как правило, внутренние соединения обычно не подходят для использования в анализе, потому что слишком легко потерять наблюдения.
Внешнее соединение сохраняет наблюдения, которые отображаются по крайней мере в одной из таблиц.
Left Join
left_join - сохраняет все строки из первой таблицы и соединяет все совпавшие по ключу строки из второй таблицы.
Наиболее часто используемым соединением является левое соединение: его используют всякий раз, когда просматривают дополнительные данные из другой таблицы, потому что оно сохраняет исходные наблюдения, даже если совпадения нет. Левое соединение должно быть соединением по умолчанию: используйте его, если у нет веских причин предпочесть одно из других.
Фильтрующие соединения используются для фильтрации первого фрейма на основе данных из второго фрейма данных.
semi_join
semi_join соединяет две таблицы подобно мутирующему соединению, но вместо добавления новых столбцов сохраняет только те строки в x, которые совпадают в y.
x
ABCDEFGHIJ0123456789
key
<dbl>
val_x
<chr>
1
x1
2
x2
3
x3
y
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
1
y1
2
y2
4
y3
semi_join
semi_join(x, y, by ="key")
ABCDEFGHIJ0123456789
key
<dbl>
val_x
<chr>
1
x1
2
x2
Важно только наличие совпадения; не имеет значения, какому наблюдению соответствует. Это означает, что фильтрующие соединения никогда не дублируют строки, как это делают мутирующие соединения.
anti_join
Антисоединения полезны для диагностики несоответствий соединений. Например, так можно делать проверку полноты данных по эталонным справочникам:
x
ABCDEFGHIJ0123456789
key
<dbl>
val_x
<chr>
1
x1
2
x2
3
x3
y
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
1
y1
2
y2
4
y3
anti_join
anti_join(x, y, by ="key")
ABCDEFGHIJ0123456789
key
<dbl>
val_x
<chr>
3
x3
nest_join
nest_join() возвращает все строки и столбцы в x с новым столбцом в каждой строке которого вложен фрейм, содержащий все совпадения из y. Если совпадений нет, то фрейм будет пустой.
x
ABCDEFGHIJ0123456789
key
<dbl>
val_x
<chr>
1
x1
2
x2
3
x3
y
ABCDEFGHIJ0123456789
key
<dbl>
val_y
<chr>
1
y1
2
y2
4
y3
nest_join(x, y, by ="key")
ABCDEFGHIJ0123456789
key
<dbl>
val_x
<chr>
1
x1
2
x2
3
x3
nest_join(x, y, by ="key") %>%unnest(cols =c(y))
ABCDEFGHIJ0123456789
key
<dbl>
val_x
<chr>
val_y
<chr>
1
x1
y1
2
x2
y2
Set operations
Операции с наборами требуют чтобы соединяемые фреймы данных имели одинаковое количество столбцов, эти функции объединяют два фрейма данных как бы складывая их друг под друга.
Создадим два фрейма, чтобы показать работу этих функций:
union - оставляет только уникальные строки из обоих наборов
union_all - оставляет все строки из обоих наборов
df1
ABCDEFGHIJ0123456789
x
<dbl>
y
<dbl>
1
1
2
1
df2
ABCDEFGHIJ0123456789
x
<dbl>
y
<dbl>
1
1
1
2
union(df1, df2)
ABCDEFGHIJ0123456789
x
<dbl>
y
<dbl>
1
1
2
1
1
2
union_all(df1, df2)
ABCDEFGHIJ0123456789
x
<dbl>
y
<dbl>
1
1
2
1
1
1
1
2
intersect
оставляет только совпавшие строки из обоих наборов:
df1
ABCDEFGHIJ0123456789
x
<dbl>
y
<dbl>
1
1
2
1
df2
ABCDEFGHIJ0123456789
x
<dbl>
y
<dbl>
1
1
1
2
intersect
intersect(df1, df2)
ABCDEFGHIJ0123456789
x
<dbl>
y
<dbl>
1
1
setdiff
оставляет строки из первого фрейма только не совпавшие со строками из второго фрейма
df1
ABCDEFGHIJ0123456789
x
<dbl>
y
<dbl>
1
1
2
1
df2
ABCDEFGHIJ0123456789
x
<dbl>
y
<dbl>
1
1
1
2
intersect
setdiff(df1, df2)
ABCDEFGHIJ0123456789
x
<dbl>
y
<dbl>
2
1
setdiff(df2, df1)
ABCDEFGHIJ0123456789
x
<dbl>
y
<dbl>
1
2
Манипуляция отдельными строками
Группа этих функций позволяет манипулировать отдельными строками на подобии SQL без создания копии фрейма данных. Каждая строка представляет из себя фрейм с одной или более строк.
Рассмотрим атрибуты функций:
x, y - пара фреймов, x исходный фрейм, а y фрейм-строка, с которой нужно выполнить операцию. y должен иметь те же столбцы, что x
by - задание ключевых столбцов. Ключи обычно однозначно идентифицируют каждую строку, но это применяется только для значений ключа y, когда используются rows_update(), rows_patch() или rows_upsert(), по умолчанию используется первый столбец в y
conflict - правило для обработки конфликтов вставки при использовании rows_insert(). Конфликт возникает, если в y есть ключ, который уже существует в x. Можно задать два типа поведения: error - значение по умолчанию, приведет к ошибке, если в y есть какие-либо ключи, которые конфликтуют с ключами в x; ignore - будет игнорировать строки в y с ключами, которые конфликтуют с ключами в x
copy - если x и ьy не из одного источника данных и значение copy равно TRUE, то y будет скопирован в тот же src, что и x. Это позволяет объединять таблицы в разных src, но это потенциально дорогостоящая операция
unmatched - правило для обработки ключей в y не совпадающих с ключами в x, используется в rows_update(), rows_patch(), and rows_delete(). Можно задать два типа поведения: error - значение по умолчанию, вызовет ошибку если ключи не совпадают; ignore - будет игнорировать строки с несовпадающими ключами
Создадим набор данных для описания возможностей работы с функциями:
data <-tibble(a =1:3, b = letters[c(1:2, NA)], c =0.5+0:2)data
ABCDEFGHIJ0123456789
a
<int>
b
<chr>
c
<dbl>
1
a
0.5
2
b
1.5
3
NA
2.5
rows_insert
rows_insert(x, y, by = NULL, ..., conflict = c("error", "ignore"), copy = FALSE, in_place = FALSE)
rows_insert() - добавляет новую стороку во фрейм данных, по умолчанию ключевые значения добавляемой строки не должны существовать во фрейме.
rows_insert(data, tibble(a =4, b ="z"))
Matching, by = "a"
ABCDEFGHIJ0123456789
a
<int>
b
<chr>
c
<dbl>
1
a
0.5
2
b
1.5
3
NA
2.5
4
z
NA
rows_insert(data, tibble(a =3, b ="z"), conflict ="ignore")
Matching, by = "a"
ABCDEFGHIJ0123456789
a
<int>
b
<chr>
c
<dbl>
1
a
0.5
2
b
1.5
3
NA
2.5
Воспроизведем ситуацию когда ключевые значения совпадают, и функция не дополнена аргументом conflict
try(rows_insert(data, tibble(a =3, b ="z")))
Matching, by = "a"
Error in rows_insert(data, tibble(a = 3, b = "z")) :
`y` can't contain keys that already exist in `x`.
ℹ The following rows in `y` have keys that already exist in `x`: `c(1)`.
ℹ Use `conflict = "ignore"` if you want to ignore these `y` rows.
rows_append
rows_append(x, y, ..., copy = FALSE, in_place = FALSE)
rows_append() - добавляет новую стороку во фрейм данных, в отличии от rows_insert() игнорирует ключи
rows_append(data, tibble(a =7, b ="n"))
ABCDEFGHIJ0123456789
a
<int>
b
<chr>
c
<dbl>
1
a
0.5
2
b
1.5
3
NA
2.5
7
n
NA
rows_update
rows_update(x, y, by = NULL, ..., unmatched = c("error", "ignore"), copy = FALSE, in_place = FALSE)
rows_update() - изменяет существующие строки. Значения ключей в y должны быть уникальными, и, по умолчанию, значения ключей в y должны существовать в x
rows_update(data, tibble(a =1, b ="s", c =11.4), by ="a")
ABCDEFGHIJ0123456789
a
<int>
b
<chr>
c
<dbl>
1
s
11.4
2
b
1.5
3
NA
2.5
rows_patch
rows_patch(x, y, by = NULL, ..., unmatched = c("error", "ignore"), copy = FALSE, in_place = FALSE)
rows_patch() - изменяет существующие строки и перезаписывает только NA значения
rows_patch(data, tibble(a =3, b ="s", c =11.4), by ="a")
ABCDEFGHIJ0123456789
a
<int>
b
<chr>
c
<dbl>
1
a
0.5
2
b
1.5
3
s
2.5
rows_upsert
rows_upsert(x, y, by = NULL, ..., copy = FALSE, in_place = FALSE)
rows_upsert() - вставляет или обновляет строку в зависимости от того, существует ли ключевое значение из y в x или нет
rows_upsert(data, tibble(a =c(1, 4), b =c("s", "e"), c =c(11.4, 3.01)), by ="a")
ABCDEFGHIJ0123456789
a
<int>
b
<chr>
c
<dbl>
1
s
11.40
2
b
1.50
3
NA
2.50
4
e
3.01
rows_delete(
rows_delete(x, y, by = NULL, ..., unmatched = c("error", "ignore"), copy = FALSE, in_place = FALSE)
rows_delete() - удаляет строки из фрейма x, по умолчанию ключи из y должны быть в x