Я пытаюсь найти внезапное уменьшение значения (столбец v44
) во многих небольших группах (из file_id
и type
) в кадре данных / tibble (dat
).
Я хочу сначала избавиться от всех значений, которые являются слишком высокими или слишком низкими, а затем выбрать первое. Я рассчитываю разницу между значениями v44_diff
. Первое значение в каждой группе должно затем использоваться для пометки последующих значений, которые не должны показывать более чем fac
* уменьшение по сравнению с начальным значением.
РЕДАКТИРОВАТЬ: Хорошо, хорошо, я переписал ниже, чтобы небольшое представление.
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
library(tibble)
library(ggplot2)
min <- 3000
max <- 50000
fac <- 1.5
dat <- tribble( ~ file_id, ~ type, ~ cycle, ~ v44,
"hey", "std", 0, 50300,
"hey", "std", 1, 40000,
"hey", "std", 2, 35000,
"hey", "std", 3, 32000,
"hey", "std", 4, 31000,
"hey", "std", 5, 30000,
"hey", "std", 6, 29500,
"hey", "smp", 1, 40100,
"hey", "smp", 2, 35100,
"hey", "smp", 3, 32100,
"hey", "smp", 4, 5000,
"hey", "smp", 5, 20,
"hey", "smp", 6, 10,
"hi", "std", 0, 49000,
"hi", "std", 1, 39700,
"hi", "std", 2, 32000,
"hi", "std", 3, 30000,
"hi", "std", 4, 29500,
"hi", "std", 5, 29400,
"hi", "std", 6, 29200,
"hi", "smp", 1, 49100,
"hi", "smp", 2, 39600,
"hi", "smp", 3, 31100,
"hi", "smp", 4, 30000,
"hi", "smp", 5, 29600,
"hi", "smp", 6, 29400)
dat %>%
ggplot(aes(x = cycle, y = v44, colour = type)) +
geom_line(aes(group = paste(file_id, type))) +
facet_grid(rows = vars(type))
dat %>%
group_by(file_id, type) %>%
mutate(v44_low = v44 <= min, # creates a flag
v44_high = v44 >= max,
v44_diff = lead(v44) - v44) %>%
mutate(v44_drop = v44_diff < fac * first(filter(., !v44_low, !v44_high)$v44_diff)) %>%
ungroup(file_id, type)
#> # A tibble: 26 x 8
#> file_id type cycle v44 v44_low v44_high v44_diff v44_drop
#> <chr> <chr> <dbl> <dbl> <lgl> <lgl> <dbl> <lgl>
#> 1 hey std 0 50300 FALSE TRUE -10300 TRUE
#> 2 hey std 1 40000 FALSE FALSE -5000 FALSE
#> 3 hey std 2 35000 FALSE FALSE -3000 FALSE
#> 4 hey std 3 32000 FALSE FALSE -1000 FALSE
#> 5 hey std 4 31000 FALSE FALSE -1000 FALSE
#> 6 hey std 5 30000 FALSE FALSE -500 FALSE
#> 7 hey std 6 29500 FALSE FALSE NA NA
#> 8 hey smp 1 40100 FALSE FALSE -5000 FALSE
#> 9 hey smp 2 35100 FALSE FALSE -3000 FALSE
#> 10 hey smp 3 32100 FALSE FALSE -27100 TRUE
#> # … with 16 more rows
но это оказалось очень-очень медленно, так как существует много групп.
См. https://github.com/tidyverse/dplyr/issues/3294 для объяснения того, почему фильтрация во многих группах медленная.
Я знаю, как переписать это в более быструю версию, но она все равно создаст копию:
out <- dat %>%
group_by(file_id, type) %>%
mutate(v44_low = v44 <= min,
v44_high = v44 >= max,
v44_diff = lead(v44) - v44) %>%
filter(!v44_low, !v44_high) %>%
mutate(v44_drop = v44_diff < fac * first(.$v44_diff)) %>%
select(file_id, type, cycle, v44_drop)
out <- dat %>%
left_join(out, by = c("file_id", "type", "cycle")) %>%
ungroup(file_id, type)
out
#> # A tibble: 26 x 5
#> file_id type cycle v44 v44_drop
#> <chr> <chr> <dbl> <dbl> <lgl>
#> 1 hey std 0 50300 NA
#> 2 hey std 1 40000 FALSE
#> 3 hey std 2 35000 FALSE
#> 4 hey std 3 32000 FALSE
#> 5 hey std 4 31000 FALSE
#> 6 hey std 5 30000 FALSE
#> 7 hey std 6 29500 NA
#> 8 hey smp 1 40100 FALSE
#> 9 hey smp 2 35100 FALSE
#> 10 hey smp 3 32100 TRUE
#> # … with 16 more rows
Создано в 2020-02-26 с помощью пакета Представить (v0.3.0)
Это потому, что я хочу сохранить строки с высоким / низким значения, но я не хочу, чтобы они использовались для расчета разницы.
Можно ли переписать это, чтобы оно было быстрее? Где мне не нужно фильтровать внутри групп, и мне не нужно создавать копию для слияния обратно в конечный результат?