我有两个数据框排列,每行qseqid和sseqid相同:
Data frame 1
qseqid evalue bitscore
1 ENSDARP00000000004.2 1e-162 469.0
2 ENSDARP00000000005.6 0e+00 856.0
3 ENSDARP00000000042.9 0e+00 1272.0
4 ENSDARP00000000069.7 3e-111 333.0
5 ENSDARP00000000070.5 2e-11 58.2
Data frame 2
sseqid evalue bitscore
1 ENSDARP00000000004.2 9e-160 462.0
2 ENSDARP00000000005.6 0e+00 821.0
3 ENSDARP00000000042.9 0e+00 1293.0
4 ENSDARP00000000069.7 4e-102 310.0
5 ENSDARP00000000070.5 1e-11 58.2
我想创建一个单独的数据框,其中包含数据框中的行(因此我可以保留比特分数),其中e值最低,如果两个数据框中的evalues相同,则跳过那一排。我的结果看起来像这样:
1 ENSDARP00000000004.2 1e-162 469.0
2 ENSDARP00000000069.7 3e-111 333.0
5 ENSDARP00000000070.5 1e-11 58.2
最小例子的代码:
qseqid <- c("ENSDARP00000000004.2",
"ENSDARP00000000005.6",
"ENSDARP00000000042.9",
"ENSDARP00000000069.7",
"ENSDARP00000000070.5")
evalue <- c(1e-162, 0e+00, 0e+00, 3e-111, 2e-11 )
bitscore <- c(469.0, 856.0, 1272.0, 333.0, 58.2)
df_1 <- data.frame(qseqid, evalue, bitscore)
sseqid <- c("ENSDARP00000000004.2",
"ENSDARP00000000005.6",
"ENSDARP00000000042.9",
"ENSDARP00000000069.7",
"ENSDARP00000000070.5")
evalue <- c(9e-160, 0e+00, 0e+00, 4e-102, 1e-11)
bitscore <- c(462.0, 821.0, 1293.0, 310.0, 58.2)
df_2 <- data.frame(sseqid, evalue, bitscore)
我的第一个想法是使用ifelse(),但这种方法失败了因为我没有 如果evalues在数据帧之间是相等的,那么确定如何传递该行,并且我不确定如何从任一数据帧返回成功的行。
filtered_df <- ifelse(df_1$evalue == df_2$evalue,
next, ifelse(df_1$evalue < df_2s$evalue,
successful df_1 row here,
successful df_2 row here))
我的第二个想法是使用rbind()组合数据框,然后使用aggregate()查找最小值,最后将结果合并为 单一数据帧。但是,这并没有结束真正的数据集。这大约是12k行,我最终得到了太多的重复值。一个优雅的解决方案将不胜感激。
答案 0 :(得分:5)
# Copying the first data.frame
df_3 <- df_1
# Replacing with the values from the second data.frame
# If the values in the second are less than in the first
m <- df_1$evalue > df_2$evalue
df_3[m,] <- df_2[m, ]
# Leave only unique values
df_4 <- df_3[df_1$evalue != df_2$evalue,]
df_4
# qseqid evalue bitscore
# 1 ENSDARP00000000004.2 1e-162 469.0
# 4 ENSDARP00000000069.7 3e-111 333.0
# 5 ENSDARP00000000070.5 1e-11 58.2
答案 1 :(得分:1)
这是一个使用功能样式的选项。步骤1)使用问题中描述的逻辑生成有效行列表(如列表)或否则生成NULL。步骤2)过滤掉空列表。步骤3)用答案恢复data.frame。
#Step 1:
a <- mapply( function(name1,name2,evalue1,evalue2,bitscore1,bitscore2) {
if( name1==name2 )
if ( evalue1 == evalue2 )
NULL
else {
minEvalue <- min(evalue1,evalue2)
keepBitScore <- ifelse(evalue1==minEvalue, bitscore1,bitscore2)
list(qseqid=name1,evalue=minEvalue,bitscore=keepBitScore)
}
},
df_1[,1],df_2[,1], df_1[,2],df_2[,2],df_1[,3],df_2[,3])
#Step 2:
Filter(Negate(function(x) is.null(unlist(x))), a)
#Step 3:
ans<-do.call(rbind.data.frame,a)
给出:
qseqid evalue bitscore
2 ENSDARP00000000004.2 1e-162 469.0
21 ENSDARP00000000069.7 3e-111 333.0
3 ENSDARP00000000070.5 1e-11 58.2
我的回答丢失了原始的行名称。我相信他们可以保留一些调整。我尽可能喜欢直接的功能风格。
答案 2 :(得分:0)
这是使用dplyr包的强大功能的好机会。
首先,让我们为数据帧制作相同的标题,并将“qseqid”/“sseqid”保留为新变量。
library(dplyr)
df_1 <- df_1 %>% mutate('type' = 'qseqid') %>% rename('instance' = 'qseqid')
df_2 <- df_2 %>% mutate('type' = 'sseqid') %>% rename('instance' = 'sseqid')
然后,我们可以轻松地将数据帧绑定在一起并以下列方式处理它:
res <- df_1 %>% bind_rows(df_2) %>%
#calculate standart deviation of "evalue" within created groups
group_by(instance) %>% mutate('diff_e' = sd(evalue)) %>%
#select rows with the following logic: std non-equal zero and select minimal within created groups
filter(diff_e != 0 & evalue == min(evalue))
有关dplyr的更多信息,请考虑以下书籍:http://r4ds.had.co.nz