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

Posted

技术标签:

【中文标题】R - 如何在NA中填写值,但仅当结束值与起始值相同时?【英文标题】:R - How to fill in values in NA, but only when ending value is the same as the beginning value? 【发布时间】:2021-11-30 03:01:00 【问题描述】:

我有以下示例数据:

示例

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之间的差距应该用6s来填补。所有其他值应保持 NA。 因此,之后它应该是这样的:

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

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

【问题讨论】:

【参考方案1】:

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

【讨论】:

您的动物园解决方案运行良好。但是对于 dplyr 它不起作用,在示例中它很好,但在我的真实数据中却没有。似乎 NA 在开始和结束值之后被填充,它应该真正结束。就像数据是:(6, NA, NA, 6, NA, 8) 你的 dplyr 解决方案会给出:(6, 6, 6, 6, 6, 8)。但同样,动物园解决方案工作正常。谢谢。【参考方案2】:

这是使用dplyrtidyrtidyverse 方法: 逻辑:

    创建一个id 列 删除所有 na 行 如果下一个值相同则标记 right_join 与第一个 Example df fillflag 和对应的col1.y 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

【讨论】:

【参考方案3】:
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 日创建

【讨论】:

【参考方案4】:

这是一个 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

【讨论】:

以上是关于R - 如何在NA中填写值,但仅当结束值与起始值相同时?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SQL 中选择最接近的值,但仅当该值较大时?

SQL 表中如何让某条记录的某个属性值与另一个表中的某条记录的某个属性值相关联

在R中迭代地用先前的值填充NA行[重复]

MySQL查询返回按一个字段分组的表的所有字段,但仅当该分组在另一个字段中有多个值时

t值、F值与R方的区别?F值和P值关系

如何填充(自动填充)值,例如使用 R 中的 data.table 将 NA 替换为组中的第一个值?