2016-07-17 58 views
1

我有一个列表中的n个矩阵和一个附加矩阵,它包含我想要在矩阵列表中找到的值。匹配一个区间并提取两个矩阵之间的值R

为了得到矩阵的名单,我用这个代码:

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 

我想获得它写入匹配RT. ± 0.02m.z. ± 0.0002Area.结果列表中的所有矩阵中的新矩阵。输出可能就是这样。

 RT. m.z.  Area.[1]  Area.[2] 
1 1.01 358.9777 2820.1  7820.1 
2 1.07 368.4238     8271.8  
3 2.05 284.3295 6674.0  12674.0 
4 2.03 922.0092 5856.3    
5 3.03 261.1299 27814.6    
6 3.65 528.6475  

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

回答

1

这是使用data.table Arun优雅回答的替代方法。我决定后,因为它包含了额外的两个方面是你的问题的重要考虑因素:

  1. 浮点比较:比较,看是否有浮点值处于区间需要考虑廿四的计算间隔时出现错误。这是比较实数的浮点表示的一般问题。在R的上下文中参见thisthis。下面在函数in.interval中实现该比较。

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

为了找到从txt.import.matrix在一个矩阵中的匹配列(个),在矩阵reduced.list.pre.filtering每一行,下面的代码向量化的比较函数在所有列举的双行中的reduced.list.pre.filtering和之间的空间中的应用程序矩阵从txt.import.matrix。从功能上来说,这与Arun使用data.tablenon-equi连接的解决方案相同;但是,non-equi联接功能更为通用,而且即使在此应用程序中,data.table实现最有可能针对内存使用情况和速度进行更好的优化。

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 

注:

  1. 该部分构造数据,以使比较函数在所有列举的对reduced.list.pre.filtering和从txt.import.matrix基质之间的行的空间应用的矢量化。要构建的数据是四个数组,它们是比较标准中使用的两列的重复(或展开式),其中reduced.list.pre.filtering在来自txt.import.matrix的每个矩阵的行维中以及在比较中使用的两列的重复标准,来自txt.import.matrix的每个矩阵的行维数为reduced.list.pre.filtering。这里,术语数组是指二维矩阵或一维矢量。将得到的四个阵列是:

    • r.rtreduced.list.pre.filteringRT.列的复制(即,r[,1])中的t
    • t.rt行维度是矩阵的RT.柱的从txt.import.matrix(复制即,t[,2])中的r
    • r.mz行维度是reduced.list.pre.filtering(即r[,2]m.z.列在行维度复制)
    • t.mztxt.import.matrix的矩阵的m.z.列的复制。 t[,4])在r

    行维度是什么重要的是,为这些数组的索引枚举所有的行对在rt以同样的方式。具体而言,将这些阵列视为尺寸为M,N的2-D矩阵,其中M=nrow(t)N=nrow(r),行索引对应于t的行,列索引对应于r的行。因此,i列(4个阵列中的每一个)的阵列值(在全部四个阵列上)是在ri的第j行之间的比较标准中使用的值第t行。此复制过程的实现使用R功能rep。例如,在计算r.rt,rep中使用each=M,其具有将其数组输入r[,1]作为行向量并复制该行M行以形成M行的效果。结果是,对应于r中的行的每个列具有来自r的对应行的RT.值,并且该值对于r.rt(该列)的所有行都是相同的,其中每个行对应于行在t。这意味着在将r中的该行与t中的任何行进行比较时,将使用r中该行的值RT.。相反,在计算t.rt,rep时使用times=N,其具有将其阵列输入作为列向量处理并复制该列以形成N列的效果。结果是,对应于t中的行的t.rt中的每一行具有来自t的对应行的RT.值,并且该值对于t.rt的所有列(该行的)是相同的,每个列对应于一排在r。这意味着在将t中的该行与r中的任何行进行比较时,将使用t中该行中的值RT.。类似地,r.mzt.mz的计算分别使用来自rtm.z.列。

  2. 这执行导致M通过N逻辑矩阵其中i行和第j个柱是TRUE如果rj第一行的第i行标准匹配的矢量比较t,并FALSE否则。的which()输出是数组索引的阵列,以该逻辑比较结果矩阵,其中其元件是TRUE。我们希望这些数组索引转换为比较结果矩阵指回rt行的行和列索引。下一行从数组索引中提取列索引。注意,变量名是r.ind以表示这些对应于r行。我们提取这首先是因为它是在r检测多个匹配的行很重要。

  3. 这部分处理r中给定行的t可能的多个匹配。多个匹配将在r.ind中显示为重复值。如上所述,这里的逻辑仅在t的行数增加方面保持第一次匹配。函数duplicated返回数组中重复值的所有索引。因此,删除这些元素将做我们想要的。代码首先删除它们从r.ind,那么它从ind删除它们,最后计算列索引比较结果矩阵,其对应于t的行中,使用修剪indr.ind。什么是match.interval返回是一个矩阵,它的行被匹配的一对行索引的与它的第一列为行索引到r和其第二列是列指数来t

  4. get.area.matched功能只需使用结果从match.ind来提取tArea所有比赛。请注意,返回的结果是一个(列)向量,其长度等于r中的行数并初始化为NA。在r这样行已在t敌不过有一个返回的NAArea

  5. 这使用lapply超过列表txt.import.matrix返回匹配结果Area应用功能get.area.matched和附加到reduced.list.pre.filtering为列向量。同样,相应的列名也被附加并设置在结果res中。

