Вот подход, использующий 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
для применения ко всем столбцам, но я не уверен в синтаксисе в данный момент.