匹配间隔并提取两个矩阵R之间的值

时间:2016-07-17 23:16:19

标签: r find match intervals

我在列表中有一个矩阵和一个附加矩阵,其中包含我想在矩阵列表中找到的值。

要获取矩阵列表,我使用以下代码:

setwd("C:\\~\\Documents\\R") 


import.multiple.txt.files<-function(pattern=".txt",header=T)
{
list.1<-list.files(pattern=".txt")
list.2<-list()
for (i in 1:length(list.1))
{
list.2[[i]]<-read.delim(list.1[i])
}
names(list.2)<-list.1
list.2

}


txt.import.matrix<-cbind(txt.import)

我的列表看起来像这样:(我只展示一个n = 2的例子)。每个数组中的行数是不同的(这里我只需要5行和6行来简化,但我的真实数据超过500行。)

txt.import.matrix[1]

    [[1]]
     X.     RT.     Area.  m.z.      
1     1     1.01   2820.1  358.9777  
2     2     1.03   9571.8  368.4238  
3     3     2.03   6674.0  284.3294  
4     4     2.03   5856.3  922.0094  
5     5     3.03   27814.6 261.1299  


txt.import.matrix[2]

    [[2]]
     X.     RT.     Area.  m.z.      
1     1     1.01    7820.1 358.9777  
2     2     1.06    8271.8 368.4238  
3     3     2.03   12674.0 284.3294  
4     4     2.03    5856.6 922.0096  
5     5     2.03   17814.6 261.1299
6     6     3.65    5546.5 528.6475  

我想在矩阵列表中找到另一个值数组。这个数组是通过组合数组中列表中的所有数组并删除重复项来获得的。

reduced.list.pre.filtering

     RT.   m.z.
1    1.01  358.9777
2    1.07  368.4238
3    2.05  284.3295
4    2.03  922.0092
5    3.03  261.1299
6    3.56  869.4558

我想获得一个新矩阵,其中为列表中的所有矩阵写入匹配Area.RT. ± 0.02的{​​{1}}结果。输出可能就是这样。

m.z. ± 0.0002

我只知道如何在一个数组中只匹配一个确切的值。这里的困难是在数组列表中找到值,需要找到值±间隔。如果您有任何建议,我将非常感激。

3 个答案:

答案 0 :(得分:2)

使用当前开发版本的data.table,v1.9.7(参见installation instructions)中的non-equi联接,它允许向联接​​提供非等于条件:

require(data.table) # v1.9.7
names(ll) = c("Area1", "Area2")
A = rbindlist(lapply(ll, as.data.table), idcol = "id")           ## (1)

B = as.data.table(mat)
B[, c("RT.minus", "RT.plus") := .(RT.-0.02, RT.+0.02)]
B[, c("m.z.minus", "m.z.plus") := .(m.z.-0.0002, m.z.+0.0002)]   ## (2)

ans = A[B, .(id, X., RT. = i.RT., m.z. = i.m.z., Area.), 
           on = .(RT. >= RT.minus, RT. <= RT.plus, 
                  m.z. >= m.z.minus, m.z. <= m.z.plus)]          ## (3)

dcast(ans, RT. + m.z. ~ id)                                      ## (4)
# or dcast(ans, RT. + m.z. ~ id, fill = 0)
#     RT.     m.z.   Area1   Area2
# 1: 1.01 358.9777  2820.1  7820.1
# 2: 1.07 368.4238      NA  8271.8
# 3: 2.03 922.0092  5856.3      NA
# 4: 2.05 284.3295  6674.0 12674.0
# 5: 3.03 261.1299 27814.6      NA

[1]命名矩阵列表(此处称为ll)并使用lapply()将它们转换为 data.table ,然后按行绑定它们使用rbindlist,并将名称添加为额外列(idcol)。称之为A

[2]将第二个矩阵(此处称为mat)转换为 data.table 。添加与您要搜索的范围/间隔对应的其他列(因为on=参数,我们将在下一步中看到,无法处理表达式尚未)。称之为B

[3]执行条件连接/子集。对于B中的每一行,找到与A参数提供的条件对应的on=中的匹配行,并为那些匹配的行索引提取列id, X., R.T. and m.z.

[4]最好留在[3]。但如果你喜欢它,如你的答案中所示,我们可以将其重塑为宽幅格式。 fill = 0会将结果中的NA替换为0

答案 1 :(得分:1)

如果我得到你想要做的事情,这是一个快速粗略的方法,可能会有所帮助。

取消列出两个矩阵的每个变量的值

areas <- unlist(lapply(txt.import.matrix, function(x) x$Area.))
rts <- unlist(lapply(txt.import.matrix, function(x) x$RT.))
mzs <- unlist(lapply(txt.import.matrix, function(x) x$m.z.))

