【问题标题】:Grouping a data.frame and filtering based on several conditions根据多个条件对 data.frame 进行分组和过滤
【发布时间】:2019-02-04 09:01:59
【问题描述】:

我有一个data.frame 有几列:

df <- data.frame(sgid = c("sg1","sg1","sg2","sg3"), stid = c(NA,"st1",NA,NA), spid = c(NA,NA,NA,"sp3"), sch = c("sch1","sch1","sch2","sch2"), sst = c(11,11,32,21), snd = c(21,21,46,34),
                 qgid = c("qg1","qg1","qg1","qg1"), qtid = c("qt1","qt1","qt1","qt1"), qpid = c("qp1","qp1","qp1","qp1"), qch = c("qch1","qch1","qch1","qch1"), qst = c(111,111,234,21), qnd = c(211,211,267,34))

data.frame 描述了将一个序列(即查询)映射到其他序列的数据库(即搜索)。

搜索和查询序列由三组 id 标识: gidtidpid(分别以 s 和 q 为前缀用于搜索和查询),匹配的坐标由一个字符串描述:ch 和两个整数:st 和 @ 987654329@(同样,前缀 s 和 q 分别用于搜索和查询)。

tidpid 在搜索的情况下是 gid 的子集,因此在搜索数据库中它们被保存为单独的行。因此,查询可能会在不同坐标中同时“命中”gidtid 和/或 pid

但是,与 df 中的第 1 行和第 2 行一样,查询在 tid 内进行搜索,因此第 1 行和第 2 行的搜索坐标和查询坐标相同。

所以我正在寻找的是一个function(可能通过dplyr::groupdplyr::filter),它将根据上面的定义返回一个唯一的df

这是我实现这一目标的粗略方法:

tmp.df <- df %>% dplyr::select(-stid,-spid) %>% unique()

uniq.df <- do.call(rbind,lapply(1:nrow(tmp.df),function(i){
  tmp.df.i <- tmp.df[i,,drop=F] %>% dplyr::left_join(df)
  if(!(all(is.na(tmp.df.i$stid) & is.na(tmp.df.i$spid)))){
    tmp.df.i <- tmp.df.i[which(!is.na(tmp.df.i$stid) | !is.na(tmp.df.i$spid)),,drop=F]
  } else{
    tmp.df.i <- tmp.df.i %>%
      dplyr::select(-stid,-spid) %>%
      dplyr::mutate(stid=NA,spid=NA)
  }
  return(tmp.df.i)
}))

#organize the columns of uniq.df to the order of df:
uniq.df <- uniq.df %>% dplyr::select_(.dots = colnames(df))

> uniq.df
   sgid stid spid  sch sst snd qgid qtid qpid  qch qst qnd
2   sg1  st1 <NA> sch1  11  21  qg1  qt1  qp1 qch1 111 211
1   sg2 <NA> <NA> sch2  32  46  qg1  qt1  qp1 qch1 234 267
11  sg3 <NA>  sp3 sch2  21  34  qg1  qt1  qp1 qch1  21  34

寻找更优雅的东西。

【问题讨论】:

  • 刚刚相应地编辑了我的帖子
  • 根据 Wimpel 的回答,您需要 df[!duplicated(df[setdiff(names(df), c("stid","spid"))]), ] 吗?

标签: r dataframe group-by dplyr unique


【解决方案1】:

data.table解决方案

样本数据

#    sgid stid spid  sch sst snd qgid qtid qpid  qch qst qnd
# 1:  sg1 <NA> <NA> sch1  11  21  qg1  qt1  qp1 qch1 111 211
# 2:  sg1  st1 <NA> sch1  11  21  qg1  qt1  qp1 qch1 111 211
# 3:  sg2 <NA> <NA> sch2  32  46  qg1  qt1  qp1 qch1 234 267
# 4:  sg3 <NA>  sp3 sch2  21  34  qg1  qt1  qp1 qch1  21  34

代码

library( data.table )
setDT( df )
#get columns you wish to exclude from duplication-check
cols <- c( "stid", "spid" )
#keep non-duplicated rows, based on a subset of df (without the columns in `cols`)
df[ !duplicated( df[, !..cols] ), ][]

#    sgid stid spid  sch sst snd qgid qtid qpid  qch qst qnd
# 1:  sg1 <NA> <NA> sch1  11  21  qg1  qt1  qp1 qch1 111 211
# 2:  sg2 <NA> <NA> sch2  32  46  qg1  qt1  qp1 qch1 234 267
# 3:  sg3 <NA>  sp3 sch2  21  34  qg1  qt1  qp1 qch1  21  34

替代
如果您不想保留重复的第一行,而是最后一行,请使用:

df[ !duplicated( df[, !..cols], fromLast = TRUE ), ][]  #<-- note fromlast-argument!

#    sgid stid spid  sch sst snd qgid qtid qpid  qch qst qnd
# 1:  sg1  st1 <NA> sch1  11  21  qg1  qt1  qp1 qch1 111 211
# 2:  sg2 <NA> <NA> sch2  32  46  qg1  qt1  qp1 qch1 234 267
# 3:  sg3 <NA>  sp3 sch2  21  34  qg1  qt1  qp1 qch1  21  34

【讨论】:

    【解决方案2】:

    dplyr 这样的事情怎么样:

    cols <- setdiff(names(df), c("stid", "spid"))
    
    df %>% group_by_at(cols) %>% 
      summarise(stid = ifelse(length(unique(stid)) == 1,
                              unique(stid), 
                              unique(stid)[! is.na(unique(stid))]),
                spid = ifelse(length(unique(spid)) == 1,
                              unique(spid), 
                              unique(spid)[! is.na(unique(spid))]))
    

    或者您可以使用 DescTools 包中的函数 Coalesce(或者甚至定义您自己的函数来选择第一个非 NA 值):

    df %>% group_by_at(cols) %>% 
      summarise(stid = DescTools::Coalesce(stid),
                spid = DescTools::Coalesce(spid))
    

    【讨论】:

      猜你喜欢
      • 2021-01-27
      • 1970-01-01
      • 2021-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-03
      • 2022-08-18
      • 2022-08-08
      相关资源
      最近更新 更多