代码之家  ›  专栏  ›  技术社区  ›  Esther

根据不同列中的NAs数量而定的列,删除具有重复项的行

  •  1
  • Esther  · 技术社区  · 7 年前

    我想根据其他列中的NAs数量删除列a具有重复值的行。这与此类似,但我无法让计算NAs与那里的解决方案一起工作。

    Deleting rows that are duplicated in one column based on the conditions of another column

    这是我的玩具数据集:

    df1 <- data.frame(a = c("x","y","y","z","x", "z"), b = c(1,2,NA,4,8,3), c = c(NA,2,2,NA,NA,4), d= c(1:4,NA,NA))
    

      a  b  c  d
    1 x  1 NA  1
    2 y  2  2  2
    3 y NA  2  3
    4 z  4 NA  4
    5 x  8 NA NA
    6 z  3  4 NA
    

    我只想在列a中保留具有唯一值的行,在列b中只保留具有最少NAs数的行;c(忽略d列中的NAs)

    这是我想到的代码:

    df1 %>%
     mutate(NAs= apply(is.na(cbind(b,c)), 1, sum)) %>%     
     group_by(a) %>%
     top_n(n=1, -NAs)
    

    我的问题是,如果出现平局,top\n会返回多行。万一打成平手,我只想退回第一排。在mutate中选择列的方法可能比cbind更好。我也不需要使用mutate创建的“NAs”变量。我想要的结果是:

      a  b  c  d
      x  1 NA  1
      y  2  2  2
      z  3  4 NA
    
    3 回复  |  直到 7 年前
        1
  •  3
  •   arg0naut91    7 年前

    @马库斯认为这也可能是一个答案。也许这是真的,因为保持代码简短有助于 dplyr ,否则您常常会得到非常冗长的脚本。

    rowSums 已经强调过了。

    df1 %>% 
    arrange(a, rowSums(is.na(.[, c("b", "c")]))) %>% 
    distinct(a, .keep_all = TRUE)
    
      a b  c  d
    1 x 1 NA  1
    2 y 2  2  2
    3 z 3  4 NA
    

    dplyr公司 尽可能多的动词,例如只用 arrange & distinct group , slice top_n , filter 等等。

        2
  •  2
  •   markus    7 年前

    这里有一个选择

    library(dplyr)
    df1 %>%
      mutate(NAs = rowSums(is.na(.[, c("b", "c")]))) %>%
      group_by(a) %>%
      top_n(n = 1, -NAs) %>% 
      slice(1) %>% 
      select(-NAs)
    # A tibble: 3 x 4
    # Groups:   a [3]
    #  a         b     c     d
    #  <fct> <dbl> <dbl> <int>
    #1 x         1    NA     1
    #2 y         2     2     2
    #3 z         3     4    NA
    

    rowSums 是一种比 apply(..., 1, sum)


    你也可以试试 data.table . 下面的解决方案应该非常快速(但可能可读性较差)。

    library(data.table)
    setDT(df1)
    df1[df1[order(a, df1[, rowSums(is.na(.SD)), .SDcols = c("b", "c")]), .I[1], by = "a"]$V1]
    #   a b  c  d
    #1: x 1 NA  1
    #2: y 2  2  2
    #3: z 3  4 NA
    
        3
  •  1
  •   tmfmnk    7 年前

    有点不同 dplyr

    df1 %>%
      mutate(miss = rowSums(is.na(cbind(b,c)))) %>%
      group_by(a) %>%
      filter(miss == min(miss)) %>%
      slice(1) %>%
      select(-miss) %>%
      ungroup()
    

    df1 %>%
      mutate(miss = rowSums(is.na(cbind(b,c)))) %>%
      group_by(a) %>%
      mutate(dupl = seq_along(a)) %>%
      filter(miss == min(miss)) %>%
      filter(dupl == min(dupl)) %>%
      select(-miss, -dupl) %>%
      ungroup()