来自两个独立数据框的行的条件子集

时间:2017-08-06 01:15:15

标签: r

我有两个数据框排列,每行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行,我最终得到了太多的重复值。一个优雅的解决方案将不胜感激。

3 个答案:

答案 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

相关问题