仅使用非 NA 单元格替换另一列中的单元格

Use only non-NA cells to replace cells in another column

长期听众,第一次来电,所以如果我在 post 或一般情况下遗漏了重要信息,我深表歉意。

简而言之,我有两列,其中一列的每个单元格都已填充(行为)。另一个(游戏)除了少数单元格外大部分是NA,但每个单元格中的内容不一定相同。对于游戏中的每一个非NA,无论内容如何,​​我都想用它来替换行为列中对应行的数据。

这是数据:

behavior<-c("run","jump","play","walk","jump","walk","run","play","jump","jump")
game<-c(NA,"tag",NA,NA,NA,"slide",NA,"tag",NA,"hopscotch")

    test<-data.frame(behavior,game)

behavior    game
1   run     NA
2   jump    tag
3   play    NA
4   walk    NA
5   jump    NA
6   walk    slide
7   run     NA
8   play    tag
9   jump    NA
10  jump    hopscotch

我希望它看起来像:

behavior    game
1   run     NA
2   tag     tag
3   play    NA
4   walk    NA
5   jump    NA
6   slide   slide
7   run     NA
8   tag     tag
9   jump    NA
10  hopscotch   hopscotch

我试过使用 !(test$game==NA) 和 if/else 之类的东西来编写函数,但我认为我在这里遗漏了一些基本的东西。这看起来相当简单,但是在搜索 Whosebug 之后,我看到了很多关于如何替换 NA 的建议,但是 none 关于如何仅使用非 NA 来替换已经填充的单元格的建议。出于好奇,如果有一种方法可以交换单元格值,我也会感兴趣,所以第二行将是 tag/jump 而不是 tag/tag。很高兴提供任何额外的 info/clarifications,非常感谢任何建议。

欢迎来到 SO。

感谢您提供一些示例数据,这真的很有帮助!

我个人会使用 dplyr 包和 coalesce() 函数来解决这个问题(如果您熟悉 SQL,您可能会认出那个函数,如果不熟悉,请不要不用担心!)。

coalecse() 函数的作用是获取两个或多个向量中的第一个非 NA 值。您可以单独使用它,或者根据我的喜好,在 mutate() 函数(也来自 dplyr)中使用它,这对数据框中的 creating/modifying 列很有用:

library(dplyr)

behavior<-c("run","jump","play","walk","jump","walk","run","play","jump","jump")
game<-c(NA,"tag",NA,NA,NA,"slide",NA,"tag",NA,"hopscotch")

# Make the data frame, using stringsAsFactors = FALSE to make sure our data
# get treated as characters, not factors 
test <- data.frame(behavior = behavior, game = game, stringsAsFactors = FALSE)
dplyr::mutate(
     test,
     behavior = dplyr::coalesce(game, behavior)
)

    behavior      game
1        run      <NA>
2        tag       tag
3       play      <NA>
4       walk      <NA>
5       jump      <NA>
6      slide     slide
7        run      <NA>
8        tag       tag
9       jump      <NA>
10 hopscotch hopscotch

为了帮助形象化一点,让我们创建一个新列(而不是覆盖 behavior):

mutate(
     test,
     new = coalesce(game, behavior)
)

   behavior      game       new
1       run      <NA>       run
2      jump       tag       tag
3      play      <NA>      play
4      walk      <NA>      walk
5      jump      <NA>      jump
6      walk     slide     slide
7       run      <NA>       run
8      play       tag       tag
9      jump      <NA>      jump
10     jump hopscotch hopscotch

所以 coalesce() 查看 game 然后 behavior,如果 game 中有值则使用它,如果没有则查看 behavior 并使用该值代替(如果两者都没有值,它将使用 NA)。

如果您喜欢这种方法,我建议您阅读(优秀的)R for Data Science 一书(此处免费在线:https://r4ds.had.co.nz/) and the tidyverse collection of packages (https://www.tidyverse.org/)。

以字符串而不是因子的形式读取数据

test<- data.frame(behavior,game, stringsAsFactors = FALSE)

我们可以将简单的 ifelsetransform 一起使用,其中 behavior 的值根据 NAgame 列进行更改。

transform(test, behavior = ifelse(is.na(game), behavior, game))

#    behavior      game
#1        run      <NA>
#2        tag       tag
#3       play      <NA>
#4       walk      <NA>
#5       jump      <NA>
#6      slide     slide
#7        run      <NA>
#8        tag       tag
#9       jump      <NA>
#10 hopscotch hopscotch

factors 在内部存储为数字,如果您不将它们作为字符读取,则相同的代码将生成

test<- data.frame(behavior,game)
transform(test, behavior = ifelse(is.na(game), behavior, game))
#   behavior      game
#1         3      <NA>
#2         3       tag
#3         2      <NA>
#4         4      <NA>
#5         1      <NA>
#6         2     slide
#7         3      <NA>
#8         3       tag
#9         1      <NA>
#10        1 hopscotch

这会非常混乱且难以调试。或者,我们可以使用 as.character 覆盖因子值,这将给出预期的输出。

transform(test, behavior = ifelse(is.na(game), as.character(behavior), 
                                               as.character(game)))