【问题标题】:Reordering rows in multiple columns in a data.frame and afterwards remove rows with only NAs重新排序 data.frame 中多列中的行,然后删除仅具有 NA 的行
【发布时间】:2015-10-14 14:57:40
【问题描述】:

我有一个大的 data.frame,有 ~100.000 行和 12 列(3 列包含变量,9 个值/测量值),其中有很多 NA,类似于这些:

##Example data.frame
Var1 <- c(rep("N01", 9), rep("N02",9))  
Var2 <- c("a","a","a","b","b","b","c","c","c","a","a","a","b","b","b","c","c","c")  
Val1 <- c(NA,2,1,2,NA,1, NA,2,NA, 2,NA,NA,NA,2,NA,1,NA,2)  
Val2 <- c(2,NA,1,NA,2,NA,2,NA,2,NA,2,2,2,NA,2,NA,2,NA)  
data <- data.frame(Var1,Var2,Val1,Val2)  
data  

Var1 Var2 Val1 Val2
N01    a   NA    2
N01    a    2   NA
N01    a    1    1
N01    b    2   NA
N01    b   NA    2
N01    b    1   NA
N01    c   NA    2
N01    c    2   NA
N01    c   NA    2
N02    a    2   NA
N02    a   NA    2
N02    a   NA    2
N02    b   NA    2
N02    b    2   NA
N02    b   NA    2
N02    c    1   NA
N02    c   NA    2
N02    c    2   NA

Var1 和 Var2 是变量(Var1 = PlotID,Var2 = SubplotID)。
Val1 和 Val2 是 Var1 和 Var2 的每个组合的值(测量值)。
现在我想尽可能多地删除不必要的 NA,例如Val1 和 Val2 都包含一个“N01 a”的 NA,但在不同的行中。如果 data.frame 如下所示(只是手动订购),我可以轻松删除只有 NA 的行(对于 Val1 和 Val2)。

#Ordered manually
Val1 <- c(2,1,NA,2,1,NA,2,NA,NA,2,NA,NA,2,NA,NA,2,1,NA)
Val2 <- c(2,1,NA,2,NA,NA,2,2,NA,2,2,NA,2,2,NA,2,NA,NA)
data2 <- data.frame(Var1,Var2,Val1,Val2)

Var1 Var2 Val1 Val2
N01    a    2    2
N01    a    1    1
N01    a   NA   NA
N01    b    2    2
N01    b    1   NA
N01    b   NA   NA
N01    c    2    2
N01    c   NA    2
N01    c   NA   NA
N02    a    2    2
N02    a   NA    2
N02    a   NA   NA
N02    b    2    2
N02    b   NA    2
N02    b   NA   NA
N02    c    2    2
N02    c    1   NA
N02    c   NA   NA

因此,最后我想要一个如下所示的 data.frame:

    Var1 Var2 Val1.s Val2.s
1   N01    a      1      1
2   N01    a      2      2
3   N01    b      1      2
4   N01    b      2     NA
5   N01    c      2      2
6   N01    c     NA      2
7   N02    a      2      2
8   N02    a     NA      2
9   N02    b      2      2
10  N02    b     NA      2
11  N02    c      1      2
12  N02    c      2     NA

我写了一个小循环,它只是在 Var1 和 Var2 的所有可能组合中子集 data.frame
而不是分别订购 Val1 和 Val2 并删除 Val1 和 Val2 仅为 NA 的行。
它可以工作,但它似乎相当复杂,对于大 data.frame 来说它不是很快。有没有人知道更好的方法来获取第一个 data.frame 到最后一个。
在此先感谢

#Small loop
library(dplyr)
level.var1 <- unique(Var1)
level.var2 <- unique(Var2)
Res.list1 <- list()
Res.list2 <- list()

for(i in 1:length(level.var1)){
  df.1 <- dplyr::filter(data, Var1==level.var1[i])
  for(o in 1:length(level.var2)){
    df.2 <- dplyr::filter(df.1, Var2==level.var2[o])
    Val1.s <- sort(df.2$Val1, na.last=TRUE)
    Val2.s <- sort(df.2$Val2, na.last=TRUE)
    df.3 <- data.frame(df.2[,c(1:2)], Val1.s, Val2.s)
    row_to_del <- apply(df.3[,c(3,4)], 1, function(x) all(is.na(x)))
    df.4 <- df.3[!row_to_del,]
    Res.list1[[o]] <- df.4
  }
  df.5 <- do.call(rbind, Res.list1)
  Res.list2[[i]] <- df.5  
}

Res.final <- do.call(rbind, Res.list2) 

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

    我发现data.table 对这种操作非常直接。正确指定 cols 变量后,以下解决方案将适用于任意数量的所需列

    library(data.table)
    
    ## Define the columns you want to filter by
    cols <- paste0("Val", 1:2)
    
    ## Sort the desired columns by group while sending the NAs to the end
    setDT(data)[, (cols) := lapply(.SD, sort, na.last = TRUE), 
                  .SDcols = cols, 
                  by = .(Var1, Var2)]
    
    ## Define an index which will check which rows have NAs for all the columns
    indx <- rowSums(is.na(data[, cols, with = FALSE])) < length(cols)
    
    ## A simple subset by condition
    data[indx]
    
    #     Var1 Var2 Val1 Val2
    #  1:  N01    a    1    1
    #  2:  N01    a    2    2
    #  3:  N01    b    1    2
    #  4:  N01    b    2   NA
    #  5:  N01    c    2    2
    #  6:  N01    c   NA    2
    #  7:  N02    a    2    2
    #  8:  N02    a   NA    2
    #  9:  N02    b    2    2
    # 10:  N02    b   NA    2
    # 11:  N02    c    1    2
    # 12:  N02    c    2   NA
    

    【讨论】:

    • 正如旁注:如果您使用 tbl_df 格式(dplyr 包),您会在使用 setDT 时遇到错误:'Error in [.tbl_df(setDT(data), , :=((cols ), lapply(.SD, sort, na.last = TRUE)), : 未使用的参数 (.SDcols = cols, by = .(Var1, Var2, Var3))'。否则它工作正常。谢谢
    • 您使用的是什么data.table 版本?我认为它已经在最新版本中修复了。
    • 你是对的。我使用的是 1.9.4 版。 1.9.6。 (最新版本)它的工作原理。
    猜你喜欢
    • 2021-05-28
    • 2014-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-20
    • 2013-06-03
    相关资源
    最近更新 更多