R: Сохранить первые значения во временных рядах после NA и установить 3 последовательных значения в NA - PullRequest
0 голосов
/ 02 декабря 2018

У меня есть фрейм данных со многими временными рядами в столбцах (пример для одного ряда в столбце col1).Я хотел бы просмотреть каждый временной ряд и оставить первое значение, которое появляется после NA, и установить только для последовательных 3 значений в NA (пример желаемого результата в col2).В идеале это должно работать для всех или указанных (например, [2:30]) столбцов во фрейме данных.

Этот ответ не учитывает условие только 3 последовательных значений для NA.

Пример данных

df <- data.frame(
col1 = c(7.00, NA, NA, 1.00, 2.00, 5.00, NA, 5.00, 7.00, NA, NA, 1.00, NA, 2.00, NA, NA, 1.00, 3.00, 4.00, 5.00, 6.00, 7.00, NA, 7.00, NA),
col2 = c(7.00, NA, NA, 1.00, NA, NA, NA, 5.00, NA, NA, NA, 1.00, NA, 2.00, NA, NA, 1.00, NA, NA, NA, 6.00, NA, NA, 7.0, NA),
                     stringsAsFactors = FALSE)

Спасибо за помощь.

1 Ответ

0 голосов
/ 03 декабря 2018

Вот подход, использующий dplyr.

Сначала я создаю новую группу каждый раз, когда у нас есть правильное значение, следующее за NA.Затем в каждой группе я устанавливаю для 2-й и 4-й строк значение NA, в противном случае используется col1.

library(dplyr)

df %>%
  mutate(new_grp = if_else(!is.na(col1) & is.na(lag(col1)), 1, 0),
         grp = cumsum(new_grp)) %>%
  group_by(grp) %>%
  # Modified below per OP clarification: treat each group of 4 entries
  #   following an NA like the first four, with one value and then 3 NAs.
  #   Uses modulo 4, where any row with a remainder of 2, 3, or 0 (ie row 4, etc.) will get NA
  mutate(col2b = case_when(row_number() %% 4 %in% c(2:3, 0)  ~ NA_real_,
                          TRUE ~ col1)) %>%
  ungroup() 

Вывод:

row col1 col2 col2b
1   7   7   7
2   NA  NA  NA
3   NA  NA  NA
4   1   1   1
5   2   NA  NA
6   5   NA  NA
7   NA  NA  NA
8   5   5   5
9   7   NA  NA
10  NA  NA  NA
11  NA  NA  NA
12  1   1   1
13  NA  NA  NA
14  2   2   2
15  NA  NA  NA
16  NA  NA  NA
17  1   1   1
18  3   NA  NA
19  4   NA  NA
20  5   NA  NA
21  6   6   6
22  7   NA  NA   # Modified per OP clarification
23  NA  NA  NA
24  7   7   7
25  NA  NA  NA

Редактировать: применить к нескольким /все столбцы

Если все ваши столбцы относятся к одному типу, это должно сработать для преобразования всех столбцов одновременно.Он работает с использованием tidyr для сбора данных из широкого в «длинный» формат, затем выполняет те же вычисления, что и раньше, и затем возвращается к широкому формату.

df %>%
  mutate(row = row_number()) %>%
  tidyr::gather(col, value, -row) %>%
  group_by(col) %>%

  mutate(new_grp = if_else(!is.na(value) & is.na(lag(value)), 1, 0),
         grp = cumsum(new_grp)) %>%
  group_by(col, grp) %>%
  mutate(value = case_when(row_number() %% 4 %in% c(2:3, 0)  ~ NA_real_,
                           TRUE ~ value)) %>%
  ungroup() %>%
  tidyr::spread(col, value) %>%
  select(-row, -new_grp, -grp)

Если ваш фрейм данных используетразличные типы, я думаю, что это становится более сложным, если нет более простой альтернативы, которую я пропускаю.Я начал с подхода, который использует «tidyeval», чтобы позволить вам программно изменить один указанный столбец с помощью функции.Последний шаг после этого может использовать purrr для применения функции ко всем столбцам.

NA_2to4 <- function(df_name, col_to_change) {
  col_quo <- enquo(col_to_change)
  df_name %>%
    mutate(new_grp = if_else(!is.na(!!col_quo) & is.na(lag(!!col_quo)), 1, 0),
         grp = cumsum(new_grp)) %>%
    group_by(grp) %>%
    mutate(!!col_quo := case_when(row_number() %% 4 %in% c(2:3, 0)  ~ NA_real_,
                             TRUE ~ !!col_quo)) %>%
    ungroup() %>%
    select(-new_grp, -grp)
}

Вот как вы можете применить это к определенным столбцам:

df %>% 
  NA_2to4(colA) %>%
  NA_2to4(colB)

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

...