检查向量中的值是否包含在不同数据集中的值范围内
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 中使用三种方法完成:fuzzyjoin
、data.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)与新范围匹配。我的一个问题是如何处理这样的多个匹配项,最好的情况取决于您如何使用它。
- 如果你只是想把它打印出来,你再也不会把肽作为数据来处理,那么我们可以combine/concatenate把它们变成一个字符串,例如,
"LP, IP"
或"LP, IP, IP"
.
- 如果你想压缩框架但稍后将它们用作数据,那么我不鼓励字符串连接,因为这意味着你必须稍后重新解析它。这相对简单,但如果有任何非标准的肽串,就容易出现问题。在这种情况下,我建议使用列表列来存储数据。
- 如果您不需要压缩框架,则将其保留为较长格式,接受重复
mzmin
/mzmax
对。
三个选项,演示:
字符串连接:
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>
列表列
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
。它运行良好,但需要稍作调整。
留着吧。好吧,不需要演示。 (虽然你总是可以使用 !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))
我在 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 中使用三种方法完成:fuzzyjoin
、data.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)与新范围匹配。我的一个问题是如何处理这样的多个匹配项,最好的情况取决于您如何使用它。
- 如果你只是想把它打印出来,你再也不会把肽作为数据来处理,那么我们可以combine/concatenate把它们变成一个字符串,例如,
"LP, IP"
或"LP, IP, IP"
. - 如果你想压缩框架但稍后将它们用作数据,那么我不鼓励字符串连接,因为这意味着你必须稍后重新解析它。这相对简单,但如果有任何非标准的肽串,就容易出现问题。在这种情况下,我建议使用列表列来存储数据。
- 如果您不需要压缩框架,则将其保留为较长格式,接受重复
mzmin
/mzmax
对。
三个选项,演示:
字符串连接:
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>
列表列
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
。它运行良好,但需要稍作调整。留着吧。好吧,不需要演示。 (虽然你总是可以使用
!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))