使用dplyr按组替换NA与上一个或下一个值

Tar*_*rak 27 r missing-data zoo dplyr

我有一个数据框,按日期的降序排列.

ps1 = data.frame(userID = c(21,21,21,22,22,22,23,23,23), 
             color = c(NA,'blue','red','blue',NA,NA,'red',NA,'gold'), 
             age = c('3yrs','2yrs',NA,NA,'3yrs',NA,NA,'4yrs',NA), 
             gender = c('F',NA,'M',NA,NA,'F','F',NA,'F') 
)
Run Code Online (Sandbox Code Playgroud)

我希望将NA值用先前的值归入(替换)并按userID分组如果userID的第一行有NA,则替换为该用户ID组的下一组值.

我正在尝试使用像这样的dplyr和zoo软件包......但它不起作用

cleanedFUG <- filteredUserGroup %>%
 group_by(UserID) %>%
 mutate(Age1 = na.locf(Age), 
     Color1 = na.locf(Color), 
     Gender1 = na.locf(Gender) ) 
Run Code Online (Sandbox Code Playgroud)

我需要结果df像这样:

                      userID color  age gender
                1     21  blue 3yrs      F
                2     21  blue 2yrs      F
                3     21   red 2yrs      M
                4     22  blue 3yrs      F
                5     22  blue 3yrs      F
                6     22  blue 3yrs      F
                7     23   red 4yrs      F
                8     23   red 4yrs      F
                9     23  gold 4yrs      F
Run Code Online (Sandbox Code Playgroud)

Ren*_*rop 42

require(tidyverse) #fill is part of tidyr

ps1 %>% 
  group_by(userID) %>% 
  fill(color, age, gender) %>% #default direction down
  fill(color, age, gender, .direction = "up")
Run Code Online (Sandbox Code Playgroud)

哪个给你:

Source: local data frame [9 x 4]
Groups: userID [3]

  userID  color    age gender
   <dbl> <fctr> <fctr> <fctr>
1     21   blue   3yrs      F
2     21   blue   2yrs      F
3     21    red   2yrs      M
4     22   blue   3yrs      F
5     22   blue   3yrs      F
6     22   blue   3yrs      F
7     23    red   4yrs      F
8     23    red   4yrs      F
9     23   gold   4yrs      F
Run Code Online (Sandbox Code Playgroud)

  • 此后,“fill()”函数已更新为允许同时在两个方向上填充,而无需使用两次。“.direction”选项现在包括“downup”和“updown”。 (2认同)
  • 如果你的数据集很大并且你无法写出每个列的名称怎么办 (2认同)

age*_*nis 6

直接在整个 data.frame 上使用zoo::na.locf将填充 NA,无论userID组如何。不幸的是,dplyr 包的分组对功能没有影响na.locf,这就是我进行拆分的原因:

library(dplyr); library(zoo)
ps1 %>% split(ps1$userID) %>% 
  lapply(function(x) {na.locf(na.locf(x), fromLast=T)}) %>% 
  do.call(rbind, .)
####      userID color  age gender
#### 21.1     21  blue 3yrs      F
#### 21.2     21  blue 2yrs      F
#### 21.3     21   red 2yrs      M
#### 22.4     22  blue 3yrs      F
#### 22.5     22  blue 3yrs      F
#### 22.6     22  blue 3yrs      F
#### 23.7     23   red 4yrs      F
#### 23.8     23   red 4yrs      F
#### 23.9     23  gold 4yrs      F
Run Code Online (Sandbox Code Playgroud)

它的作用是首先将数据分成 3 个 data.frames,然后我应用第一遍插补(向下),然后使用 中的匿名函数向上lapply,最后用于rbind将 data.frames 重新组合在一起。你有预期的输出。


小智 5

我写了这个函数,它肯定比 fill 更快,而且可能比 na.locf 更快:

fill_NA <- function(x) {
  which.na <- c(which(!is.na(x)), length(x) + 1)
  values <- na.omit(x)

  if (which.na[1] != 1) {
    which.na <- c(1, which.na)
    values <- c(values[1], values)
  }

  diffs <- diff(which.na)
  return(rep(values, times = diffs))
}
Run Code Online (Sandbox Code Playgroud)