根据特定规则替换 NA 值

标签 r

我正在研究一个数据集,其中根据从临床记录中收集的数据计算得分。在某些情况下,此数据已被省略,因此无法计算分数并记录为 NA。

在某些情况下,我可以用以前的值替换 NA 值。这种方法的局限性是:

如果 score 为 NA,则检查上一个和下一个值是否为 NA。如果上一个和下一个值都不是 NA,则插入这些分数的平均值。

如果 score 为 NA,则检查上一个和下一个值是否为 NA。如果只有先前的值不是 NA,则用先前的值替换第一个 NA 值。

如果顺序有两个或多个 NA 值,则仅替换第一个 NA 值,其他值保留为 NA。

我已经尝试过函数 zoo::na.locf() 但这会不加选择地替换所有 NA 或限制替换比许多 NA 大的间隙。

我查看了 tidy fill 但文档中没有包含任何关于设置填充限制的内容。

对于以下数据:

ID,episode,score
1,1,1
1,2,1
1,3,1
1,4,NA
1,5,NA
1,6,NA
1,7,2
1,8,NA
1,9,4
1,10,NA
2,1,NA
2,2,2
2,3,3
2,4,4
2,5,NA
2,6,NA
2,7,3
2,8,NA
2,9,NA
2,10,NA

所以我认为我在下面嵌套的 ifelse mutate 上走在正确的轨道上,但我缺少有关可用于将替换限制为特定数量的 NA 值的函数的知识

data <- data %>%
group_by(ID) %>%
arrange(episode) %>%
mutate(score = ifelse(is.na(score) & lag(!is.na(score)) & lead(!is.na(score)), average(sum(lag(score),lead(score))),
    ifelse(is.na(score) & lag(!is.na(score)) & lead(is.na(score)), lag(score), ...) #And this is where I get stuck as I am unsure how to code for NA runs greater than 1

我的预期输出是:
ID,episode,score
1,1,1
1,2,1
1,3,1
1,4,*1
1,5,NA
1,6,NA
1,7,2
1,8,*3
1,9,4
1,10,*4
2,1,NA
2,2,2
2,3,3
2,4,4
2,5,*4
2,6,NA
2,7,3
2,8,*3
2,9,NA
2,10,NA


添加 *s 以明确复制值的位置。

最佳答案

如果我理解正确,替换 NA 只有两条规则。列中的值 score每个ID :

  • 如果有一个NA value 用前后(非 NA)值的平均值替换它。
  • 如果有两个或多个 NA 的序列值仅替换第一个 NA值由前面的(非 NA)值并保留另一个 NA值(value)观。

  • 这两条规则的实现归结为两个简单的mutate()声明:
    一、全单NA根据规则 1 通过调用 zoo::na.approx() 替换值与 maxgap = 1L .所以只有超过两个 NA 的序列值保留(如果有)。最后,每个NA使用 if_else() 将值替换为前面的值和 lag()为了满足规则 2。
    library(dplyr)
    data %>% 
      group_by(ID) %>% 
      mutate(new_score = zoo::na.approx(score, x = row_number(), maxgap = 1, na.rm = FALSE)) %>% 
      mutate(new_score = if_else(is.na(new_score), lag(new_score), new_score))
    

    # A tibble: 20 x 4
    # Groups:   ID [2]
          ID episode score new_score
       <dbl>   <dbl> <dbl>     <dbl>
     1     1       1     1         1
     2     1       2     1         1
     3     1       3     1         1
     4     1       4    NA         1
     5     1       5    NA        NA
     6     1       6    NA        NA
     7     1       7     2         2
     8     1       8    NA         3
     9     1       9     4         4
    10     1      10    NA         4
    11     2       1    NA        NA
    12     2       2     2         2
    13     2       3     3         3
    14     2       4     4         4
    15     2       5    NA         4
    16     2       6    NA        NA
    17     2       7     3         3
    18     2       8    NA         3
    19     2       9    NA        NA
    20     2      10    NA        NA
    


    注意新列new_score创建是为了允许比较,这里。

    用于更换 score
    data %>% 
      group_by(ID) %>% 
      mutate(score = zoo::na.approx(score, x = row_number(), maxgap = 1, na.rm = FALSE)) %>% 
      mutate(score = if_else(is.na(score), lag(score), score))
    

    数据
    data <- readr::read_csv("ID,episode,score
    1,1,1
    1,2,1
    1,3,1
    1,4,NA
    1,5,NA
    1,6,NA
    1,7,2
    1,8,NA
    1,9,4
    1,10,NA
    2,1,NA
    2,2,2
    2,3,3
    2,4,4
    2,5,NA
    2,6,NA
    2,7,3
    2,8,NA
    2,9,NA
    2,10,NA")
    

    关于根据特定规则替换 NA 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56404211/

    相关文章:

    R. 仅加入重复项一次

    r - 循环和聚类

    python - Python 是否也有一些内置数据集(如 R)来执行测试?

    r - 如何有效地索引和乘以两个矩阵?

    r - 如何将 R 中的积分结果分配给数值变量?

    删除 R 中 apply 语句和函数后面的逗号

    R:4D 绘图、x、y、z、颜色

    r - 如何根据字符串的匹配部分合并R中的两个数据帧?

    r - 如何简化R中的嵌套列表?

    r - 如何将图像添加到 ggplot