#r #dplyr
Вопрос:
Я хотел бы использовать конвейерный рабочий процесс для регулярного применения dplyr::case_when
к набору данных из 10^4 строк и хотел бы избежать rowwise
этого, так как он очень медленный.
Я хотел бы сопоставить большое количество критериев с заданными значениями, например any(x = c(1:999, 3000:200000, 250000:250100)
, где length(x)
1, и применить его к каждой строке в a data.frame
.
Что-то вроде этой функции, но с гораздо большим количеством критериев:
is_good_car <- function(x){
any(
x == c(
"Mazda RX4",
"Datsun 710",
"Valiant"
)
)
}
Я мог бы применить это так:
library(dplyr)
mtcars %>%
mutate(
car = rownames(.)
) %>%
as_tibble %>%
mutate(
good_cars = case_when(
is_good_car(car) ~ "good",
TRUE ~ "rubbish"
)
) %>%
select(car, good_cars)
#> Warning in x == c("Mazda RX4", "Datsun 710", "Valiant"): longer object length is
#> not a multiple of shorter object length
#> # A tibble: 32 x 2
#> car good_cars
#> <chr> <chr>
#> 1 Mazda RX4 good
#> 2 Mazda RX4 Wag good
#> 3 Datsun 710 good
#> 4 Hornet 4 Drive good
#> 5 Hornet Sportabout good
#> 6 Valiant good
#> 7 Duster 360 good
#> 8 Merc 240D good
#> 9 Merc 230 good
#> 10 Merc 280 good
#> # ... with 22 more rows
Но это не работает, потому что он просто возвращает один TRUE
из is_good_car
и возвращает это в каждую строку.
Я могу использовать rowwise
, чтобы получить правильный ответ, но для моей цели это слишком медленно:
mtcars %>%
mutate(
car = rownames(.)
) %>%
as_tibble %>%
rowwise %>%
mutate(
good_cars = case_when(
is_good_car(car) ~ "good",
TRUE ~ "rubbish"
)
) %>%
select(car, good_cars)
#> # A tibble: 32 x 2
#> # Rowwise:
#> car good_cars
#> <chr> <chr>
#> 1 Mazda RX4 good
#> 2 Mazda RX4 Wag rubbish
#> 3 Datsun 710 good
#> 4 Hornet 4 Drive rubbish
#> 5 Hornet Sportabout rubbish
#> 6 Valiant good
#> 7 Duster 360 rubbish
#> 8 Merc 240D rubbish
#> 9 Merc 230 rubbish
#> 10 Merc 280 rubbish
#> # ... with 22 more rows
Я мог sapply
бы также использовать, но я хочу включить его в конвейерный рабочий процесс, как описано выше:
sapply(
X = rownames(mtcars),
FUN = is_good_car
)
#> Mazda RX4 Mazda RX4 Wag Datsun 710 Hornet 4 Drive
#> TRUE FALSE TRUE FALSE
#> Hornet Sportabout Valiant Duster 360 Merc 240D
#> FALSE TRUE FALSE FALSE
#> Merc 230 Merc 280 Merc 280C Merc 450SE
#> FALSE FALSE FALSE FALSE
#> Merc 450SL Merc 450SLC Cadillac Fleetwood Lincoln Continental
#> FALSE FALSE FALSE FALSE
#> Chrysler Imperial Fiat 128 Honda Civic Toyota Corolla
#> FALSE FALSE FALSE FALSE
#> Toyota Corona Dodge Challenger AMC Javelin Camaro Z28
#> FALSE FALSE FALSE FALSE
#> Pontiac Firebird Fiat X1-9 Porsche 914-2 Lotus Europa
#> FALSE FALSE FALSE FALSE
#> Ford Pantera L Ferrari Dino Maserati Bora Volvo 142E
#> FALSE FALSE FALSE FALSE
Есть ли какие-либо варианты использования функции, например is_good_car
, по желанию, внутри case_when
без использования rowwise
?
Создано 2021-09-22 пакетом reprex (v2.0.1)
Ответ №1:
Для сравнения нескольких значений вы должны использовать %in%
.
is_good_car <- function(x){
x %in% c(
"Mazda RX4",
"Datsun 710",
"Valiant"
)
}
тогда вы можете использовать его без rowwise
—
library(dplyr)
mtcars %>%
mutate(
car = rownames(.)
) %>%
as_tibble %>%
mutate(
good_cars = case_when(is_good_car(car) ~ "good",
TRUE ~ "rubbish"
)
) %>%
select(car, good_cars)
# car good_cars
# <chr> <chr>
# 1 Mazda RX4 good
# 2 Mazda RX4 Wag rubbish
# 3 Datsun 710 good
# 4 Hornet 4 Drive rubbish
# 5 Hornet Sportabout rubbish
# 6 Valiant good
# 7 Duster 360 rubbish
# 8 Merc 240D rubbish
# 9 Merc 230 rubbish
#10 Merc 280 rubbish
# … with 22 more rows
Ответ №2:
Если ты изменишься ==
на %in%
такой:
is_good_car <- function(x){
any(
x %in% c(
"Mazda RX4",
"Datsun 710",
"Valiant"
)
)
}
Функция теперь векторизована и будет быстрой и не понадобится rowwise
.
Ответ №3:
Мы могли бы использовать map
, и это должно быть быстрее, чем rowwise
library(purrr)
library(tibble)
library(dplyr)
mtcars %>%
rownames_to_column('car') %>%
mutate(good_cars = case_when(map_lgl(car, is_good_car) ~
'good', TRUE ~ 'rubbish')) %>%
as_tibble
-выход
# A tibble: 32 x 13
car mpg cyl disp hp drat wt qsec vs am gear carb good_cars
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
1 Mazda RX4 21 6 160 110 3.9 2.62 16.5 0 1 4 4 good
2 Mazda RX4 Wag 21 6 160 110 3.9 2.88 17.0 0 1 4 4 rubbish
3 Datsun 710 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1 good
4 Hornet 4 Drive 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1 rubbish
5 Hornet Sportabout 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2 rubbish
6 Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1 good
7 Duster 360 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4 rubbish
8 Merc 240D 24.4 4 147. 62 3.69 3.19 20 1 0 4 2 rubbish
9 Merc 230 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2 rubbish
10 Merc 280 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4 rubbish
# … with 22 more rows
Или есть другой вариант использования %in%
, и без case_when
него его можно изменить
is_good_car <- function(x){
x %in% c(
"Mazda RX4",
"Datsun 710",
"Valiant"
)
}
-тестирование
mtcars %>%
rownames_to_column('car') %>%
mutate(good_cars = c("rubbish", "good")[1 is_good_car(car)])
-выход
car mpg cyl disp hp drat wt qsec vs am gear carb good_cars
1 Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 good
2 Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 rubbish
3 Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 good
4 Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 rubbish
5 Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2 rubbish
6 Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1 good
7 Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4 rubbish
....
Кроме того, если нам нужен более быстрый подход, используйте data.table
library(data.table)
mtcars1 <- copy(mtcars)
setDT(mtcars, keep.rownames = TRUE)[, good_cars := 'rubbish'
][rn %chin% c( "Mazda RX4",
"Datsun 710",
"Valiant"), good_cars := 'good'][]