R - 如何在 NA 中填写值,但仅当结束值与开始值相同时?

R - How to fill in values in NA, but only when ending value is the same as the beginning value?

我有以下示例数据:

示例 <- data.frame(col1 =c(1, NA, NA, 4, NA, NA, 6, NA, NA, NA, 6, 8, NA, 2, NA))

col1
1
NA
NA
4
NA
NA
6
NA
NA
NA
6
8
NA
2
NA

我想用上面的值填充 NA,但前提是 NA 介于 2 个相同的值之间。在这个例子中,从 1 到 4 的第一个 NA 间隙不应该用 1 填充。但是第一个6和第二个6之间的空隙应该用6来填补。所有其他值应保持 NA。 因此,之后它应该看起来像:

col1
1
NA
NA
4
NA
NA
6
6
6
6
6
8
NA
2
NA

但实际上我并没有只有15个观察值,而是超过50000个。因此我需要一个有效的解决方案,这比我想象的要难。我尝试使用填充功能,但无法想出解决方案。

一个dplyrzoo选项可以是:

df %>%
    mutate(cond = na.locf0(col1) == na.locf0(col1, fromLast = TRUE),
           col1 = ifelse(cond, na.locf0(col1), col1)) %>%
    select(-cond)

   col1
1     1
2    NA
3    NA
4     4
5    NA
6    NA
7     6
8     6
9     6
10    6
11    6
12    8
13   NA
14    2
15   NA

这是一个 dply 解决方案:

首先,我以 tibble 格式创建数据:

df <- tibble(
  x = c(1, NA_real_, NA_real_, 
        4, NA_real_, NA_real_,
        6, NA_real_, NA_real_, NA_real_, 
        6, 8, NA_real_, 2, NA_real_)
) 

接下来,我创建两个分组变量,这将有助于识别第一个和最后一个非 NA 值。 然后我将这些参考值保存到 ref_startref_end。 最后我覆盖了 x:

的值
df %>%
  mutate(gr1 = cumsum(!is.na(x))) %>%
  group_by(gr1) %>%
  mutate(ref_start = first(x)) %>%
  ungroup() %>%
  mutate(gr2 = lag(gr1, default = 1)) %>%
  group_by(gr2) %>%
  mutate(ref_end = last(x)) %>%
  ungroup() %>%
  mutate(x = if_else(is.na(x) & ref_start == ref_end, ref_start, x))

# A tibble: 15 x 1
       x
   <dbl>
 1     1
 2    NA
 3    NA
 4     4
 5    NA
 6    NA
 7     6
 8     6
 9     6
10     6
11     6
12     8
13    NA
14     2
15    NA
df <- data.frame(col1 =c(1, NA, NA, 4, NA, NA, 6, NA, NA, NA, 6, 8, NA, 2, NA))

library(data.table)
library(magrittr)

setDT(df)[!is.na(col1), n := .N, by = col1] %>% 
  .[, n := nafill(n, type = "locf")] %>% 
  .[n == 2, col1 := nafill(col1, type = "locf")] %>% 
  .[, n := NULL] %>% 
  .[]
#>     col1
#>  1:    1
#>  2:   NA
#>  3:   NA
#>  4:    4
#>  5:   NA
#>  6:   NA
#>  7:    6
#>  8:    6
#>  9:    6
#> 10:    6
#> 11:    6
#> 12:    8
#> 13:   NA
#> 14:    2
#> 15:   NA

reprex package (v2.0.1)

于 2021 年 10 月 11 日创建

这是使用 dplyrtidyrtidyverse 方法: 逻辑:

  1. 创建一个 id
  2. 删除所有 na 行
  3. 如果下一个值相同则标记
  4. right_join 与第一个 Example df
  5. fill向下flag对应col1.y
  6. mutateifelse
library(dplyr)
library(tidyr)

Example <- Example %>% 
  mutate(id=row_number())

Example %>% 
  na.omit() %>% 
  mutate(flag = ifelse(col1==lead(col1), TRUE, FALSE)) %>% 
  right_join(Example, by="id") %>% 
  arrange(id) %>% 
  fill(col1.y, .direction="down") %>% 
  fill(flag, .direction="down") %>% 
  mutate(col1.x = ifelse(flag==TRUE, col1.y, col1.x), .keep="unused") %>% 
  select(col1 = col1.x)

输出:

   col1
1     1
2    NA
3    NA
4     4
5    NA
6    NA
7     6
8     6
9     6
10    6
11    6
12    8
13   NA
14    2
15   NA