检查向量中的值是否包含在不同数据集中的值范围内

Checking if values in vector is included in range of values in different dataset

我在 R 中工作并且有一个大型数据框(我的数据库 =“db”),其中包含不同的 m/z 质量,这些质量对应于这样的肽序列:

    peptide MZ
    WV  304.16558
    VR  274.18738
    VR  274.18738
    LP  229.15468
    IP  229.15468
    IP  229.15468
    FP  263.13903

第二个数据框(“df”)具有一系列 MZ 肽,如下所示:

mzmin        mzmax
296.2286    296.2584
296.8832    297.0105
299.1425    299.1511
301.1299    301.2393
301.0612    301.1668
302.106     302.1985

我想做的是检查第一个数据框中的行是否适合第二个数据框的范围,如果是,则将肽序列(第一个数据框的第 1 列)添加到第二个数据框。 是否有任何 R 函数可以帮助我完成这项任务?

我用过:

# order the first data.frame by the ranges

df <- df[order(df[[1]]), ]

# create a vector breaks from the interval ranges

breaks <- as.vector(do.call(rbind, df[c(1,2)]))
ints <- ceiling(findInterval(db[[2]], breaks)/2)

df$ <- df[ints, 3]

我需要匹配,所以我在 df 中添加了一行 229 到 230 之间。此解决方案使用 dplyr

df %>% rowwise() %>% 
   mutate(pptz=ifelse(is.null(db$peptide[between(db$MZ,mzmin,mzmax)]), NA, 
      paste(unique(db$peptide[between(db$MZ,mzmin,mzmax)]),collapse=", ")))
Source: local data frame [7 x 3]
Groups: <by row>

# A tibble: 7 x 3
  mzmin mzmax pptz    
  <dbl> <dbl> <chr>   
1  296.  296. ""      
2  297.  297. ""      
3  299.  299. ""      
4  301.  301. ""      
5  301.  301. ""      
6  302.  302. ""      
7  229   230  "LP, IP"

我认为“非相等”或“范围”连接的概念在这里很合适。这可以在 R 中使用三种方法完成:fuzzyjoindata.table 或某种形式的 SQL(例如,sqldf)。

与@iod 类似,我正在注入一些虚假数据以找到匹配项。即,我将 228-230 的范围添加到 df.

out <- fuzzyjoin::fuzzy_left_join(
  df, db,
  by = c("mzmin" = "MZ", "mzmax" = "MZ"),
  match_fun = list(`<=`, `>=`)
)
out
#      mzmin    mzmax peptide       MZ
# 1 228.0000 230.0000      LP 229.1547
# 2 228.0000 230.0000      IP 229.1547
# 3 228.0000 230.0000      IP 229.1547
# 4 296.2286 296.2584    <NA>       NA
# 5 296.8832 297.0105    <NA>       NA
# 6 299.1425 299.1511    <NA>       NA
# 7 301.1299 301.2393    <NA>       NA
# 8 301.0612 301.1668    <NA>       NA
# 9 302.1060 302.1985    <NA>       NA

这表明两个肽段(LP 和 IP)与新范围匹配。我的一个问题是如何处理这样的多个匹配项,最好的情况取决于您如何使用它。

  1. 如果你只是想把它打印出来,你再也不会把肽作为数据来处理,那么我们可以combine/concatenate把它们变成一个字符串,例如,"LP, IP""LP, IP, IP".
  2. 如果你想压缩框架但稍后将它们用作数据,那么我不鼓励字符串连接,因为这意味着你必须稍后重新解析它。这相对简单,但如果有任何非标准的肽串,就容易出现问题。在这种情况下,我建议使用列表列来存储数据。
  3. 如果您不需要压缩框架,则将其保留为较长格式,接受重复 mzmin/mzmax 对。

