在R中,如何将NA替换为前一个字符?

5
以下是一份包含NA值的数据框:
md <- data.frame(cat=c('a','b','d',NA,'E',NA),
                subcat=c('A','C',NA,NA,NA,'D')) 

 cat subcat
1    a      A
2    b      C
3    d   <NA>
4 <NA>   <NA>
5    E   <NA>
6 <NA>      D

我想用前一个字符替换NA,结果如下。
使用循环语句像'for ...'可以实现,但效率不高。是否有公式或包可以实现?谢谢!
  cat subcat
1   a      A
2   b      C
3   d      C
4   d      C
5   E      C
6   E      D

2
如果一列的第一个元素是 NA,会发生什么? - rafagarci
此问题仅适用于第一行没有NA的特定情况。 - anderwyang
5个回答

6

您可以使用来自 zoo 包的 na.locf 函数。

zoo::na.locf(md)
  cat subcat
1   a      A
2   b      C
3   d      C
4   d      C
5   E      C
6   E      D

或者使用tidyrdplyr中的filleverything

library(dplyr)
library(tidyr)

md %>% fill(everything())
#   cat subcat
# 1   a      A
# 2   b      C
# 3   d      C
# 4   d      C
# 5   E      C
# 6   E      D

这很棒,谢谢! - anderwyang

1

一种方法是使用运行长度编码rle()。因为它不会对NAs进行编码,所以我用字符串“NA”替换了它们。

roll_na <- function(.) {
  .[is.na(.)] <- "NA"
  var <- rle(.)
  na_ind <- which(var$values == "NA")
  var_lag <- c(NA, var$values[-length(var$values)])
  var$values[na_ind] <- var_lag[na_ind]
  
  rep(var$values, times = var$lengths)
}

library(dplyr)

md %>% 
  mutate(across(everything(), roll_na))

#   cat subcat
# 1   a      A
# 2   b      C
# 3   d      C
# 4   d      C
# 5   E      C
# 6   E      D

0

如果您在大列向量中有许多连续的NA,那么这不是正确的方法,但如果只有几个,它会很快:

no_NA <- function(x) {while(any(is.na(x))) x[is.na(x)] <- x[which(is.na(x))-1]; x}
as.data.frame(apply(md, 2, no_NA))

如果您有大量带有许多NA的数据集,我建议使用一个简单的while循环,从每个向量开头更改所有的NA

no_NA <- function(x){
  len <- length(x); i <- 2
  while(i <= len){
    if (is.na(x[i])) x[i] <- x[i-1]
    i <- i + 1
  } 
  x
}
as.data.frame(apply(md, 2, no_NA))

谢谢你的帮助。 - anderwyang

0
忽略列的初始值为NA的情况,您可以使用以下函数。
# Replacement function
func = function(DF){
    tmp = DF
    for(i in 1:length(tmp[1,])){
        for(j in 1:length(tmp[,i])){
            if(j == 1){
                next
            } else if (is.na(tmp[j,i])) {
                tmp[j,i] = tmp[j-1,i]
            }
        }
    }
    return(tmp)
}

并且执行

# data 
md = func(md)
print(md)

输出

  cat subcat
1   a      A
2   b      C
3   d      C
4   d      C
5   E      C
6   E      D

0
library(tidyverse)
library(magrittr)
#> 
#> Attaching package: 'magrittr'
#> The following object is masked from 'package:purrr':
#> 
#>     set_names
#> The following object is masked from 'package:tidyr':
#> 
#>     extract

md <- data.frame(cat=c(NA,'b','d',NA,'E',NA),
                 subcat=c(NA,'C',NA,NA,NA,'D')) 

md
#>    cat subcat
#> 1 <NA>   <NA>
#> 2    b      C
#> 3    d   <NA>
#> 4 <NA>   <NA>
#> 5    E   <NA>
#> 6 <NA>      D

#if the first value is NA
value <- '0'

md <- 
    map(md, ~{
        if(is.na(.x[[1]])) {
            c(value, .x[-1])
        } else {
            .x
        }
    }) %>% bind_cols()

#while loop is needed for consecutive NA's
while (any(map_lgl(md, ~any(is.na(..1))))) { 
    md %<>% mutate(cat = if_else(is.na(cat), lag(cat), cat),
                   subcat = if_else(is.na(subcat), lag(subcat), subcat))
}

md
#> # A tibble: 6 x 2
#>   cat   subcat
#>   <chr> <chr> 
#> 1 0     0     
#> 2 b     C     
#> 3 d     C     
#> 4 d     C     
#> 5 E     C     
#> 6 E     D

reprex package (v2.0.0)于2021年6月11日创建


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接