169 похожих чатов

Всем привет, иногда возникает задача сравнивать наборы числовых данных с

различными справочниками.
Долго не мог понять, как в lapply использовать одновременно .SD и имя колонки.
Нашел следующее решение.
library(data.table)

# набор данных
df <- data.table(a = c(1,3,5),
b = c(10,30,NA))

# справочник с границами
frontiers <- data.table(variable = c("a","b","c"),
min = c(2,20,30),
max = c(4,40,65))
frontiers
#> variable min max
#> 1: a 2 4
#> 2: b 20 40
#> 3: c 30 65

# оценка параметров по границам
cols_to_define = paste0(names(df), "_grade" )
df[, (cols_to_define) := mapply(function(x,n){
fcase(x < frontiers[variable == n, min], "below",
x > frontiers[variable == n, max], "above",
x >= frontiers[variable == n, min] & x <= frontiers[variable == n, max], "fine",
default = NA_character_)
},
x = .SD,
n = names(.SD),
SIMPLIFY = FALSE
)]
df
#> a b a_grade b_grade
#> 1: 1 10 below below
#> 2: 3 30 fine fine
#> 3: 5 NA above <NA>

Нормально ли решать задачу так или это адский костыль и есть более красивые решения?

1 ответов

11 просмотров

Неясна необходимость работы с колонками. Решение задачи в исходной постановке почти классическое. Если использовать dcast и melt, то второй вариант может оказаться даже быстрее. library(tidyverse) library(data.table) #> #> Присоединяю пакет: 'data.table' #> Следующие объекты скрыты от 'package:dplyr': #> #> between, first, last #> Следующий объект скрыт от 'package:purrr': #> #> transpose # набор данных df <- tibble(a = c(1,3,5), b = c(10,30,NA)) dt <- data.table(a = c(1,3,5), b = c(10,30,NA)) # справочник с границами frontiers <- data.table(variable = c("a","b","c"), min = c(2,20,30), max = c(4,40,65)) frontiers #> variable min max #> <char> <num> <num> #> 1: a 2 4 #> 2: b 20 40 #> 3: c 30 65 #> variable min max #> 1: a 2 4 #> 2: b 20 40 #> 3: c 30 65 # оценка параметров по границам f1 <- function(){ dt$a_grade <- NULL dt$b_grade <- NULL cols_to_define = paste0(names(df), "_grade" ) dt[, (cols_to_define) := mapply(function(x,n){ fcase(x < frontiers[variable == n, min], "below", x > frontiers[variable == n, max], "above", x >= frontiers[variable == n, min] & x <= frontiers[variable == n, max], "fine", default = NA_character_) }, x = .SD, n = names(.SD), SIMPLIFY = FALSE )] } f2 <- function(){ df %>% mutate(id = row_number()) %>% pivot_longer(cols = -id) %>% left_join(frontiers, by = c("name" = "variable")) %>% mutate(grade = if_else(between(value, min, max), "In", "Out")) %>% select(-min, -max) %>% pivot_wider(names_from = name, values_from = c(value, grade)) } bench::mark(f1(), f2(), check = FALSE) #> # A tibble: 2 × 6 #> expression min median `itr/sec` mem_alloc `gc/sec` #> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> #> 1 f1() 11.4ms 12.1ms 81.7 3.24MB 4.19 #> 2 f2() 18.6ms 19.2ms 50.2 3.49MB 9.56

Похожие вопросы

Обсуждают сегодня

30500 за редактор? )
Владимир
47
а через ESC-код ?
Alexey Kulakov
29
Чёт не понял, я ж правильной функцией воспользовался чтобы вывести отладочную информацию? но что-то она не ловится
notme
18
У меня есть функция где происходит это: write_bit(buffer, 1); write_bit(buffer, 0); write_bit(buffer, 1); write_bit(buffer, 1); write_bit(buffer, 1); w...
~
13
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
Ребят в СИ можно реализовать ООП?
Николай
33
Как передать управляющий символ в открытую через CreateProcess консоль? Собсна, есть процедура: procedure TRedirectThread.WriteData(Data: OEMString); var Written: Cardinal;...
Serjone
6
в JclConsole объявлено так: function CtrlHandler(CtrlType: DWORD): BOOL; stdcall; - где ваше объявление с stdcall? у вас на картинке нет stdcall
Karagy
8
https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_h_common.erl#L174 https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_olp.erl#L76 15 лет назад...
Maksim Lapshin
20
program test; {$mode delphi} procedure proc(v: int32); overload; begin end; procedure proc(v: int64); overload; begin end; var x: uint64; begin proc(x); end. Уж не знаю...
notme
6
Карта сайта