В современном анализе данных в R большинство пользователей используют мета-пакет Tidyverse — набор взаимосвязанных пакетов с полезными функциями по управлению данными и созданию графиков. Чтобы не устанавливать их по отдельности, достаточно выполнить команду:
install.packages("tidyverse")
И аналогичным образом включать в начале работы:1
library(tidyverse)
── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
✔ ggplot2 3.4.2 ✔ purrr 1.0.1
✔ tibble 3.2.1 ✔ dplyr 1.1.2
✔ tidyr 1.3.0 ✔ stringr 1.5.0
✔ readr 2.1.2 ✔ forcats 0.5.1
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
Работать с Tidyverse удобнее всего в редакторе скриптов, а не консоли. Поэтому далее предполагается, что вы используете RStudio.
Программа R за несколько десятилетий существования обросла огромным количеством сторонних пакетов, в том числе меняющих и базовые принципы работы с данными. При этом скриптовый код будет словно написан на другом языке — или, вернее, на другом диалекте “языка R”. Диалект Tidyverse выстроился на основе идей новозеландского статистика Хэдли Уикхема о принципах работы с данными и вокруг его сверхпопулярных пакетов dplyr, tidyr и ggplot2. Они повсеместно встречаются в сетевых руководствах по тем или иным операциям в R, а ggplot2 вообще является самой популярной графической системой. Общая идеология этих пакетов строится на принципах функционального программирования, и в двух словах её можно представить примерно так: код, написанный в Tidyverse, будет более громоздким, но зато легко читаемым и понятным. При этом используемые команды просты, единообразно устроены и прячут от пользователя большую часть мелкой работы.
Настоятельно рекомендуем в свободное время ознакомиться с ультимативным руководством от Уикхема по работе с данными в Tidyverse (и вообще в R).
Работа с данными производится с помощью шести основных функций:
select() |
выбор переменных (столбцов) |
mutate() |
изменение или добавление переменных |
filter() |
отобрать строки (наблюдения) по интересующим критериям |
arrange() |
сортировка строк |
group_by() |
разбивка наблюдений на группы для последующих операций |
summarise() |
создание новых таблиц, обобщающих наблюдения |
Если использовать их по отдельности, каждая функция первым параметром принимает объект, с которым будет работать: таблицу с данными типа data.frame или tibble. Однако гораздо удобнее объединять их в цепочку с помощью оператора конвейера %>%2. Тогда функции “передают” друг другу объект, с которым поработали, и указывать его в параметрах не нужно. Сравните два варианта кода, выполняющих одно и то же:
# Каждая команда сохраняет результат в новую переменную,
# которую использует следующая функция:
a <- filter(iris, Species == "versicolor")
b <- mutate(a, ratio = Sepal.Length / Sepal.Width)
c <- select(b, 1, 2, 6)
d <- arrange(c, ratio)
# То же самое, но без лишних переменных и понятнее:
d <- iris %>%
filter(Species == "versicolor") %>%
mutate(ratio = Sepal.Length / Petal.Length) %>%
select(1, 3, 6) %>%
arrange(ratio)
# Сначала выполняются все операции, затем результат сохраняется в d
d
Sepal.Length Petal.Length ratio
1 6.0 5.1 1.176471
2 5.4 4.5 1.200000
3 5.9 4.8 1.229167
4 5.6 4.5 1.244444
...
Рассмотрим этот пример подробнее. Первая команда
filter() отбирает из таблицы iris лишь те строки, в которых
переменная Species имеет значение “versicolor”. Следующая команда
mutate()создаёт в таблице новую переменную ratio, значения
которой у каждого ириса равны отношению длины “лепестков” к длине
“чашелистиков” — т.е. отношению значений из соответствующих столбцов.
Далее команда select() оставляет только первый, третий и
шестой столбцы (Sepal.Length, Petal.Length и ratio), а
arrange() сортирует строки полученной таблицы по столбцу
ratio, начиная с наименьшего значения.
Далее эти и другие функции будут рассмотрены подробнее.
Эта функция позволяет выбирать нужные столбцы в таблице различными способами:
| названия столбцов через запятую | select(iris, Sepal.Length, Petal.Length) |
| номера столбцов через запятую | select(iris, 1, 3) |
| : выбирает все столбцы между двумя указанными | select(iris, 1:4) — выберет все 4 числовые
переменные в iris; подходят номера или имена столбцов |
| ! выбирает все столбцы, кроме указанных | select(iris, !Species) — выберет те же 4
переменные; можно использовать и минус, как в базовом R |
Также для выбора можно применять специальные функции:
last_col() — последний столбец.
starts_with("текст"),
ends_with("текст"), contains("текст") —
выбирают столбцы, содержащие требуемый текст в начале, в конце или где
угодно.
num_range("текст", n:m) — для выбора столбцов, имена
которых содержат текст и последовательность чисел. Пример:
num_range("day", 5:10) выберет столбцы day5, day6, day7,
day8, day9, day10.
where(имя функции) — выбирает столбцы, которые
задаваемая вами функция проверяет и даёт результат TRUE.
select(iris, where(is.numeric)) выберет только числовые
переменные (первые 4 столбца)3.
Операторы & и | позволяют объединять разные условия так, чтобы либо они выполнялись все (&), либо хотя бы одно (|).
Столбцы, которые не были выбраны, отбрасываются. Можно оставить их,
добавив в конце параметр everything() — так можно, не меняя
таблицу, переставлять столбцы местами.
Несколько примеров:
# Самый простой вариант:
select(mtcars, mpg, wt, disp)
mpg wt disp
Mazda RX4 21.0 2.620 160
Mazda RX4 Wag 21.0 2.875 160
Datsun 710 22.8 2.320 108
Hornet 4 Drive 21.4 3.215 258
...
# Просто вытащим эти столбцы вперёд, для удобства:
select(mtcars, mpg, wt, disp, everything())
mpg wt disp cyl hp drat qsec vs am gear carb
Mazda RX4 21.0 2.620 160 6 110 3.90 16.46 0 1 4 4
Mazda RX4 Wag 21.0 2.875 160 6 110 3.90 17.02 0 1 4 4
Datsun 710 22.8 2.320 108 4 93 3.85 18.61 1 1 4 1
Hornet 4 Drive 21.4 3.215 258 6 110 3.08 19.44 1 0 3 1
...
# Всё, кроме первого столбца:
select(mtcars, 2:last_col())
cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 6 258 110 3.08 3.215 19.44 1 0 3 1
...
# Операторы & и |
select(iris, starts_with("Sepal") & ends_with("Width"))
Sepal.Width
1 3.5
2 3.0
3 3.2
4 3.1
...
select(iris, starts_with("Sepal") | ends_with("Width"))
Sepal.Length Sepal.Width Petal.Width
1 5.1 3.5 0.2
2 4.9 3.0 0.2
3 4.7 3.2 0.2
4 4.6 3.1 0.2
...
# Сложное условие
select(iris, 2:last_col() & ! where(is.factor) & ! contains("Width"))
Petal.Length
1 1.4
2 1.4
3 1.3
4 1.5
...
Функция rename(новое_имя = старое_имя) позволяет
переименовывать столбцы. Выбирать столбцы для переименования
(“старое_имя”) нужно так же, как и в select().
Если в описании какой-нибудь функции вы встречаете в качестве
значения одного из параметров “<tidy-select>”, значит вы можете
выбрать один или несколько столбцов таблицы, с которой работает эта
функция, точно таким же образом, как и в select(). Если
нужно перечислить несколько критериев через запятую, то окружите их
функцией c(). Типичные примеры функций, использующих
<tidy-select>: pivot_longer(), across() или описанная выше
rename().
Добавление столбца в таблице похоже на создание нового
объекта, только пишется внутри функции mutate() и
использует оператор = вместо <-.
При этом можно использовать другие столбцы (переменные) таблицы,
совершая с ними произвольные операции. Можно создавать сразу несколько
переменных.
# Посчитаем соотношение длины к ширине для "лепестков" и "чашелистиков" ирисов.
#
# Обратите внимание: так как это скрипт, то можно для удобства
# записывать длинные команды на нескольких строчках.
iris %>%
mutate(s.ratio = Sepal.Length / Sepal.Width,
p.ratio = Petal.Length / Petal.Width)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species s.ratio p.ratio
1 5.1 3.5 1.4 0.2 setosa 1.457143 7.0
2 4.9 3.0 1.4 0.2 setosa 1.633333 7.0
3 4.7 3.2 1.3 0.2 setosa 1.468750 6.5
4 4.6 3.1 1.5 0.2 setosa 1.483871 7.5
...
Чтобы изменить существующий столбец, надо “создать” новый столбец с тем же именем:
# Для анализа таблицы mtcars может понадобиться преобразовать
# несколько столбцов в факторы, в т.ч. упорядоченные:
mtcars %>%
mutate(cyl = ordered(cyl),
gear = ordered(gear),
am = factor(am, labels=c("automatic", "manual")))
# Преобразуем единицы измерения переменных mtcars в привычные СИ:
mtcars %>% mutate(mpg = mpg * 1.60934 / 3.78541, # км / л
disp = disp * 0.0163871, # литры
wt = wt * 0.453592) # тонны
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 8.928000 6 2.621936 110 3.90 1.188411 16.46 0 1 4 4
Mazda RX4 Wag 8.928000 6 2.621936 110 3.90 1.304077 17.02 0 1 4 4
Datsun 710 9.693257 4 1.769807 93 3.85 1.052333 18.61 1 1 4 1
Hornet 4 Drive 9.098057 6 4.227872 110 3.08 1.458298 19.44 1 0 3 1
...
Для манипуляций с переменными можно использовать любые функции R. В частности, полезными могут оказаться следующие:
rank(имя_столбца) — ранжирует значения переменной, т.е.
присваивает им порядковые номера, начиная с самого маленького. Можно
наоборот, начать с самого большого значения, с помощью
dec(), как в примере ниже. Судьба одинаковых значений
решается параметром ties.method.# Top-5 самых экономичных автомобилей из mtcars
mtcars %>%
mutate(top_econom = rank( desc(mpg) )) %>%
arrange(top_econom) %>%
head(5)
mpg cyl disp hp drat wt qsec vs am gear carb top_econom
Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1 1.0
Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1 2.0
Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2 3.5
Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2 3.5
Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1 5.0
if_else(условие, если да, если нет) — работает
аналогично функции ЕСЛИ / IF из Excel. Принцип её работы проще всего
понять на конкретном примере:# Допустим, мы считаем, что экономные машины имеют значение mpg больше 20.
# Отметим все машины в mtcars как экономные или растратные:
mtcars %>%
mutate(efficiency = if_else(mpg > 20, # проверяем условие
"экономная", # новое значение, если условие выполняется
"растратная")) %>% # если не выполняется
select(mpg, efficiency)
mpg efficiency
Mazda RX4 21.0 экономная
Mazda RX4 Wag 21.0 экономная
Datsun 710 22.8 экономная
Hornet 4 Drive 21.4 экономная
Hornet Sportabout 18.7 растратная
Valiant 18.1 растратная
Duster 360 14.3 растратная
...
case_when() — усложненная версия
if_else(), в которой можно выполнить сразу несколько
проверок, и для каждой задать свой результат. Формат проверки:
запрос ~ результат. Проверки будут проводиться строго по
очереди:# Разделим ирисы по длине лепестков:
iris %>%
mutate(size = case_when(
Petal.Length > 6 ~ "большой",
Petal.Length > 4 ~ "средний",
Petal.Length > 2 ~ "маленький",
Petal.Length > 1 ~ "малюсенький",
TRUE ~ "ошибка" # выполняется всегда, если не выполнились предыдущие
))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species size
1 5.1 3.5 1.4 0.2 setosa малюсенький
2 4.9 3.0 1.4 0.2 setosa малюсенький
3 4.7 3.2 1.3 0.2 setosa малюсенький
4 4.6 3.1 1.5 0.2 setosa малюсенький
...
# Если мы хотим, чтобы на диаграммах разные виды ирисов всегда
# помечались конкретными цветами, можно сделать для этого отдельный
# столбец с названиями цветов
iris %>%
mutate(colors = case_when(
Species == "setosa" ~ "aquamarine2",
Species == "virginica" ~ "darkviolet",
Species == "versicolor" ~ "yellowgreen"
))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species colors
1 5.1 3.5 1.4 0.2 setosa aquamarine2
2 4.9 3.0 1.4 0.2 setosa aquamarine2
3 4.7 3.2 1.3 0.2 setosa aquamarine2
4 4.6 3.1 1.5 0.2 setosa aquamarine2
...
Впрочем, можно лаконичнее выполнить ту же процедуру с помощью следующей функции:
recode() — упрощенная версия case_when(),
когда нужно только поменять конкретные значения в столбце:iris %>%
mutate(colors = recode(Species,
"setosa" = "aquamarine2",
"virginica" = "darkviolet",
"versicolor" = "yellowgreen" ))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species colors
1 5.1 3.5 1.4 0.2 setosa aquamarine2
2 4.9 3.0 1.4 0.2 setosa aquamarine2
3 4.7 3.2 1.3 0.2 setosa aquamarine2
4 4.6 3.1 1.5 0.2 setosa aquamarine2
...
mtcars %>%
mutate(am = recode(am,
"0" = "automatic",
"1" = "manual")) %>%
select(am)
am
Mazda RX4 manual
Mazda RX4 Wag manual
Datsun 710 manual
Hornet 4 Drive automatic
Hornet Sportabout automatic
...
Если нужно совершить одинаковые преобразования столбцов таблицы без
создания новых переменных, используйте функцию
across():
mutate( across(столбцы, функция) )
Столбцы выбираются так же, как в
select(). Функция для преобразования указывается либо
названием (без кавычек, скобок и параметров), либо в виде анонимной лямбда-функции — так же, как в
map().
Несколько простых примеров использования across() внутри
mutate():
# Преобразуем три категориальных переменных mtcars в факторы:
mtcars %>%
mutate( across( c(am, cyl, gear), factor ) )
# Округлим числа во всех столбцах iris, не являющихся фактором:
iris %>%
mutate( across( !where(is.factor), round ) )
# Анонимная функция
# Преобразуем в iris все наблюдения в миллиметры
# Для этого умножим содержимое первых четырёх столбцов на 10:
iris %>%
mutate( across( 1:4, ~ (.x)*10 ) )
Для выбора строк используйте логическое выражение: запрос, который даст ответ “да” или “нет”. Функция применит этот запрос ко всем строкам таблицы и оставит только те, где получит ответ “да”.
Чаще всего сравнивают значения переменных с конкретными числами, строками текста или значениями других переменных с помощью операторов сравнения: <, >, <=, >=, != (не равно), == (равно). Обратите внимание на последний оператор! Одна из наиболее частых, вездесущих и раздражающих ошибок в R — случайное использование = вместо == при сравнении.
Операторы & и | позволяют объединять разные запросы так, чтобы либо они все должны дать ответ “да” (&), либо хотя бы один (|). В сложных случаях можно использовать скобки. Простые запросы можно перечислить через запятую — это аналогично объединению через &.
# Пример сложного условия
mtcars %>%
filter( (mpg > 20 & am == '0') | (am == '1' & cyl == '8'))
mpg cyl disp hp drat wt qsec vs am gear carb
Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
# Более типичный пример
iris %>%
filter(Species == 'virginica',
Petal.Length > 6.5)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 7.6 3.0 6.6 2.1 virginica
2 7.7 3.8 6.7 2.2 virginica
3 7.7 2.6 6.9 2.3 virginica
4 7.7 2.8 6.7 2.0 virginica
Помимо сравнений, значения переменных можно проверять с помощью
функций — главное, чтобы они давали ответ “да”/“нет” (TRUE/FALSE). В
частности, могут пригодиться is.na() (позволяет добавить
строки с пропущенными значениями — NA), is.numeric(),
is.factor(), и т.д.
Это работает аналогично номерам в квадратных скобках, но удобнее применять внутри конвейера.
Укажите, по какому столбцу проводить сортировку. Можно указать несколько столбцов: сначала будет использован первый, при равных значениях — второй, и т.д.
Чтобы сортировать по убыванию, “окружите” название столбца функцией
desc().
# Упорядочим машины по числу цилиндров, затем по типу коробки передач
# В каждой подгруппе отсортируем по убыванию mpg
mtcars %>%
arrange(cyl, am, desc(mpg)) %>%
select(cyl, am, mpg) # чтобы было удобнее смотреть
cyl am mpg
Merc 240D 4 0 24.4
Merc 230 4 0 22.8
Toyota Corona 4 0 21.5
Toyota Corolla 4 1 33.9
Fiat 128 4 1 32.4
Honda Civic 4 1 30.4
Lotus Europa 4 1 30.4
Fiat X1-9 4 1 27.3
Porsche 914-2 4 1 26.0
Datsun 710 4 1 22.8
Volvo 142E 4 1 21.4
Hornet 4 Drive 6 0 21.4
Merc 280 6 0 19.2
Valiant 6 0 18.1
Merc 280C 6 0 17.8
Mazda RX4 6 1 21.0
Mazda RX4 Wag 6 1 21.0
Ferrari Dino 6 1 19.7
Pontiac Firebird 8 0 19.2
Hornet Sportabout 8 0 18.7
Merc 450SL 8 0 17.3
Merc 450SE 8 0 16.4
Dodge Challenger 8 0 15.5
Merc 450SLC 8 0 15.2
AMC Javelin 8 0 15.2
Chrysler Imperial 8 0 14.7
Duster 360 8 0 14.3
Camaro Z28 8 0 13.3
Cadillac Fleetwood 8 0 10.4
Lincoln Continental 8 0 10.4
Ford Pantera L 8 1 15.8
Maserati Bora 8 1 15.0
Многие операции требуется проводить не на всех данных, а на
подгруппах. Например, посчитать среднюю длину “лепестков” ирисов из
таблицы iris для каждого вида отдельно. Или найти максимальный
показатель экономичности (mpg) для автомобилей из mtcars в зависимости
от числа цилиндров. Можно отбирать нужные строки командой
filter() и проводить операции на каждой полученной группе
по-отдельности — но это значительно увеличивает число команд и раздувает
код.
Команда group_by() позволяет удобно разбивать данные на
группы по значениям категориальных (текстовых, факторных) переменных.
При этом структура и отображение таблицы не меняются: функция просто
добавляет пометки, к какой группе принадлежит каждая строка. Последующие
операции с “группированной” таблицей будут проводиться отдельно по
каждой группе. В основном это функции mutate(), filter() и summarise().
Для примера сначала рассчитаем долю длины “лепестков” ирисов относительно их средней длины:
iris %>%
mutate(relative.size = Petal.Length / mean(Petal.Length)) %>%
select(Petal.Length, relative.size)
Petal.Length relative.size
1 1.4 0.3725386
2 1.4 0.3725386
3 1.3 0.3459287
4 1.5 0.3991485
...
А теперь относительно средней длины по каждому виду отдельно:
iris %>%
group_by(Species) %>%
mutate(relative.size = Petal.Length / mean(Petal.Length)) %>%
select(Petal.Length, relative.size)
# A tibble: 4 × 3
# Groups: Species [1]
Species Petal.Length relative.size
<fct> <dbl> <dbl>
1 setosa 1.4 0.958
2 setosa 1.4 0.958
3 setosa 1.3 0.889
4 setosa 1.5 1.03
...
Команда ungroup() отменяет группирование.
Группировка по нескольким переменным приведёт к созданию групп по всем сочетаниям значений группирующих переменных — см. примеры в следующем разделе.
Сводные таблицы могут содержать средние значения, стандартные отклонения, число измерений — словом, новые параметры, рассчитываемые по всем значениям исходных переменных.
Самый простой (и заведомо бесполезный) пример:
# Среднее значение 4-х переменных iris и общее число наблюдений:
iris %>%
summarise(S.L.mean = mean(Sepal.Length),
S.W.mean = mean(Sepal.Width),
P.L.mean = mean(Petal.Length),
P.W.mean = mean(Petal.Width),
count = n()
)
S.L.mean S.W.mean P.L.mean P.W.mean count
1 5.843333 3.057333 3.758 1.199333 150
Сам по себе этот пример неудачен, т.к. того же результата можно
гораздо проще добиться с помощью других команд: lapply(),
map(), summary(). Однако добавление функции group_by открывает мощные функциональные
возможности:
# Среднее значение 4-х переменных iris и общее число наблюдений,
# рассчитанные отдельно по каждому виду:
iris %>%
group_by(Species) %>% # единственная добавленная строка
summarise(S.L.mean = mean(Sepal.Length),
S.W.mean = mean(Sepal.Width),
P.L.mean = mean(Petal.Length),
P.W.mean = mean(Petal.Width),
count = n()
)
# A tibble: 3 × 6
Species S.L.mean S.W.mean P.L.mean P.W.mean count
<fct> <dbl> <dbl> <dbl> <dbl> <int>
1 setosa 5.01 3.43 1.46 0.246 50
2 versicolor 5.94 2.77 4.26 1.33 50
3 virginica 6.59 2.97 5.55 2.03 50
# Несколько статистик для всех сочетаний числа цилиндров
# и типа коробки передач автомобилей:
mtcars %>%
group_by(am, cyl) %>%
summarise(number.of.cars = n(), # сколько машин в группе
V.shaped = sum(vs == '0'), # сколько машин имеет V-образный двигатель
most.econom = max(mpg), # максимальный mpg
mean.weight = mean(wt) ) # средний вес
# A tibble: 6 × 6
# Groups: am [2]
am cyl number.of.cars V.shaped most.econom mean.weight
<dbl> <dbl> <int> <int> <dbl> <dbl>
1 0 4 3 0 24.4 2.94
2 0 6 4 0 21.4 3.39
3 0 8 12 12 19.2 4.10
4 1 4 8 1 33.9 2.04
5 1 6 3 3 21 2.76
6 1 8 2 2 15.8 3.37
Внутри summarise() можно использовать стандартные
функции R, такие как mean(), sd(),
max() и другие, дающие одно значение. В частности, обратите
внимание на следующие функции:
n() |
число строк в каждой группе |
sum(!is.na(x)) |
число непустых значений переменной х в каждой группе |
n_distinct(x) |
число уникальных значений переменной х в каждой группе |
sum(условие) |
число значений переменной х, удовлетворяющих условию |
first(x) |
первое значение переменной х в каждой группе |
nth(x, n) |
n-ное значение |
last(x) |
последнее значение |
По аналогии с mutate(), можно использовать функцию across(), чтобы упростить код. Так, выше был
рассмотрен расчет среднего значения четырёх переменных iris в
зависимости от видовой принадлежности. Сократим код ещё сильнее:
iris %>%
group_by(Species) %>%
summarise( across( 1:4, mean ) )
# A tibble: 3 × 5
Species Sepal.Length Sepal.Width Petal.Length Petal.Width
<fct> <dbl> <dbl> <dbl> <dbl>
1 setosa 5.01 3.43 1.46 0.246
2 versicolor 5.94 2.77 4.26 1.33
3 virginica 6.59 2.97 5.55 2.03
Можно применить к каждому столбцу сразу несколько функций:
iris %>%
group_by(Species) %>%
summarise( across( 1:4, list(mean=mean, sd=sd) ) )
# A tibble: 3 × 9
Species Sepal.Length_mean Sepal.Length_sd Sepal.Width_mean Sepal.Width_sd
<fct> <dbl> <dbl> <dbl> <dbl>
1 setosa 5.01 0.352 3.43 0.379
2 versicolor 5.94 0.516 2.77 0.314
3 virginica 6.59 0.636 2.97 0.322
# ℹ 4 more variables: Petal.Length_mean <dbl>, Petal.Length_sd <dbl>,
# Petal.Width_mean <dbl>, Petal.Width_sd <dbl>
Некоторые устанавливаемые пакеты из Tidyverse нужно
запускать “вручную” отдельными командами library() — в
дальнейшем это всегда будет явно указано.↩︎
В RStudio оператор конвейера %>% можно вставить сочетанием клавиш Ctrl+Shift+M.↩︎
Возможен даже совсем простой вариант
select(iris, is.numeric). Команда поругается, но всё
сделает правильно.↩︎