Как фильтровать фрейм данных для последовательно возрастающих значений

#r #dataframe #dplyr

#r #фрейм данных #dplyr

Вопрос:

У меня есть большой фрейм данных с несколькими столбцами, но для этого запроса меня интересуют 3 столбца.

 df <- structure(list(country = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "ireland", class = "factor"), 
    parameter = structure(c(2L, 1L, 3L, 2L, 1L, 3L, 2L, 1L, 3L,2L, 1L, 3L), .Label = c("rainfall", "temp", "wind"), class = "factor"), 
    value = c(10L, 15L, 20L, 9L, 18L, 10L, 12L, 25L, 15L, 10L, 10L, 20L), unit = structure(c(3L, 2L, 1L, 3L, 2L, 1L, 3L, 
    2L, 1L, 3L, 2L, 1L), .Label = c("km/hr", "mm", "oC"), class = "factor")), class = "data.frame", row.names = c(NA, -12L))

country parameter   value   unit
ireland temp          10    oC
ireland rainfall      15    mm
ireland wind          20    km/hr
ireland temp           9    oC
ireland rainfall      18    mm
ireland wind          10    km/hr
ireland temp          12    oC
ireland rainfall      25    mm
ireland wind          15    km/hr
ireland temp          10    oC
ireland rainfall      10    mm
ireland wind          20    km/hr
  

Я хочу сгруппировать по стране и параметру, чтобы извлечь строки, в которых столбец значений последовательно увеличивается в 3 или более раз.

Пример вывода desire.

 country parameter   value   unit
ireland rainfall      15    mm
ireland rainfall      18    mm
ireland rainfall      25    mm
ireland wind          10    km/hr
ireland wind          15    km/hr
ireland wind          20    km/hr
  

Комментарии:

1. diff() предоставляет разницу между одним значением и следующим в списке. Возможно, проверка на diff(df) > 3 ? После вас sort(df, decreasing=TRUE) , конечно.

2. Почему у вас есть для wind последних 20? Есть два значения по 20, поэтому разница равна нулю. Правильно ли там иметь 20?

Ответ №1:

Вы можете сгруппировать по стране и параметру, и они создадут третью группирующую переменную для значений, которые не меньше запаздывающего значения, затем отфильтруйте группы размером 3 или больше:

 library(dplyr)

df %>%
  group_by(country, parameter) %>%
  group_by(x = cumsum(value <= lag(value, default = FALSE)), .add = TRUE) %>%
  filter(n() >= 3) %>%
  ungroup() %>%
  arrange(country, parameter) %>%
  select(-x)

# A tibble: 6 x 4
  country parameter value unit 
  <fct>   <fct>     <int> <fct>
1 ireland rainfall     15 mm   
2 ireland rainfall     18 mm   
3 ireland rainfall     25 mm   
4 ireland wind         10 km/hr
5 ireland wind         15 km/hr
6 ireland wind         20 km/hr
  

Комментарии:

1. Это выглядит великолепно, но некорректно работает с моим фактическим фреймом данных, и я не уверен, почему. Я попытался преобразовать свои столбцы в коэффициенты и промежуточные. Использование разных групп столбцов по комбинациям. Я даже просто вернул его обратно в группу только по параметру. Возвращаемые результаты включают отбрасывания после последовательного увеличения.

2. В пределах страны и групп параметров будут возвращены все экземпляры с 3 или более последовательно возрастающими значениями. Вам нужен только первый набор этих значений? из вашего поста не ясно.

3. Если значения продолжают увеличиваться, да. Если есть падение, я не хочу, чтобы об этом сообщалось. Я хочу значения, которые выглядят как 1,2,3,4,5, а не 1,2,3,1,1,2,1. Надеюсь, это имеет больше смысла.

4. Да, но как насчет 1,2,3,1,2,3,4,1,2 — что бы вы хотели вернуть в этом случае? Вы хотите 1,2,3, потому что это первый набор последовательно увеличивающихся значений, или 1,2,3,4, потому что он самый длинный, или оба?

5. Оба. Но в текущей форме я получаю: (непосредственно из выходных данных в моем df) 7,16, 30, 10, 1, 7,13, 15, 30…… 10 должны были отфильтроваться?

Ответ №2:

Вот базовый вариант R, использующий subset ave rle

 subset(
  df[with(df,order(country, parameter)), ],
  !!ave(value, country, parameter, FUN = function(x) with(rle(cumsum(c(1, diff(x) <= 0))), rep(lengths >= 3, lengths)))
)
  

что дает

    country parameter value  unit
2  ireland  rainfall    15    mm
5  ireland  rainfall    18    mm
8  ireland  rainfall    25    mm
6  ireland      wind    10 km/hr
9  ireland      wind    15 km/hr
12 ireland      wind    20 km/hr
  

Ответ №3:

 df %>% 
  group_by(country, parameter) %>% 
  mutate(
    flag = c(0, diff(value)) > 0,
    flag_lag = lead(flag),
    seq_end = flag == TRUE amp; flag_lag %in% c(NA, FALSE),
    seq_begin = flag == FALSE amp; flag_lag == TRUE,
  ) %>%
  slice(if(length(which(seq_begin == TRUE):which(seq_end == TRUE)) >= 3) which(seq_begin == TRUE):which(seq_end == TRUE) else NA) %>%
  select(-contains("flag"), -contains("seq"))
  

Комментарии:

1. lag() более mutate удобен, поскольку вам не придется вручную присваивать первое значение.

Ответ №4:

Вот решение, использующее dplyr

 df %>%
  arrange(value,decreasing = FALSE) %>% # Arrange by value
  filter(lag(value) > 3) # And filter for a difference above 3 in value

df
   country parameter value  unit
1  ireland      temp    10    oC
2  ireland      wind    10 km/hr
3  ireland      temp    10    oC
4  ireland  rainfall    10    mm
5  ireland      temp    12    oC
6  ireland  rainfall    15    mm
7  ireland      wind    15 km/hr
8  ireland  rainfall    18    mm
9  ireland      wind    20 km/hr
10 ireland      wind    20 km/hr
11 ireland  rainfall    25    mm