Fcase dla wielu wyjść

0

Pytanie

Załóżmy, że w poniższej tabeli:

data <- data.table(dummy=1:10)

Wiem, że można zrobić następujące rzeczy:

data[dummy < 5, c("test1", "test2") := list("Yes", 1)]

i:

data[, test1 := fcase(dummy < 5, "Yes")]
data[, test2 := fcase(dummy < 5, 1)]

Próbuję połączyć je w jedno, to tak:

data[, c("test1", "test2") := fcase(dummy < 5, list("Yes", 1))]

Ale to daje mi następujący błąd:

Error in fcase(dummy < 5, list("Yes", 1)) : 
  Length of output value #2 must either be 1 or length of logical condition.

Muszę przejść przez kilka filtrów, więc ma to sens używać fcase. Zawsze mogę uciec się do użycia pierwszego rozwiązania dla każdego filtra, na przykład:

data[dummy < 5, c("test1", "test2") := list("Yes", 1)]
data[dummy > 7, c("test1", "test2") := list("No", 0)]
data[between(dummy, 5, 7), c("test1", "test2") := list("Maybe", NA)]

ale zastanawiam się, czy nie ma czegoś bardziej możliwe. Istnieje również rozwiązanie tworzenia tabeli z każdej kombinacji test1 i test2 i połącz tę tabelę z tabelą danych po wykonaniu fcase tylko dla test1 oto tak:

tests <- data.table(test1 = c("Yes", "No", "Maybe"),
                    test2 = c(1, 0, NA))

data[, test1 := fcase(dummy < 5, "Yes",
                      dummy > 7, "No",
                      between(dummy, 5, 7), NA_character_)]
merge(data, tests, by = "test1", all.x = T, sort = F)

Ale to wydaje się być nieskuteczne dla dużej i skomplikowanej bazy danych

case data.table r
2021-11-17 16:48:12
1

Najlepsza odpowiedź

4

Z rbindlist:

data[, c("test1", "test2") := rbindlist(fcase(dummy < 5, .(.("Yes", 1)),
                                              dummy > 7, .(.("No", 0)),
                                              default = .(.("Maybe", NA))))]
data
#>     dummy test1 test2
#>  1:     1   Yes     1
#>  2:     2   Yes     1
#>  3:     3   Yes     1
#>  4:     4   Yes     1
#>  5:     5 Maybe    NA
#>  6:     6 Maybe    NA
#>  7:     7 Maybe    NA
#>  8:     8    No     0
#>  9:     9    No     0
#> 10:    10    No     0

do.call pozwoli ci umieścić fcase warunki do listy i wartości w innym liście zagnieżdżonych list:

data[, c("test1", "test2") := rbindlist(do.call(fcase, rbind(.(dummy < 5, dummy <= 7, dummy > 7),
                                                             .(.(.("Yes", 1)), .(.("Maybe", NA)), .(.("No", 0))))))]

Lub za pomocą tests przykład:

tests <- data.table(test1 = c("Yes", "Maybe", "No"),
                    test2 = c(1, NA, 0))
tests[, val := .(.(.(.SD))), by = 1:nrow(tests)]
data[, c("test1", "test2") := rbindlist(do.call(fcase, rbind(.(dummy < 5, dummy <= 7, dummy > 7), tests$val)))]
2021-11-22 13:23:13

Cześć @jblood94 Doskonała odpowiedź, elegancki i pouczająca. Dziękuję, że dzielisz się. Twoje zdrowie.
lovalery

To jest dokładnie to, czego szukałem! Wielkie dzięki
Wietse de Vries

Cześć @jblood94, w tym samym duchu, nie wiesz, czy jesteś, czy istnieje sposób, aby umieścić również różne testy na listę i wartości w innej listy. Mimo, że wiem, że składnia, który proponuję, jest nieprawidłowy, dla jasności napisz coś takiego: rbindlist(fcase(.(dummy < 5, dummy > 7), .(.("Yes", 1)), .(.("No", 0))), default = .(.("Maybe", NA))))] . Z góry dziękujemy za wasze opinie. Twoje zdrowie.
lovalery

@lovalery dodałem kilka przykładów zgodnie z pytaniem-komentarzem.
jblood94

Dziękuję bardzo @jblood94. Twoje przykłady sprawiają, że mam zadać ostatnie pytanie! Naśladując twój ostatni przykład, próbowałem poradzić sobie z cases jak poradziłeś sobie z tests ale R zwraca następujący komunikat o błędzie: Error in (function (..., default = NA) : Argument #1 must be logical. Oto co zrobiłem: cases <- data.table(Ncases = c("dummy < 5", "dummy <= 7", "dummy > 7"))wtedy cases[, val := .(.(.(. SD))), by = 1:nrow(cases)] i, w końcu, data[, c("test1", "test2") := rbindlist(do.call(fcase, rbind(.(as.list(cases$val)), as.list(tests$val))))] Z góry dziękuję za pomoc. Twoje zdrowie.
lovalery

@lovalery fcase nie będzie odbierać polecenia dla when argumenty. Można to obejść poprzez Ncases wektor wyrażeń. To nie jest zgodne sprawie OP, więc wolałbym nie zaśmiecać swoją odpowiedź jeszcze więcej. Proponuję utworzyć nowe pytanie i odnieść się do tego-może ktoś wymyśli lepszy sposób, niż to, o czym myślę.
jblood94

Ok Wielkie dzięki @jblood94 za twój komentarz. Postaram się zbadać sposób, który mi podano, i jeśli popełnię błędu (co jest bardzo prawdopodobne!), opublikuje nowe pytanie, powołując się na to, jak sugerujesz. Twoje zdrowie.
lovalery

W innych językach

Ta strona jest w innych językach

Русский
..................................................................................................................
Italiano
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................