Меня часто спрашиваютc студенты, вот мы загрузили данные в R, а как их потом обрабатывать? В Excel это всё просто, там есть сводные таблицы, фильтры. А как тут? Неужели все сложно? Нет, отнюдь.
Давайте рассмотрим несколько рецептов на примере данных mtcars. Напоминаю, что команда head выводит первые несколько строк большой таблицы. Чтобы не перегружать заметку я её буду использовать практически в каждой команде.
data("mtcars")
head(mtcars)
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
Сортируем данные
Классический подход к сортировке в R с помощью команды order выглядит так:
head(mtcars[order(mtcars$mpg, mtcars$cyl, mtcars$hp),])
## mpg cyl disp hp drat wt qsec vs am gear carb
## Cadillac Fleetwood 10.4 8 472 205 2.93 5.250 17.98 0 0 3 4
## Lincoln Continental 10.4 8 460 215 3.00 5.424 17.82 0 0 3 4
## Camaro Z28 13.3 8 350 245 3.73 3.840 15.41 0 0 3 4
## Duster 360 14.3 8 360 245 3.21 3.570 15.84 0 0 3 4
## Chrysler Imperial 14.7 8 440 230 3.23 5.345 17.42 0 0 3 4
## Maserati Bora 15.0 8 301 335 3.54 3.570 14.60 0 1 5 8
или так, если добавить команду with (чтобы проще записывать названия колонок):
head(with(mtcars,mtcars[order(mpg, cyl, hp),]))
## mpg cyl disp hp drat wt qsec vs am gear carb
## Cadillac Fleetwood 10.4 8 472 205 2.93 5.250 17.98 0 0 3 4
## Lincoln Continental 10.4 8 460 215 3.00 5.424 17.82 0 0 3 4
## Camaro Z28 13.3 8 350 245 3.73 3.840 15.41 0 0 3 4
## Duster 360 14.3 8 360 245 3.21 3.570 15.84 0 0 3 4
## Chrysler Imperial 14.7 8 440 230 3.23 5.345 17.42 0 0 3 4
## Maserati Bora 15.0 8 301 335 3.54 3.570 14.60 0 1 5 8
Однако с библиотекой dplyr это выглядит гораздо проще для чтения:
library(dplyr)
head(arrange(mtcars, mpg, cyl, hp))
## mpg cyl disp hp drat wt qsec vs am gear carb
## 1 10.4 8 472 205 2.93 5.250 17.98 0 0 3 4
## 2 10.4 8 460 215 3.00 5.424 17.82 0 0 3 4
## 3 13.3 8 350 245 3.73 3.840 15.41 0 0 3 4
## 4 14.3 8 360 245 3.21 3.570 15.84 0 0 3 4
## 5 14.7 8 440 230 3.23 5.345 17.42 0 0 3 4
## 6 15.0 8 301 335 3.54 3.570 14.60 0 1 5 8
Единственный недостаток — пропали имена строк. Но, если там была значимая информация, логично было бы держать её в отдельной колонке или воспользоваться пакетом tibble и функцией rownames_to_column.
library(tibble)
head(newcars<-rownames_to_column(mtcars))
## rowname mpg cyl disp hp drat wt qsec vs am gear carb
## 1 Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## 2 Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## 3 Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## 4 Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## 5 Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
## 6 Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
Конвейерная обработка
Интересный результат можно получить если использовать конвейерную обработку, сейчас dplyr использует для неё оператор %>% из пакета magrittr. В приведенном ниже примере, мы говорим, что хотим группировать данные по колонкам cyl и am, отобрать из всех только колонки mpg, cyl, wt, am, причём при группировке по двум колонкам найти средние значения, после чего, результат отфильтровать.
newcars %>%
group_by(cyl, am) %>%
select(mpg, cyl, wt, am) %>%
summarise(avgmpg = mean(mpg), avgwt = mean(wt)) %>%
filter(avgmpg > 20)
## # A tibble: 3 x 4
## # Groups: cyl [2]
## cyl am avgmpg avgwt
## <dbl> <dbl> <dbl> <dbl>
## 1 4 0 22.90000 2.93500
## 2 4 1 28.07500 2.04225
## 3 6 1 20.56667 2.75500
Полезные рецепты
Привожу несколько распространенных задач на преобразование таблиц.
- Отобрать из таблицы только нужные данные, записать все в X, при этом вывести для контроля первые шесть строк.
library(magrittr)
head(X<-newcars %>% filter(cyl == 8))
## rowname mpg cyl disp hp drat wt qsec vs am gear carb
## 1 Hornet Sportabout 18.7 8 360.0 175 3.15 3.44 17.02 0 0 3 2
## 2 Duster 360 14.3 8 360.0 245 3.21 3.57 15.84 0 0 3 4
## 3 Merc 450SE 16.4 8 275.8 180 3.07 4.07 17.40 0 0 3 3
## 4 Merc 450SL 17.3 8 275.8 180 3.07 3.73 17.60 0 0 3 3
## 5 Merc 450SLC 15.2 8 275.8 180 3.07 3.78 18.00 0 0 3 3
## 6 Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.25 17.98 0 0 3 4
Если нужно отобрать текст, а не числа (несколько примеров). Библиотека :
library(stringr)
newcars %>% filter(str_detect(rowname,"RX4"))
## rowname mpg cyl disp hp drat wt qsec vs am gear carb
## 1 Mazda RX4 21 6 160 110 3.9 2.620 16.46 0 1 4 4
## 2 Mazda RX4 Wag 21 6 160 110 3.9 2.875 17.02 0 1 4 4
newcars %>% filter(str_detect(rowname,"Hornet"))
## rowname mpg cyl disp hp drat wt qsec vs am gear carb
## 1 Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## 2 Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
newcars %>% filter(str_detect(rowname,"Hornet|RX4"))
## rowname mpg cyl disp hp drat wt qsec vs am gear carb
## 1 Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## 2 Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## 3 Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## 4 Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
newcars %>% filter(str_detect(rowname,"Hornet|RX4") & cyl==6)
## rowname mpg cyl disp hp drat wt qsec vs am gear carb
## 1 Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## 2 Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## 3 Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
- Взять из таблицы только нужные колонки данных (mpg, cyl,am), сгруппировать по (cyl, am) и найти среднее по mpg.
head(Y<-newcars %>%
group_by(cyl, am) %>%
select(mpg, cyl,am) %>%
summarise(avgmpg = mean(mpg)))
## # A tibble: 6 x 3
## # Groups: cyl [3]
## cyl am avgmpg
## <dbl> <dbl> <dbl>
## 1 4 0 22.90000
## 2 4 1 28.07500
## 3 6 0 19.12500
## 4 6 1 20.56667
## 5 8 0 15.05000
## 6 8 1 15.40000
- Построить “сводную таблицу”» из полученных данных.
library(tidyr)
##
## Attaching package: 'tidyr'
## The following object is masked from 'package:magrittr':
##
## extract
Y %>% spread(am,avgmpg)
## # A tibble: 3 x 3
## # Groups: cyl [3]
## cyl `0` `1`
## * <dbl> <dbl> <dbl>
## 1 4 22.900 28.07500
## 2 6 19.125 20.56667
## 3 8 15.050 15.40000
- Ёще несколько полезных примеров
newcars %>% group_by(cyl, am) %>% summarise_all(c("mean", "sd"))
## Warning in mean.default(rowname): argument is not numeric or logical:
## returning NA
## Warning in var(if (is.vector(x) || is.factor(x)) x else as.double(x), na.rm
## = na.rm): в результате преобразования созданы NA
## # A tibble: 6 x 22
## # Groups: cyl [?]
## cyl am rowname_mean mpg_mean disp_mean hp_mean drat_mean wt_mean
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 4 0 NA 22.90000 135.8667 84.66667 3.770000 2.935000
## 2 4 1 NA 28.07500 93.6125 81.87500 4.183750 2.042250
## 3 6 0 NA 19.12500 204.5500 115.25000 3.420000 3.388750
## 4 6 1 NA 20.56667 155.0000 131.66667 3.806667 2.755000
## 5 8 0 NA 15.05000 357.6167 194.16667 3.120833 4.104083
## 6 8 1 NA 15.40000 326.0000 299.50000 3.880000 3.370000
## # ... with 14 more variables: qsec_mean <dbl>, vs_mean <dbl>,
## # gear_mean <dbl>, carb_mean <dbl>, rowname_sd <dbl>, mpg_sd <dbl>,
## # disp_sd <dbl>, hp_sd <dbl>, drat_sd <dbl>, wt_sd <dbl>, qsec_sd <dbl>,
## # vs_sd <dbl>, gear_sd <dbl>, carb_sd <dbl>
newcars %>% summarise_if(is.numeric,c("mean", "sd"))
## mpg_mean cyl_mean disp_mean hp_mean drat_mean wt_mean qsec_mean vs_mean
## 1 20.09062 6.1875 230.7219 146.6875 3.596563 3.21725 17.84875 0.4375
## am_mean gear_mean carb_mean mpg_sd cyl_sd disp_sd hp_sd
## 1 0.40625 3.6875 2.8125 6.026948 1.785922 123.9387 68.56287
## drat_sd wt_sd qsec_sd vs_sd am_sd gear_sd carb_sd
## 1 0.5346787 0.9784574 1.786943 0.5040161 0.4989909 0.7378041 1.6152
mtcars %>% group_by(cyl) %>% mutate(rank = min_rank(desc(mpg)))
## # A tibble: 32 x 12
## # Groups: cyl [3]
## mpg cyl disp hp drat wt qsec vs am gear carb rank
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <int>
## 1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 2
## 2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 2
## 3 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 8
## 4 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 1
## 5 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2 2
## 6 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1 6
## 7 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4 11
## 8 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2 7
## 9 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2 8
## 10 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4 5
## # ... with 22 more rows