我正在研究一个数据集,其中基于从临床记录收集的数据计算出分数。在某些情况下,该数据已被省略,因此无法计算分数并将其记录为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
添加*可以清楚地将值复制到何处。
答案 0 :(得分:2)
如果我理解正确,那么只有两个规则可以为每个NA
替换列score
中的ID
值:
NA
值,请用之前和之后(非NA)值的平均值替换。NA
值序列,请仅用前一个(非NA)值替换第一个NA
值,并保留其他NA
值。这两个规则的实现可以归结为两个简单的mutate()
语句:
首先,根据规则1通过用NA
调用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")
答案 1 :(得分:2)
从计算上讲,您可以将三个规则简化为一个复合条件:
如果
NA
,则将每个is.na(score[i]) && !is.na(score[i - 1])
替换为其邻居的平均值,即元素为NA
而先前的元素不是NA
。
要实现此目的,您只需要将na.rm = T
传递到mean()
,即mean(x[(i-1):(i+1)], na.rm = T)
中,即可在*apply
函数或{{1}中使用},如下所述。请注意,我还选择了按索引位置引用和分配值,而不是使用map
和lead
来生成额外的向量。可能不那么令人兴奋,但它也更有效:
lag
答案 2 :(得分:0)
一个选项是
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