【问题标题】:Fill missing values in a data frame填充数据框中的缺失值
【发布时间】:2018-12-17 09:16:19
【问题描述】:

嘿,我需要填写数据框的缺失值。逻辑很简单,如果M[i, j + 1] 中有值,则使用M[i, j + 1],否则使用M[i, j - 1]。但棘手的是我需要填写从行开始到每行最后一个非 na 值之后的列的缺失值,而不仅仅是非空单元格附近的单元格。

这是数据

a1 <- c('a',9,8,rep(NA,5))
a2 <- c('b',NA,NA,NA,NA,3,NA,4)
a3 <- c('c',11,6,7,NA,NA,NA,6)
M <- rbind(a1,a2,a3)
ind <- !is.na(M[,-1]) 
t <- tapply(M[,-1][ind], row(M[,-1])[ind], head, 1) 

M <- M %>%
 as.data.frame(stringsAsFactors = FALSE) %>%
 group_by(V1) %>%
 do(mutate(., last_non_na_col = max(apply(.,1,function(x) max(which(!is.na(x)))))))


 for (i in 1:nrow(M)) {         
  for (j in 3:(M$last_non_na_col[i]+1)) {      
    if (is.na(M[i,j])) { 
   M[i,j] = ifelse(!is.na(M[i,j+1]),M[i,j+1],(ifelse(!is.na(M[i,j-1]),M[i,j-1],t[i])))
 } }
 for (j in 2) { M[i,j] = ifelse(is.na(M[i,j]), M[i,j+1], M[i,j])}   

}

原始数据是这样的

   [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
 a1 "a"  "9"  "8"  NA   NA   NA   NA   NA  
 a2 "b"  NA   NA   NA   NA   "3"  NA   "4" 
 a3 "c"  "11" "6"  "7"  NA   NA   NA   "6" 

我的代码输出如下,是正确的。请注意,对于单元格 M[2,5],填充的值应该是 7(它之前的数字),而不是 6(它之后最接近的数字)。

 V1    V2    V3    V4    V5    V6    V7    V8    last_non_na_col
 <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>           <int>
1 a     9     8     8     NA    NA    NA    NA                  3
2 b     3     3     3     3     3     4     4                   8
3 c     11    6     7     7     7     6     6                   8

我在 for 循环中做了这个。有没有人可以帮助我在 tidyverse 中做到这一点?

谢谢,

凯茜

【问题讨论】:

  • 您创建了所有列作为字符的数据。这是你的意图吗?
  • 不,那不是。但我认为这不会影响结果,对吧?
  • 不会,但我很好奇你是否知道原因
  • 我知道原因,但我还没有弄清楚如何解决它。在for循环中,它会遍历每个i,然后遍历每个j,所以如果M[2,5]的值发生变化,它不会再次改变M[2,3]的值,因为循环已经通过了M[2 ,3]。但是我想要的是在 M[2,5] 改变之后, M[2,3] 在那之后改变。我可能需要尝试申请...

标签: r dplyr na missing-data tidyr


【解决方案1】:

由于我们有 tbl_df,我们可以使用 tidyverse 方法

library(tidyverse)
gather(M, key, val, -V1) %>%
     group_by(V1) %>%
     fill(val, .direction = 'up') %>% 
     mutate(val = replace(val, which(is.na(val))[1], 
                         val[tail(which(!is.na(val)), 1)])) %>% 
    spread(key, val)
# A tibble: 3 x 8
# Groups:   V1 [3]
#  V1    V2    V3    V4    V5    V6    V7    V8   
#  <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#1 a     9     8     8     NA    NA    NA    NA   
#2 b     3     3     3     3     3     4     4    
#3 c     11    6     7     5     5     6     6   

在 OP 的 for 循环中,我们可以使用 na.locf(用相邻的非 NA 元素填充 NA 元素 - 来自 zoo 包)

library(zoo)
last_non_na_col <- c(3, 8, 8)

for (i in seq_len(nrow(M))) {
   M[i, -1] <- na.locf(unlist(M[i, -1]), fromLast = TRUE, na.rm = FALSE)
   for (j in 3:(pmin(ncol(M), last_non_na_col[i]+1))) {      
     if (is.na(M[i,j])) { 
       M[i,j] = ifelse(!is.na(M[i,j+1]), M[i,j+1], M[i,j-1])
     }
   }   
 } 
 
M
# A tibble: 3 x 8
# Groups:   V1 [3]
#  V1    V2    V3    V4    V5    V6    V7    V8   
#  <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#1 a     9     8     8     NA    NA    NA    NA   
#2 b     3     3     3     3     3     4     4    
#3 c     11    6     7     5     5     6     6    

注意:在这里,我们将 last_non_na_col 创建为 vector,而不是数据集中的单独列,以便于索引

数据

M <- structure(list(V1 = c("a", "b", "c"), V2 = c("9", NA, "11"), 
    V3 = c("8", NA, "6"), V4 = c(NA, NA, "7"), V5 = c(NA_character_, 
    NA_character_, NA_character_), V6 = c(NA, "3", "5"), V7 = c(NA_character_, 
    NA_character_, NA_character_), V8 = c(NA, "4", "6")), .Names = c("V1", 
"V2", "V3", "V4", "V5", "V6", "V7", "V8"), row.names = c(NA, 
-3L), class = c("grouped_df", "tbl_df", "tbl", "data.frame"),
  vars = "V1", drop = TRUE, indices = list(
    0L, 1L, 2L), group_sizes = c(1L, 1L, 1L), biggest_group_size = 1L, 
  labels = structure(list(
    V1 = c("a", "b", "c")), row.names = c(NA, -3L),
  class = "data.frame", vars = "V1", drop = TRUE, .Names = "V1"))

【讨论】:

  • 嗨 Akrun,非常感谢您的回复。在这种情况下效果很好。但规则是,如果 is.na(M[i,j]),则使用 M[i,j+1] 中的值,否则使用 M[i,j-1]。但是在您的代码中,我认为它只说使用缺失单元格之后的值。我刚刚更新了原始数据并更新了我的 for 循环。现在效果很好。但是,如果您能告诉我如何在 tidyverse 中获得结果,那就太好了。非常感谢。
  • @Cathy 你看过帖子中更新的for循环代码吗
  • 嗨 Akrun,我更新了我的 for 循环,它给了我现在想要的东西。但是你能告诉我如何在 tidyverse 中实现这一点吗?非常感谢。
  • 请注意,我更新了原始数据以使其更通用。谢谢,
  • @Cathy 这将是 tidyverse 方法的一个问题,因为它会在检查下一个循环更新之前立即全部更新\
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-06
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
  • 1970-01-01
  • 2021-09-21
  • 2020-02-20
相关资源
最近更新 更多