Найти max/min для колонки с рисунком в R
У меня возникли проблемы с разработкой данных.таблица, которая дает мне max/min на основе нескольких столбцов, которые разделяют шаблон имени.
Это упрощенная таблица:
int <- seq(as.POSIXct("2016-04-08"), as.POSIXct("2016-04-10"), by="6 h")
df <- data.frame(date = int, x_01 = runif(9), x_02 = runif(9), x_10 = runif(9), b_31 = runif(9))
df$date <- format(as.POSIXct(df$date), format = "%Y-%m-%dM")
Я знаю, как получить сводную статистику, применив следующий код:
sum <- setDT(df)[, list(x_01min=min(x_01), x_01max=max(x_01)), by=list(date)]
Моя цель-получить сводную статистику по всем столбцам с шаблоном " x_"
Я попытался вложить for
петли и использовать lapply
с grep
, но, похоже, не могу получить желаемых результатов. Приведенный ниже код должен показать, что я такое пытаюсь добраться до него.
sum <- setDT(df)[, list(x_01min=min(x_01), x_01max=max(x_01),
x_02min=min(x_02), x_02max=max(x_02),
x_10min=min(x_10), x_10max=max(x_10)), by=list(date)]
В идеале имена столбцов сводной таблицы должны включать имена из исходной таблицы. Мой фактический набор данных состоит из нескольких фреймов данных с различным количеством столбцов, соответствующих шаблону. По мере сбора новых данных будут добавляться новые переменные, поэтому важно иметь возможность выполнять функцию, основанную на шаблоне colname
.
Ваша помощь ценится!
3 ответа:
library(data.table); setDT(df); ## ensure df is a data.table cns <- grep(value=T,'^x_',names(df)); df[,do.call(c,lapply(cns,function(cn) { x <- get(cn); setNames(nm=paste0(cn,c('min','max')),.(min(x),max(x))); })),.(date)]; ## date x_01min x_01max x_02min x_02max x_10min x_10max ## 1: 2016-04-08M 0.2655087 0.9082078 0.06178627 0.6870228 0.21214252 0.93470523 ## 2: 2016-04-09M 0.2016819 0.9446753 0.38410372 0.7698414 0.12555510 0.65167377 ## 3: 2016-04-10M 0.6291140 0.6291140 0.99190609 0.9919061 0.01339033 0.01339033
Во-первых, имена целевых столбцов получаются путем вызова
grep()
с аргументомvalue=T
. Эти имена хранятся вcns
в глобальной среде.Затем данные.таблица индексируется, группируясь по
date
.Для каждой группы,
lapply()
выполняется над векторомcns
, принимая имя текущего столбца в качестве параметраcn
.Внутри лямбды вектор столбца извлекается и сохраняется в локальной переменной
x
, вызываяget()
наcn
, которая работает потому что это данные.столбцы таблицы всегда видны выражению аргументаj
.Наконец, итоговая статистика вычисляется в списке с помощью
.()
, а их имена задаются с помощьюsetNames()
, что позволяет нам динамически вычислять их изcn
сpaste0()
.Результатом вызова
lapply()
будет список списков, но поскольку нам нужно создать один не вложенный список для результата агрегации группы, мы должны запустить его черезdo.call(c,...)
, чтобы отменить вложенные списки. Один альтернативой здесь будетunlist(recursive=F,...)
. Оба варианта сохраняют имена вложенных списков, чего мы и добиваемся.
Бенчмаркинг
library(data.table); library(microbenchmark); bgoldst <- function(df) { cns <- grep(value=T,'^x_',names(df)); df[,do.call(c,lapply(cns,function(cn) { x <- get(cn); setNames(nm=paste0(cn,c('min','max')),.(min(x),max(x))); })),.(date)]; }; kunal <- function(df) { indices <- grep('x_',colnames(df)); col_names <- colnames(df)[indices]; query_min <- paste0(col_names,'min=min(',col_names,')'); query_max <- paste0(col_names,'max=max(',col_names,')'); query_1 <- paste(c(query_min,query_max),collapse=','); eval(parse(text=paste0('df[,.(',query_1,'),by=date]'))); }; psidom <- function(df) { cols <- names(df)[grepl('x_',names(df))]; newCols <- paste0(rep(cols,each=2),c('max','min')); sumFun <- function(col) list(max(col),min(col)); df[,c(newCols):=unlist(lapply(.SD,sumFun),recursive=F),.(date),.SDcols=cols]; unique(df[,.SD,.SDcols=c('date',newCols)]); };
set.seed(1L); int <- seq(as.POSIXct('2016-04-08'),as.POSIXct('2016-04-10'),by='6 h'); df <- data.frame(date=int,x_01=runif(9L),x_02=runif(9L),x_10=runif(9L),b_31=runif(9L)); df$date <- format(as.POSIXct(df$date),format='%Y-%m-%dM'); setDT(df); expected <- bgoldst(copy(df)); co <- names(expected); identical(expected,kunal(copy(df))[,co,with=F]); ## [1] TRUE identical(expected,psidom(copy(df))[,co,with=F]); ## [1] TRUE microbenchmark(bgoldst(copy(df)),kunal(copy(df)),psidom(copy(df))); ## Unit: milliseconds ## expr min lq mean median uq max neval ## bgoldst(copy(df)) 1.397569 1.445893 1.522512 1.490369 1.538908 2.749805 100 ## kunal(copy(df)) 1.318453 1.362287 1.483356 1.403555 1.443968 4.733684 100 ## psidom(copy(df)) 1.451881 1.532920 1.625494 1.573120 1.624010 3.097487 100
set.seed(1L); NR <- 500L; NC <- 100L; df <- data.frame( date=seq(as.POSIXct('2016-04-08'),by='6 h',len=NR), setNames(nm=paste0('x_',seq_len(NC)),as.data.frame(replicate(NC,runif(NR)))), b_31=runif(NR) ); df$date <- format(as.POSIXct(df$date),format='%Y-%m-%dM'); setDT(df); expected <- bgoldst(copy(df)); co <- names(expected); identical(expected,kunal(copy(df))[,co,with=F]); ## [1] TRUE identical(expected,psidom(copy(df))[,co,with=F]); ## [1] TRUE microbenchmark(bgoldst(copy(df)),kunal(copy(df)),psidom(copy(df))); ## Unit: milliseconds ## expr min lq mean median uq max neval ## bgoldst(copy(df)) 94.75322 100.94627 106.61343 102.37655 105.89292 164.58885 100 ## kunal(copy(df)) 21.38946 23.04383 24.60639 24.20192 25.18723 69.29593 100 ## psidom(copy(df)) 45.32431 48.76798 50.63476 49.60532 51.03667 92.41567 100
Вы можете попробовать этот код:
## building the data.table int <- seq(as.POSIXct("2016-04-08"), as.POSIXct("2016-04-10"), by="6 h") df <- data.frame(date = int, x_01 = runif(9), x_02 = runif(9), x_10 = runif(9), b_31 = runif(9)) df$date <- format(as.POSIXct(df$date), format = "%Y-%m-%dM") ## actual work begins here library(data.table) setDT(df) indices <- grep("x_",colnames(df)) col_names <- colnames(df)[indices] query_min <- paste0(col_names,'min=min(',col_names,')') query_max <- paste0(col_names,'max=max(',col_names,')') query_1 <- paste(c(query_min,query_max),collapse=',') eval(parse(text=paste0("df[,.(",query_1,"),by=date]"))) ## date x_01min x_02min x_10min x_01max x_02max x_10max ##1: 2016-04-08M 0.07527176 0.026276086 0.3315467 0.9404001 0.906662120 0.7069425 ##2: 2016-04-09M 0.34796983 0.065390319 0.2437374 0.8130796 0.739978420 0.6760062 ##3: 2016-04-10M 0.45671821 0.003374905 0.7245515 0.4567182 0.003374905 0.7245515
cols <- names(df)[grepl("x_", names(df))] newCols <- paste0(rep(cols, each = 2), c("max", "min")) sumFun <- function(col) list(max(col), min(col)) setDT(df)[, c(newCols) := unlist(lapply(.SD, sumFun), recursive = F), .(date), .SDcols = cols] sum <- unique(df[, .SD, .SDcols = c("date", newCols)]) > sum date x_01max x_01min x_02max x_02min x_10max x_10min 1: 2016-04-08M 0.8770486 0.1828969 0.99869872 0.159936264 0.8983131 0.3767007 2: 2016-04-09M 0.6475017 0.1429131 0.57890510 0.007439883 0.9242098 0.1077233 3: 2016-04-10M 0.9176341 0.9176341 0.05900942 0.059009423 0.2717861 0.2717861