我在列表中有一个矩阵和一个附加矩阵,其中包含我想在矩阵列表中找到的值。
要获取矩阵列表,我使用以下代码:
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
我只知道如何在一个数组中只匹配一个确切的值。这里的困难是在数组列表中找到值,需要找到值±间隔。如果您有任何建议,我将非常感激。
答案 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相当优雅的答案,这是另一种方法。我决定发布它,因为它包含两个额外的方面,这些方面是您问题中的重要考虑因素:
浮点比较:比较以查看浮点值是否在某个时间间隔内,需要考虑计算时间间隔时的舍入误差。这是比较实数的浮点表示的一般问题。请参阅R上下文中的this和this。以下内容在函数in.interval
中实现此比较。
多次匹配:如果间隔重叠,您的间隔匹配条件可能会导致多次匹配。以下假设您只想要第一个匹配(相对于每个txt.import.matrix
矩阵的增加行)。这是在函数match.interval
中实现的,并在后面的注释中进行了解释。如果你想获得符合你标准的区域的平均值,则需要其他逻辑。
为了在矩阵txt.import.matrix
中的每一行的reduced.list.pre.filtering
矩阵中找到匹配的行,下面的代码将比较函数的应用程序在所有枚举对的空间中向量化。 reduced.list.pre.filtering
与txt.import.matrix
之间的行之间的行。在此应用程序的功能上,这与使用data.table
的{{1}}联接的Arun解决方案相同;但是,non-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
和reduced.list.pre.filtering
之间的矩阵之间的所有枚举行的空间上对比较函数的应用进行矢量化。要构建的数据是四个数组,它们是比较标准中使用的两列的复制(或扩展),来自txt.import.matrix
的每个矩阵的行维度中reduced.list.pre.filtering
的复制和比较标准中使用的两列,来自txt.import.matrix
行维中txt.import.matrix
的每个矩阵。这里,术语阵列指的是2-D矩阵或1-D矢量。得到的四个数组是:
reduced.list.pre.filtering
是r.rt
行RT.
中reduced.list.pre.filtering
列r[,1]
的复制(即t
t.rt
是来自RT.
t[,2]
)矩阵的r
列的复制>
r.mz
是m.z.
行reduced.list.pre.filtering
中r[,2]
列t
的复制(t.mz
m.z.
是txt.import.matrix
t[,4]
(即r
)矩阵的r
列的复制
重要的是,每个数组的索引都以相同的方式枚举t
和M
中的所有行对。具体来说,将这些数组视为大小为N
的二维矩阵M=nrow(t)
N=nrow(r)
和t
,行索引对应r
行和列索引对应于i
的行。因此,j
- 行和j
- 列(四个数组中的每一个)的数组值(在所有四个数组上)是{之间的比较标准中使用的值{1}} - 第r
行和i
行t
。此复制过程的实现使用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.mz
和t.mz
中的m.z.
列。
执行向量化比较,得到r
个t
逻辑矩阵,M
- 行和N
- 列为{{ 1}}如果i
的{{1}}行符合j
- TRUE
行的标准,则j
。 r
的输出是此逻辑比较结果矩阵的数组索引数组,其元素为i
。我们希望将这些数组索引转换为比较结果矩阵的行索引和列索引,以引用t
和FALSE
的行。下一行从数组索引中提取列索引。请注意,变量名称为which()
,表示这些对应于TRUE
的行。我们首先提取它,因为它对于r
中的行检测多个匹配很重要。
此部分针对t
中给定行的r.ind
处理可能的多个匹配项。多个匹配项将在r
中显示为重复值。如上所述,此处的逻辑仅保留第一个匹配,以增加r
中的行数。函数t
返回数组中重复值的所有索引。因此,删除这些元素将做我们想要的。代码首先将它们从r
中删除,然后将它们从r.ind
中删除,最后使用修剪的计算列索引到比较结果矩阵,该矩阵对应于t
的行duplicated
和r.ind
。 ind
返回的是一个矩阵,其行是匹配的行索引对,其第一列是t
的行索引,第二列是ind
的行索引。
r.ind
函数只使用match.interval
的结果从r
中提取所有匹配的t
。请注意,返回的结果是一个(列)向量,其长度等于get.area.matched
中的行数并初始化为match.ind
。这样,Area
中t
中没有匹配的行r
已返回NA
。
这会使用r
将功能t
应用于列表Area
,并将返回的匹配NA
结果附加到lapply
作为列向量。同样,相应的列名也会在结果get.area.matched
中附加并设置。
修改:使用txt.import.matrix
包
事后看来,更好的实现使用Area
包进行矢量化比较。在此实施中,reduced.list.pre.filtering
和res
包是必需的
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
希望这有帮助。