#r #dataframe #filter #dplyr #pipe
#r #dataframe #Фильтр #dplyr #канал
Вопрос:
У меня много фреймов данных, каждый из которых содержит несколько столбцов. Двумя из этих столбцов являются time
и value
.
Минимальный пример
library(tidyverse)
df <- approx(seq(1,10,1), c(1,5,7,11,4,12,30, 20, 10, 9)) %>%
as.data.frame() %>%
rename(time = x, value = y)
Цель
Я хочу удалить все строки из каждого фрейма данных, начиная с первого раза value > 10
.
Когда фрейм данных содержит values > 10
, решение будет следующим:
df <- df %>%
filter(row_number() <= first(which(value > 10))-1)
Однако существуют также фреймы данных, где значение value
не превышает 10
, например,
df <- approx(seq(1,10,1), c(1,5,7,1,4,2,1, 2, 1, 9)) %>%
as.data.frame() %>%
rename(time = x, value = y)
В этом случае фрейм данных не должен фильтроваться (поскольку value
пороговое значение не достигнуто). Однако, когда я использую filter
решение выше, оно возвращает пустой фрейм данных.
Вопрос
Как бы вы решили эту проблему внутри dplyr
канала? Возможно ли выполнить условную фильтрацию?
Ответ №1:
Вы могли бы написать условный оператор в filter
:
library(dplyr)
df %>%
filter(if(any(value > 10)) row_number() <= which.max(value > 10)-1 else TRUE)
Запись той же логики в slice
:
df %>%
slice(if(any(value > 10)) seq_len(which.max(value > 10)-1) else seq_len(n()))
Микробеншмарк
С точки зрения скорости, нет большой разницы между filter
и slice
:
df <- approx(seq(1,10^5,1),
round( runif(10^5, min = 1, max = 10^10) ) ) %>%
as.data.frame()
library(microbenchmark)
microbenchmark(
filter = df %>% filter(if(any(value > 10)) row_number() <= which.max(value > 10)-1 else TRUE),
slice = df %>% slice(if(any(value > 10)) seq_len(which.max(value > 10)-1) else seq_len(n())), times = 10000)
Unit: microseconds
expr min lq mean median uq max neval
filter 551.522 570.2715 655.7250 586.3530 621.5590 13575.81 10000
slice 614.276 633.6840 735.0398 654.2455 695.3795 14123.43 10000