使用fill来有条件地填充NA值而不循环

时间:2018-04-26 00:36:44

标签: r date dplyr tidyr

我正在寻找一种方法来有条件地使用fill()命令或类似的东西来填充基于前一行值的NA值,条件是满足条件。我已经找到了一个解决方案,但是我找不到任何可以工作的东西。

数据看起来如下所示,但有多个' caseval'测量:

casedate = seq(as.Date('2018/1/1'),as.Date('2018/3/5'),b='week')
caseid = c(rep(1,10),rep(2,10),rep(3,10))
caseval = c(80,rep(NA,4),rep(80,5),40,rep(NA,2),rep(40,4),rep(50,3),rep(NA,7),rep(70,3))
df = cbind.data.frame(casedate,caseid, caseval)

每条记录代表一个日期和一个测量。对于某些项目,当它没有改变时跳过测量,对于其他项目,没有测量与日期相关(由该caseid的第一个记录表示为NA),如下面的第21行。在没有条件的情况下使用填充时,行21:27会填充caseid 2的值,这是不正确的。

     casedate caseid caseval
1  2018-01-01      1      80
2  2018-01-08      1      NA
3  2018-01-15      1      NA
4  2018-01-22      1      NA
5  2018-01-29      1      NA
6  2018-02-05      1      80
7  2018-02-12      1      80
8  2018-02-19      1      80
9  2018-02-26      1      80
10 2018-03-05      1      80
11 2018-01-01      2      40
12 2018-01-08      2      NA
13 2018-01-15      2      NA
14 2018-01-22      2      40
15 2018-01-29      2      40
16 2018-02-05      2      40
17 2018-02-12      2      40
18 2018-02-19      2      50
19 2018-02-26      2      50
20 2018-03-05      2      50
**21 2018-01-01      3      NA**
22 2018-01-08      3      NA
23 2018-01-15      3      NA
24 2018-01-22      3      NA
25 2018-01-29      3      NA
26 2018-02-05      3      NA
27 2018-02-12      3      NA
28 2018-02-19      3      70
29 2018-02-26      3      70
30 2018-03-05      3      70

我尝试了一个循环,但是效果很慢

for (i in 1:nrow(df)) {
  for (item in list_casevals) {
    if (df[i,'caseid']==df[i-1,'caseid'] && is.na(df[i,item])) {
      df[i,item]=df[i-1,item]
    }
  }
}

我尝试使用填充ifelse,但它只替换第2行中的NA,而不替换其他,除非它再次运行,当它替换第3行时等等。

df = df %>%
  mutate(., caseval = ifelse(lag(caseid)==caseid & is.na(caseval),fill(caseval),caseval))

除了使用循环之外,还有更快的方法吗?

1 个答案:

答案 0 :(得分:4)

你可以按caseid分组吗?例如,

df <- df %>%
  group_by(caseid) %>%
  fill(caseval) %>%
  ungroup()
相关问题