data.tabela alternatywna dla przypadku dplyr, gdy
Jakiś czas temu wprowadzili ładną alternatywę podobną do SQL do ifelse
wewnątrz dplyr
, czyli case_when
.
Czy w data.table
istnieje odpowiednik, który pozwoliłby określić różne warunki w ramach jednego []
Oświadczenia, bez ładowania dodatkowych pakietów?
Przykład:
library(dplyr)
df <- data.frame(a = c("a", "b", "a"), b = c("b", "a", "a"))
df <- df %>% mutate(
new = case_when(
a == "a" & b == "b" ~ "c",
a == "b" & b == "a" ~ "d",
TRUE ~ "e")
)
a b new
1 a b c
2 b a d
3 a a e
Z pewnością byłoby to bardzo pomocne i uczyniłoby Kod o wiele bardziej czytelny (jeden z powodów, dla których wciąż używam dplyr
w tych przypadkach).
4 answers
[5]} dla twojej wiadomości, bardziej aktualna odpowiedź dla tych, którzy natkną się na ten post 2019. data.table
wersje powyżej 1.13.0 posiadają funkcję fcase
, która może być użyta. Zauważ, że nie jest to zamiennik dplyr::case_when
, ponieważ składnia jest inna, ale będzie to "natywny" data.table
sposób obliczania.
# Lazy evaluation
x = 1:10
data.table::fcase(
x < 5L, 1L,
x >= 5L, 3L,
x == 5L, stop("provided value is an unexpected one!")
)
# [1] 1 1 1 1 3 3 3 3 3 3
dplyr::case_when(
x < 5L ~ 1L,
x >= 5L ~ 3L,
x == 5L ~ stop("provided value is an unexpected one!")
)
# Error in eval_tidy(pair$rhs, env = default_env) :
# provided value is an unexpected one!
# Benchmark
x = sample(1:100, 3e7, replace = TRUE) # 114 MB
microbenchmark::microbenchmark(
dplyr::case_when(
x < 10L ~ 0L,
x < 20L ~ 10L,
x < 30L ~ 20L,
x < 40L ~ 30L,
x < 50L ~ 40L,
x < 60L ~ 50L,
x > 60L ~ 60L
),
data.table::fcase(
x < 10L, 0L,
x < 20L, 10L,
x < 30L, 20L,
x < 40L, 30L,
x < 50L, 40L,
x < 60L, 50L,
x > 60L, 60L
),
times = 5L,
unit = "s")
# Unit: seconds
# expr min lq mean median uq max neval
# dplyr::case_when 11.57 11.71 12.22 11.82 12.00 14.02 5
# data.table::fcase 1.49 1.55 1.67 1.71 1.73 1.86 5
Źródło , dane.1.13.0, wydany 24 lipca 2020 roku.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-26 06:13:03
1) Jeśli warunki wzajemnie się wykluczają z wartością domyślną, jeśli wszystkie warunki są fałszywe, to działa to:
library(data.table)
DT <- as.data.table(df) # df is from question
DT[, new := c("e", "c", "d")[1 +
1 * (a == "a" & b == "b") +
2 * (a == "b" & b == "a")]
]
Dając:
> DT
a b new
1: a b c
2: b a d
3: a a e
2) Jeżeli wyniki warunków są liczbowe, to jest to jeszcze łatwiejsze. Na przykład załóżmy, że zamiast c
i d
chcemy 10 i 17 z domyślną wartością 3. Wtedy:
library(data.table)
DT <- as.data.table(df) # df is from question
DT[, new := 3 +
(10 - 3) * (a == "a" & b == "b") +
(17 - 3) * (a == "b" & b == "a")]
3) zauważ, że dodanie 1-linera jest wystarczające, aby to zaimplementować. Zakłada ona, że w każdym rzędzie jest co najmniej jedna prawdziwa noga.
when <- function(...) names(match.call()[-1])[apply(cbind(...), 1, which.max)]
# test
DT[, new := when(c = a == 'a' & b == 'b',
d = a == 'b' & b == 'a',
e = TRUE)]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-28 14:48:15
To nie jest tak naprawdę odpowiedź, ale trochę za długa na komentarz. Jeśli uznasz za nieodpowiednie, chętnie usunę post.
Istnieje ciekawy post na RStudio Community , który omawia opcje użycia dplyr::case_when
bez zwykłych zależności tidyverse
.
Podsumowując, wydaje się, że istnieją trzy alternatywy:
-
Stefan Fleck wyizolował
case_when
zdplyr
i zbudował nowy pakietlest
to zależy tylko odbase
. -
yonicd opracowany
noplyr
, który "zapewnia podstawową funkcjonalnośćdplyr
itidyr
bez zależności tidyverse". -
Bob Rudis (hrbrmstr)jest twórcą
freebase
, "a' usethis '- like Package for Base R Pseudo-odpowiedniki kodu 'tidyverse'", które też warto sprawdzić.
Jeśli chodzi tylko o case_when
, wyobrażam sobie lest
może być atrakcyjną i minimalną opcją w połączeniu z data.table
.
[[54]} Aktualizacja [29 Października 2019]
Tyson Barrett tidyfast
dostępny (obecnie jako wersja 0.1.0
) na Githubie, który udostępnia funkcję "dt_case_when
for dplyr::case_when()
składnia z szybkością data.table::fifelse()
".
data.table
dla dplyr
. Celem dtplyr
jest pozwala na napisanie dplyr
kodu, który jest automatycznie tłumaczony na odpowiednik, ale zazwyczaj znacznie szybszy, data.table
kodu.".Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-25 08:37:57
Oto wariacja na temat odpowiedzi @ g-grothendieck, która działa na niewyłącznych Warunkach:
DT[, new := c("c", "d", "e")[
apply(cbind(
a == "a" & b == "b",
a == "b" & b == "a",
TRUE), 1, which.max)]
]
DT
# a b new
# 1: a b c
# 2: b a d
# 3: a a e
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-03 12:20:33