我有一个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标识:
gid
,tid
和pid
(分别以s和q前缀进行搜索和查询),并且匹配项的坐标由字符串ch
和两个整数:st
和nd
(再次以s和q为前缀分别表示搜索和查询)。
tid
和pid
在搜索的情况下是gid
的子集,因此在搜索数据库中它们被保存为单独的行。因此,查询可能会在不同的坐标中“击中” gid
和tid
和/或pid
。
但是,与df
中第1行和第2行的情况一样,查询正在tid
内部进行搜索,因此第1行和第2行的搜索和查询坐标是相同的。 / p>
所以我要寻找的是function
(可能通过dplyr::group
和dplyr::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
正在寻找更优雅的东西。
答案 0 :(得分: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
答案 1 :(得分:1)
使用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))]))
或者您可以使用Coalesce
包中的函数DescTools
(甚至定义您自己的函数来选择第一个非NA值):
df %>% group_by_at(cols) %>%
summarise(stid = DescTools::Coalesce(stid),
spid = DescTools::Coalesce(spid))