查找RT和m.z的那些值的索引。最接近第三个矩阵/ df中的值:

 rtmins <- lapply(reduced.list.pre.filtering$RT., function(x) which(abs(rts-x)==min(abs(rts-x))))
mzmins <- lapply(reduced.list.pre.filtering$m.z., function(x) which(abs(mzs-x)==min(abs(mzs-x))))

使用purrr快速计算两者中的哪些指数(即每个指数的最小差异):

inboth <- purrr::map2(rtmins,mzmins,intersect)

获取相应的区域值:

vals<-lapply(inboth, function(x) areas[x])

使用reshape2加入宽格式:

vals2 <- reshape2::melt(vals)
vals2$number <- ave(vals2$L1, vals2$L1, FUN = seq_along)
vals.wide <-reshape2::dcast(vals2, L1 ~ number, value.var="value")

cbind(reduced.list.pre.filtering, vals.wide)

#   RT.     m.z. L1       1       2
#1 1.01 358.9777  1  2820.1  7820.1
#2 1.07 368.4238  2  8271.8      NA
#3 2.05 284.3295  3  6674.0 12674.0
#4 2.03 922.0092  4  5856.3      NA
#5 3.03 261.1299  5 27814.6      NA

这可能会给你一些想法。可以轻松调整以检查共享的最小值是否超过+/-值。

答案 2 :(得分:1)