编辑:使用foreach

事后替代的实施,更好地实现使用foreach包矢量化的比较。在本实施方式中,foreachmagrittr包需要

require("magrittr") ## for %>% 
require("foreach") 

然后用于矢量化的比较

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)) 

match.interval代码可以通过

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定义as

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)) 
} 

这更容易解析并反映正在执行的内容。请注意,嵌套的foreachcbind结合返回的内容也是逻辑矩阵。最后,也可以使用foreach执行的get.area.matched函数在列表txt.import.matrix应用:

res <- foreach(i = 1:length(txt.import.matrix), .combine=cbind) %do% 
     get.area.matched(reduced.list.pre.filtering, txt.import.matrix[[i]]) %>% 
      cbind(reduced.list.pre.filtering,.) 

使用foreach完整的代码如下:

require("magrittr") 
require("foreach") 

in.interval <- function(x, center, deviation, tol = .Machine$double.eps^0.5) { 
    return (abs(x-center) <= (deviation + tol)) 
} 

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)) 
} 

match.interval <- function(r, t) { 
    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(.) 
    # which returns 1-D indices (row-major), 
    # convert these to 2-D indices in (row,col) 
    r.ind <- floor((ind - 1)/nrow(t)) + 1     ## 2. 
    # detect duplicates in r.ind and remove them from ind 
    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] 
    return(area) 
} 

res <- foreach(i = 1:length(txt.import.matrix), .combine=cbind) %do% 
    get.area.matched(reduced.list.pre.filtering, txt.import.matrix[[i]]) %>% 
     cbind(reduced.list.pre.filtering,.) 

colnames(res) <- c(colnames(reduced.list.pre.filtering), 
      sapply(seq_len(length(txt.import.matrix)), 
       function(i) {return(paste0("Area.[",i,"]"))})) 

希望这有助于。

+0

谢谢爱超!事实上,你的代码对我来说有点复杂,但尝试理解它却是一个很好的挑战。它运行得非常好,我得到了我想要的输出。是的,它帮助了很多! – Vanbell

+0

@Vanbell:谢谢。我仍在编辑帖子。明天再来看看,希望它会更清晰。当然,如果您有任何问题,请留下评论。再次,我想我应该发布指出我认为重要的问题的两个可能方面。 – aichao

+0

好的,我在等你的帖子。我的事情,我会问你一些问题,因为它太容易复制和过去;) – Vanbell

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 

这可能会给你一些想法。可以很容易地适用于检查共享最小值是否超过+/-值。

+0

谢谢,我一旦成功申请,就会通知您。 – Vanbell

2

使用non-equi从data.table,v1.9.7的当前发展版本联接(见installation instructions),它允许要被提供给非相等条件联接:

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()将它们中的每一个转换为10 data.table,并使用rbindlist将它们按行进行绑定,并将名称作为额外列(idcol)添加。叫它A

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

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

[4]最好留在[3]。但如果你喜欢它,如你的答案所示,我们可以将它重新塑造成宽幅。 fill = 0将用0代替NA s。