如何在获取某些列的最小值和最大值时折叠R中的矩阵

时间:2014-07-27 01:09:04

标签: r dataframe

我在R中有以下数据框。它代表了一个简化的蛋白质结构,以便于解释。

Uniprots Chain resSeq Serial
P68871  D   23  3446
P68871  D   24  3453
P68871  D   25  3457
P68871  D   26  3461
P68871  D   27  3470
P69011  A   38  3561
P69011  A   39  3568
P69011  A   40  3577
P69011  A   41  3588
P69011  A   42  3599
P69011  A   43  3610
P69011  A   44  3619
P69011  A   45  3625
P69011  A   46  3636
P0116   B   2   4239
P0116   B   4   4242
P0116   B   5   4268
P0116   B   6   4279
P0116   B   7   4285
P0116   B   8   4299
P0116   B   9   5015
P0116   C   15  5055
P0116   C   30  5199
P0116   C   42  5239

我想要的是把它折叠起来,看起来像这样:

Uniprot Chain resSeq_start resSeq_end Serial_start Serial_end
P68871   D      23            27          3446       3470
P69011   A      38            46          3561       3636
P0116    B       2             9          4239       5015
P0116    C      15            42          5055       5239

基本上,我希望在前1,2和3列上向下折叠。然后我可以使用第4列作为检查它是否有效。我以为我可以用聚合来做到这一点,但这似乎不起作用。我肯定可以通过一些凌乱的for循环来做到这一点(继续附加到一个向量直到一个新的uniprot /链)但这很难看。

有一点需要注意的是,Uniprot / Chain组合并不总是唯一的。具体来说,uniprot可以有多个链(如我的例子)。

感谢您的帮助!

3 个答案:

答案 0 :(得分:4)

当然还有dplyr

require(dplyr)
dat %>% group_by(Uniprots, Chain) %>%
    summarize(resSeq_start = min(resSeq),
              resSeq_end   = max(resSeq),
              Serial_start = min(Serial),
              Serial_end   = max(Serial))

答案 1 :(得分:3)

我推荐data.table。

这是一个简单的实现:

Step1:将data.frame转换为data.table:

library(data.table)
setDT(dt)

第2步:创建新列:

dt[, `:=`(resSeq_start = min(resSeq), 
          resSeq_end   = max(resSeq), 
          Serial_start = min(Serial), 
          Serial_end   = max(Serial)), 
by = list(Uniprots, Chain)]

第3步:删除旧列:

res <- dt[, c("Serial", "resSeq") := NULL]

步骤4:仅保留唯一列:

unique(res, by=c("Uniprots", "Chain"))
#    Uniprots Chain resSeq_start resSeq_end Serial_start Serial_end
# 1:   P68871     D           23         27         3446       3470
# 2:   P69011     A           38         46         3561       3636
# 3:    P0116     B            2          9         4239       5015
# 4:    P0116     C           15         42         5055       5239

我已经说明了使用data.table引用添加/删除列的两种方法。一个使用c("col", "col2") := list(val1, val2),另一个使用`:=`(col1 = val1,col2 = val2)。

希望这会有所帮助。您应该阅读有关data.table的更多信息。

答案 2 :(得分:3)

aggregate:@ user20650提供的基本解决方案(我更喜欢)(do.call很重要,因为聚合将返回数据框,但带有矩阵元素)

do.call(data.frame, aggregate(cbind(resSeq, Serial) ~ Uniprots + Chain, 
                              data = dat, function(x) c(start = min(x), end = max(x))))

#   Uniprots Chain resSeq.start resSeq.end Serial.start Serial.end
# 1   P69011     A           38         46         3561       3636
# 2    P0116     B            2          9         4239       5015
# 3    P0116     C           15         42         5055       5239
# 4   P68871     D           23         27         3446       3470

plyr

dat <- psych::read.clipboard()

library(plyr)

ddply(dat, .(Uniprots, Chain), summarise, 
      resSeq_start = min(resSeq),
      resSeq_end = max(resSeq),
      Serial_start = Serial[which.min(resSeq)],
      Serial_end = Serial[which.max(resSeq)])

#   Uniprots Chain resSeq_start resSeq_end Serial_start Serial_end
# 1    P0116     B            2          9         4239       5015
# 2    P0116     C           15         42         5055       5239
# 3   P68871     D           23         27         3446       3470
# 4   P69011     A           38         46         3561       3636

(可能不需要.min / max)