对于使用data.table的Arun相当优雅的答案,这是另一种方法。我决定发布它,因为它包含两个额外的方面,这些方面是您问题中的重要考虑因素:

  1. 浮点比较:比较以查看浮点值是否在某个时间间隔内,需要考虑计算时间间隔时的舍入误差。这是比较实数的浮点表示的一般问题。请参阅R上下文中的thisthis。以下内容在函数in.interval中实现此比较。

  2. 多次匹配:如果间隔重叠,您的间隔匹配条件可能会导致多次匹配。以下假设您只想要第一个匹配(相对于每个txt.import.matrix矩阵的增加行)。这是在函数match.interval中实现的,并在后面的注释中进行了解释。如果你想获得符合你标准的区域的平均值,则需要其他逻辑。

  3. 为了在矩阵txt.import.matrix中的每一行的reduced.list.pre.filtering矩阵中找到匹配的行,下面的代码将比较函数的应用程序在所有枚举对的空间中向量化。 reduced.list.pre.filteringtxt.import.matrix之间的行之间的行。在此应用程序的功能上,这与使用data.table的{​​{1}}联接的Arun解决方案相同;但是,non-equi连接功能更为通用,non-equi实现最有可能针对此应用程序的内存使用和速度进行更好的优化。

    data.table

    注意:

    1. 此部分构造数据,以便在in.interval <- function(x, center, deviation, tol = .Machine$double.eps^0.5) { return (abs(x-center) <= (deviation + tol)) } match.interval <- function(r, t) { r.rt <- rep(r[,1], each=nrow(t)) t.rt <- rep(t[,2], times=nrow(r)) r.mz <- rep(r[,2], each=nrow(t)) t.mz <- rep(t[,4], times=nrow(r)) ## 1. ind <- which(in.interval(r.rt, t.rt, 0.02) & in.interval(r.mz, t.mz, 0.0002)) r.ind <- floor((ind - 1)/nrow(t)) + 1 ## 2. dup <- duplicated(r.ind) r.ind <- r.ind[!dup] t.ind <- ind[!dup] - (r.ind - 1)*nrow(t) ## 3. return(cbind(r.ind,t.ind)) } get.area.matched <- function(r, t) { match.ind <- match.interval(r, t) area <- rep(NA,nrow(r)) area[match.ind[,1]] <- t[match.ind[,2], 3] ## 4. return(area) } res <- cbind(reduced.list.pre.filtering, do.call(cbind,lapply(txt.import.matrix, get.area.matched, r=reduced.list.pre.filtering))) ## 5. colnames(res) <- c(colnames(reduced.list.pre.filtering), sapply(seq_len(length(txt.import.matrix)), function(i) {return(paste0("Area.[",i,"]"))})) ## 6. print(res) ## RT. m.z. Area.[1] Area.[2] ##[1,] 1.01 358.9777 2820.1 7820.1 ##[2,] 1.07 368.4238 NA 8271.8 ##[3,] 2.05 284.3295 6674.0 12674.0 ##[4,] 2.03 922.0092 5856.3 NA ##[5,] 3.03 261.1299 27814.6 NA ##[6,] 3.56 869.4558 NA NA reduced.list.pre.filtering之间的矩阵之间的所有枚举行的空间上对比较函数的应用进行矢量化。要构建的数据是四个数组,它们是比较标准中使用的两列的复制(或扩展),来自txt.import.matrix的每个矩阵的行维度中reduced.list.pre.filtering的复制和比较标准中使用的两列,来自txt.import.matrix行维中txt.import.matrix的每个矩阵。这里,术语阵列指的是2-D矩阵或1-D矢量。得到的四个数组是:

      • reduced.list.pre.filteringr.rtRT.reduced.list.pre.filteringr[,1]的复制(即t
      • t.rt是来自RT. txt.import.matrix(即t[,2])矩阵的r列的复制>
      • r.mzm.z.reduced.list.pre.filteringr[,2]t的复制(t.mz
      • m.z.txt.import.matrix
      • 行维中t[,4](即r)矩阵的r列的复制

      重要的是,每个数组的索引都以相同的方式枚举tM中的所有行对。具体来说,将这些数组视为大小为N的二维矩阵M=nrow(t) N=nrow(r)t,行索引对应r行和列索引对应于i的行。因此,j - 行和j - 列(四个数组中的每一个)的数组值(在所有四个数组上)是{之间的比较标准中使用的值{1}} - 第r行和it。此复制过程的实现使用R函数rep。例如,在计算r.rt时,使用rep each=M,这会将其数组输入r[,1]视为行向量并复制该行{{1}形成M行的次数。结果是,与M中的行对应的每个列都具有来自r的相应行的RT.值,并且该值对于所有行都是相同的( ({1}}列,每个r对应r.rt中的一行。这意味着,在将t中的该行与r中的任意行进行比较时,会使用t中该行的RT.值。相反,在计算r时,使用带有t.rt的{​​{1}},这会将其数组输入视为列向量并将该列rep复制一次以形成times=N列。结果是,N中与N中的行对应的每一行都具有来自t.rt的相应行的t值,并且该值相同对于RT.的所有列(该行),每个列对应t中的一行。这意味着,在将t.rt中的该行与r中的任意行进行比较时,会使用t中该行的r值。同样,RT.t的计算分别使用r.mzt.mz中的m.z.列。

    2. 执行向量化比较,得到rt逻辑矩阵,M - 行和N - 列为{{ 1}}如果i的{​​{1}}行符合j - TRUE行的标准,则jr的输出是此逻辑比较结果矩阵的数组索引数组,其元素为i。我们希望将这些数组索引转换为比较结果矩阵的行索引和列索引,以引用tFALSE的行。下一行从数组索引中提取列索引。请注意,变量名称为which(),表示这些对应于TRUE的行。我们首先提取它,因为它对于r中的行检测多个匹配很重要。

    3. 此部分针对t中给定行的r.ind处理可能的多个匹配项。多个匹配项将在r中显示为重复值。如上所述,此处的逻辑仅保留第一个匹配,以增加r中的行数。函数t返回数组中重复值的所有索引。因此,删除这些元素将做我们想要的。代码首先将它们从r中删除,然后将它们从r.ind中删除,最后使用修剪的计算列索引到比较结果矩阵,该矩阵对应于t的行duplicatedr.indind返回的是一个矩阵,其行是匹配的行索引对,其第一列是t的行索引,第二列是ind的行索引。

    4. r.ind函数只使用match.interval的结果从r中提取所有匹配的t。请注意,返回的结果是一个(列)向量,其长度等于get.area.matched中的行数并初始化为match.ind。这样,Areat中没有匹配的行r已返回NA

    5. 这会使用r将功能t应用于列表Area,并将返回的匹配NA结果附加到lapply作为列向量。同样,相应的列名也会在结果get.area.matched中附加并设置。

    6. 修改:使用txt.import.matrix

      的替代实施方式

      事后看来,更好的实现使用Area包进行矢量化比较。在此实施中,reduced.list.pre.filteringres包是必需的

      foreach

      然后foreach中的代码用于矢量化比较

      foreach

      可以替换为

      magrittr

      require("magrittr") ## for %>% require("foreach") 定义为

      match.interval

      这更容易解析并反映正在执行的内容。请注意,嵌套r.rt <- rep(r[,1], each=nrow(t)) t.rt <- rep(t[,2], times=nrow(r)) r.mz <- rep(r[,2], each=nrow(t)) t.mz <- rep(t[,4], times=nrow(r)) # 1. ind <- which(in.interval(r.rt, t.rt, 0.02) & in.interval(r.mz, t.mz, 0.0002)) ind <- foreach(r.row = 1:nrow(r), .combine=cbind) %:% foreach(t.row = 1:nrow(t)) %do% match.criterion(r.row, t.row, r, t) %>% as.logical(.) %>% which(.) 结合返回的内容也是逻辑矩阵。最后,还可以使用match.criterion在列表match.criterion <- function(r.row, t.row, r, t) { return(in.interval(r[r.row,1], t[t.row,2], 0.02) & in.interval(r[r.row,2], t[t.row,4], 0.0002)) } 上应用foreach函数:

      cbind

      使用get.area.matched的完整代码如下:

      txt.import.matrix

      希望这有帮助。