将列中的 NA 值替换为 +1 以上行中的值

Replace NA values in column with value in row above +1

我有以下数据框:

game <- c('game1','game1','game2','game2','game2','game3','game4', 'game4')
shot_number <- c(1,NA,1,NA,NA,1,1,NA)
df <- data.frame(game, shot_number)

      game     shot_number
      game1              1
      game1             NA
      game2              1
      game2             NA
      game2             NA
      game3              1
      game4              1
      game4             NA

我想通过将上一行的值加1来填充NA,所以df如下:

      game     shot_number
      game1              1
      game1              2
      game2              1
      game2              2
      game2              3
      game3              1
      game4              1
      game4              2

我不知道是否有某种方法可以使用 'zoo' 库和 na.locf 来完成此操作,或者我是否需要编写 for 循环或某种函数。

这是适用于您的示例的基本 R 方法。

df$shot_number <- ave(df$shot_number, df$game,
                      FUN=function(i) pmin(tail(cumsum(c(1, is.na(i))), -1), i, na.rm=TRUE))

此处,ave 按组 (df$game) 运行函数。对于每场比赛,计算 NA 的累计和,在开始前加上 1。使用 tail 删除最终值,因为结果将是 1 个元素到 long。然后取最小值到实际向量,删除任何 NA。

这个returns

df
   game shot_number
1 game1           1
2 game1           2
3 game2           1
4 game2           2
5 game2           3
6 game3           1
7 game4           1
8 game4           2

数据

df <-
structure(list(game = structure(c(1L, 1L, 2L, 2L, 2L, 3L, 4L, 
4L), .Label = c("game1", "game2", "game3", "game4"), class = "factor"), 
    shot_number = c(1, NA, 1, NA, NA, 1, 1, NA)), .Names = c("game", 
"shot_number"), row.names = c(NA, -8L), class = "data.frame")

使用 dplyr 组和 cumsum:

library(dplyr)

df1 %>% 
  group_by(game) %>% 
  mutate(shot_number_new = cumsum(is.na(shot_number)) + 1)

# Source: local data frame [8 x 3]
# Groups: game [4]
# 
#     game shot_number shot_number_new
#   <fctr>       <dbl>           <dbl>
# 1  game1           1               1
# 2  game1          NA               2
# 3  game2           1               1
# 4  game2          NA               2
# 5  game2          NA               3
# 6  game3           1               1
# 7  game4           1               1
# 8  game4          NA               2

您可以使用 group_by()row_number() 而无需显式使用原始 shot_number 列:

df %>%
  group_by(game) %>%
  mutate(shot_number2 = row_number())

下面的解决方案都处理问题中的示例数据,但假设的一般情况越来越复杂。 (4) 是最一般的,但如果实际情况不需要完全一般性,则其他可能是基于简单的首选。没有使用包。

1) 在示例数据中,每个组中的基行为 1,其余数字为 NA,因此如果这是一般模式,那么我们可以使用 ave 像这样 seq_along

transform(df, shot_number = ave(shot_number, game, FUN = seq_along))

2) 如果基数不一定为 1 则将 (1) 中的 seq_along 替换为 f 如下所示:

f <- function(x) seq(x[1], length = length(x))
transform(df, shot_number = ave(shot_number, game, FUN = f))

2a) 这也适用于与 (2) 相同的假设。它用 1 替换每个 NA,然后在 game 组中使用 cumsum

NAtoN <- function(x, N) replace(x, is.na(x), N)
transform(df, shot_number = ave(NAtoN(shot_number, 1), game, FUN = cumsum))

3) 如果一般情况是数字和 NA 混合存在,但已知每个游戏组的第一个元素不是 NA,那么我们可以组成组来自非 NA 以及跟随它们的 NA:

transform(df, shot_number = ave(shot_number, cumsum(!is.na(shot_number)), FUN = f))

4) 如果游戏组的第一个元素也可以是 NA,则处理由非 NA 后跟 NA 或所有 NA 定义的子组,如果游戏组以不适用。在前导 NA 的情况下使用 0 作为基值(或将 f2 中的 0 替换为其他数字。)

 f2 <- function(x) ave(NAtoN(x, 0), cumsum(!is.na(x)), FUN = f)
 transform(df, shot_number = ave(shot_number, game, FUN = f2))