当前位置: 首页 > 知识库问答 >
问题:

根据特定规则替换NA值

濮阳研
2023-03-14

我正在处理一个数据集,其中的分数是根据从临床记录中收集的数据计算出来的。在某些情况下,这些数据被忽略,因此分数无法计算,并记录为NA。

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

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

如果分数为NA,请检查前一个值和下一个值是否为NA。如果只有前一个值不是NA,则将第一个NA值替换为前一个值。

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

我试过zoo::na函数。locf(),但这将不分青红皂白地替换所有NA,或限制替换大于许多NA的间隙。

我查看了整洁的填充,但文档中没有任何关于设置填充限制的内容。

对于以下数据:

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变量时走上了正确的轨道,但我缺少关于函数的知识,我可以使用这些函数来将我的替换限制为特定数量的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是为了清楚地说明值被复制到哪里。

共有3个答案

许昆
2023-03-14

一个选择是

library(dplyr)
data %>%
   group_by(ID) %>% 
  group_by(grp = cumsum(lead(is.na(score) & !is.na(lead(score) & 
      !is.na(lag(score)) ))), add = TRUE) %>% 
  mutate(score1 = if(n() == 3 & is.na(score[2]) & sum(is.na(score))== 1) 
    replace(score, is.na(score), mean(score, na.rm = TRUE)) else score) %>% 
  ungroup %>% 
  select(-grp) %>%
  mutate(score1 = coalesce(score1, lag(score1)))
# A tibble: 20 x 4
#      ID episode score score1
#   <int>   <int> <int>  <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
曾承弼
2023-03-14

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

  1. 如果存在单个 NA 值,请将其替换为前后(非 NA)值的平均值。
  2. 如果存在两个或多个 NA 值的序列,则仅将第一个 NA 值替换为前面的(非 NA)值,并保留其他 NA 值。

这两个规则的实现归结为两个简单的< code>mutate()语句:首先,根据规则1,通过用< code>maxgap = 1L调用< code>zoo::na.approx()来替换所有单个< code>NA值。因此只有具有两个以上< code>NA值的序列保留下来(如果有的话)。最后,使用< code>if_else()和< code>lag()将每个< code>NA值替换为前面的值,以满足规则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以进行比较。

用于替换分数使用

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")
李辉
2023-03-14

从计算上讲,您可以将三个规则简化为一个复合条件:

如果< code >是. na(score[i]),则将每个< code>NA替换为其相邻元素的平均值

为此,您只需将 na.rm = T 传递到 mean(),即 meanx[(i-1):(i 1)],na.rm = T),您可以在 *apply 函数或 map 中使用,就像我在下面所做的那样。请注意,我还选择按索引位置引用和分配值,而不是使用前导滞后,这会生成额外的向量。它可能不那么令人兴奋,但它也更有效率:

library(dplyr)
library(purrr)

mutate(df, score = map(seq_along(score),
                       ~ ifelse(
                           is.na(score[.]) && !is.na(score[. - 1]),
                           mean(score[(. - 1):(. + 1)], na.rm = T),
                           score[.]
                       )))

#### OUTPUT ####

   ID episode score
1   1       1     1
2   1       2     1
3   1       3     1
4   1       4     1
5   1       5    NA
6   1       6    NA
7   1       7     2
8   1       8     3
9   1       9     4
10  1      10     4
11  2       1    NA
12  2       2     2
13  2       3     3
14  2       4     4
15  2       5     4
16  2       6    NA
17  2       7     3
18  2       8     3
19  2       9    NA
20  2      10    NA
 类似资料:
  • 我有以下任务。有一根绳子。我必须按照6条规则在它中做替换,直到有可能在一个字符串中做一个替换。 我找到的解决办法就在下面。工作正常。问题是它的性能较低。我还可以如何根据多个规则进行替换?有什么算法吗? 附注。此任务来自codility站点。我的解决方案得到了100%的正确性和25%的性能。

  • 我想创建一个新列,并用和替换和不丢失的值。 我想要的: 这就是我所尝试的: 看来第二行不正确。 有什么建议吗?

  • 本文向大家介绍如何将NA替换为R数据帧中选定列的值?,包括了如何将NA替换为R数据帧中选定列的值?的使用技巧和注意事项,需要的朋友参考一下 在数据分析中,在数据框中查找某些NA值非常普遍,但如果包含NA值的列对分析无用,则所有NA值都不会产生问题。我们可以将所有NA值替换为0或将其他有用的列替换为其他值。 示例 请看以下数据帧- 将NA的连续列更改为零- 将NA的非连续列更改为零-

  • 我有两个data.frames,每个都有数千行和几十列,都是通过合并几个csv文件创建的。data.frames正是我想要的。我还要补充一点,df1和df2有几列是共同的。唯一的问题是,在其中一个中,比如df1,对于某些列,有一些NAs(这是预期的/正常的)。好的一面是,我有NAs的相同列也出现在第二data.frame,比如df2,但没有NAs。我想做的是用df1同一列的值填充df2给定列中的N

  • 使用ESLint是否可以忽略整个目录的一个特定规则? 在我的例子中,我想忽略为一个名为的目录