三个选项,演示:

  1. 字符串连接:

    do.call(rbind, by(out, out[,c("mzmin", "mzmax")], FUN = function(z) {
      within(z, {
        peptide = if (any(!is.na(peptide))) paste(na.omit(peptide), collapse = ",") else NA_character_
      })[1,]
    }))
    #      mzmin    mzmax  peptide
    # 1 228.0000 230.0000 LP,IP,IP
    # 4 296.2286 296.2584     <NA>
    # 5 296.8832 297.0105     <NA>
    # 6 299.1425 299.1511     <NA>
    # 8 301.0612 301.1668     <NA>
    # 7 301.1299 301.2393     <NA>
    # 9 302.1060 302.1985     <NA>
    
  2. 列表列

    do.call(rbind, by(out, out[,c("mzmin", "mzmax")], FUN = function(z) {
      within(z, {
        peptide = if (any(!is.na(peptide))) list(na.omit(peptide)) else list(NA_character_)
      })[1,]
    }))
    #      mzmin    mzmax    peptide
    # 1 228.0000 230.0000 LP, IP, IP
    # 4 296.2286 296.2584         NA
    # 5 296.8832 297.0105         NA
    # 6 299.1425 299.1511         NA
    # 8 301.0612 301.1668         NA
    # 7 301.1299 301.2393         NA
    # 9 302.1060 302.1985         NA
    

    虽然这看起来很相似,但并不是...... peptide 列中的每个“元素”实际上都是它自己的向量。不幸的是,任何通常处理帧的列并期望向量的东西都不适用于此,因为......它是 list,而不是 vector。它运行良好,但需要稍作调整。

  3. 留着吧。好吧,不需要演示。 (虽然你总是可以使用 !duplicated(.) 来减少其中的欺骗。)

范围连接的其他方法:

  • SQL总体上是支持的。 sqldf 的使用避免了将数据导入 DBMS、处理数据并查询回来的需要。

    sqldf::sqldf("
      select df.mzmin, df.mzmax, db.peptide
      from df
        left join db on df.mzmin <= db.MZ and df.mzmax >= db.MZ")
    #      mzmin    mzmax peptide
    # 1 228.0000 230.0000      LP
    # 2 228.0000 230.0000      IP
    # 3 228.0000 230.0000      IP
    # 4 296.2286 296.2584    <NA>
    # 5 296.8832 297.0105    <NA>
    # 6 299.1425 299.1511    <NA>
    # 7 301.1299 301.2393    <NA>
    # 8 301.0612 301.1668    <NA>
    # 9 302.1060 302.1985    <NA>
    

    或更简洁地使用 between:

    sqldf::sqldf("
      select df.mzmin, df.mzmax, db.peptide
      from df
        left join db on db.MZ between df.mzmin and df.mzmax")
    
  • data.table 套餐

    library(data.table)
    dbDT <- as.data.table(db)
    dfDT <- as.data.table(df)
    dbDT[dfDT, on = .(MZ >= mzmin, MZ <= mzmax)]
    #    peptide       MZ     MZ.1
    # 1:      LP 228.0000 230.0000
    # 2:      IP 228.0000 230.0000
    # 3:      IP 228.0000 230.0000
    # 4:    <NA> 296.2286 296.2584
    # 5:    <NA> 296.8832 297.0105
    # 6:    <NA> 299.1425 299.1511
    # 7:    <NA> 301.1299 301.2393
    # 8:    <NA> 301.0612 301.1668
    # 9:    <NA> 302.1060 302.1985
    

    注意:如果您尚未使用 data.table,请确保在尝试此操作之前转换为 data.table 格式。它之所以有效,是因为包知道如何处理它自己的对象。


数据:

db <- structure(list(peptide = c("WV", "VR", "VR", "LP", "IP", "IP", "FP"), MZ = c(304.16558, 274.18738, 274.18738, 229.15468, 229.15468, 229.15468, 263.13903)), class = "data.frame", row.names = c(NA, -7L))
df <- structure(list(mzmin = c(228, 296.2286, 296.8832, 299.1425, 301.1299, 301.0612, 302.106), mzmax = c(230, 296.2584, 297.0105, 299.1511, 301.2393, 301.1668, 302.1985)), class = "data.frame", row.names = c(NA, -7L))