【问题标题】:Filling NA row values with nearest right side row value in R用R中最近的右侧行值填充NA行值
【发布时间】:2017-05-17 05:18:25
【问题描述】:

我想将给定的数据帧从

             c1     c2   c3   c4    c5
    VEG PUFF <NA>    12  <NA>  <NA> 78.43
CHICKEN PUFF <NA>    16  <NA>  88.24 <NA>
BAKERY Total <NA>   <NA>  28   <NA> 84.04

             c1     c2  
    VEG PUFF 12     78.43   
CHICKEN PUFF 16     88.24    
BAKERY Total 28     84.04

我尝试了两种方法,但我没有得到准确的结果,它有时会取左侧行值

step1 <-  t(na.locf(t(df), fromLast=T))
step2 <-  t(na.locf(t(step1), fromLast=F))

library(dplyr)
MyReplace = function(data) {data %>% t %>% na.locf(.,,T) %>% na.locf %>% t

【问题讨论】:

  • 关于你的描述,你是不是觉得这个例子过于简单,无法传达你描述的内容?

标签: r dplyr na zoo


【解决方案1】:

更新

由于预期输出存在很多混淆,因此按照@DavidArenburg 的建议使用tidyverse 解决方案更新答案

library(dplyr)
library(tidyr)
df %>%
  add_rownames() %>%
  gather(variable, value, -rowname) %>%
  filter(!is.na(value)) %>%
  group_by(rowname) %>%
  mutate(indx = row_number()) %>%
  select(-variable) %>%
  spread(indx, value)

#        rowname   `1`   `2`
#*        <chr> <dbl> <dbl>
#1 BAKERY_Total    28 84.04
#2 CHICKEN_PUFF    16 88.24
#3     VEG_PUFF    12 78.43

另一种解决方案可能是

library(data.table)
temp <- apply(df, 1, function(x) data.frame(matrix(x[!is.na(x)], nrow = 1)))
rbindlist(temp, fill = T)

上一个答案

如果我对您的理解正确,您正在尝试用同一行中的最新非 NA 值替换一行中的 NA

我们可以使用na.locf,将fromLast设置为TRUE

t(apply(df, 1, function(x) na.locf(x, fromLast = T, na.rm = F)))


#             c1 c2    c3    c4    c5
#VEG_PUFF     12 12 78.43 78.43 78.43
#CHICKEN_PUFF 16 16 88.24 88.24    NA
#BAKERY_Total 28 28 28.00 84.04 84.04

【讨论】:

    【解决方案2】:

    我们可以使用na.omit

    t(apply(df, 1, na.omit))
    #             [,1]  [,2]
    #VEG PUFF       12 78.43
    #CHICKEN PUFF   16 88.24
    #BAKERY Total   28 84.04
    

    更新

    根据excel数据显示

    lst <- apply(df, 1, na.omit)
    df2 <- do.call(rbind, lapply(lst, `length<-`, max(lengths(lst))))
    row.names(df2) <- row.names(df)
    

    或者另一个选项是来自data.tablemelt/dcast

    library(data.table)
    dcast(melt(setDT(df1, keep.rownames=TRUE), id.var = 'rn', 
             na.rm = TRUE), rn~ paste0("c", rowid(rn)), value.var = "value")
    #             rn c1    c2  c3
    #1: BAKERY Total 28 84.04  NA
    #2: CHICKEN PUFF 16 88.24 143
    #3:     VEG PUFF 12 78.43  NA
    

    为了提供一个可重现的例子,

    df1 <- structure(list(c1 = c(NA, NA, NA), c2 = c(12L, 16L, NA), c3 = c(NA, 
    NA, 28L), c4 = c(NA, 88.24, NA), c5 = c(78.43, 143, 84.04)), .Names = c("c1", 
    "c2", "c3", "c4", "c5"), class = "data.frame", row.names = c("VEG PUFF", 
    "CHICKEN PUFF", "BAKERY Total"))
    
    lst <- lapply(seq_len(nrow(df1)), function(i) {
                   x1 <- unlist(df1[i,])
                   x1[complete.cases(x1)]})
    df2 <- do.call(rbind, lapply(lst, `length<-`, max(lengths(lst))))
    row.names(df2) <- row.names(df1)
    

    上述方法与apply方法类似,不同之处在于我们总是可以确定这个输出一个list(在apply中-它可以变化。当元素数量相同时删除NA,它将输出一个matrix,在其他情况下输出一个list)。因此,我们遍历行序列,删除NA 元素,在末尾填充NA 以使list 元素的长度相同,然后rbind


    或者另一个选项是whicharr.ind=TRUE

    ind <- which(!is.na(df), arr.ind=TRUE)
    matrix(df[ind[order(ind[,1]),]], ncol=2, byrow=TRUE, 
                dimnames = list(row.names(df), paste0("c", 1:2)))
    #             c1    c2
    #VEG PUFF     12 78.43
    #CHICKEN PUFF 16 88.24
    #BAKERY Total 28 84.04
    

    【讨论】:

    • 您的方法是正确的,但我在将相同的概念应用于此 xls 文件drive.google.com/open?id=0BzOpodJQqn6cdFdFUDVaUDZnbE0 时遇到了问题
    • 我给你的数据框是最小的,但我有一个很大的
    • @secondmethod 我希望新数据被剪切和移动而不是复制和移动。如果它正在复制它不是我想要的
    • @是的,我想在哪里有 na,​​它必须用靠近它的值替换(按行而不是 na)一旦移动值,它必须查看同一行中的另一个值所以我会得到一个没有na的数据框
    • @columns:NO 它可以是任意数量的列,就像移动右侧的值(如果有 na 的话)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    • 2018-03-13
    相关资源
    最近更新 更多