将列中的 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))
我有以下数据框:
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))