寻找数据框值的范围
Posted
技术标签:
【中文标题】寻找数据框值的范围【英文标题】:Looking for ranges in dataframe values 【发布时间】:2016-07-18 09:14:34 【问题描述】:我有 2 个数据框:
> access
V1 V2 V3
1 chr10 136122 136533
2 chr10 179432 179769
3 chr10 182988 183371
4 chr10 224234 224489
5 chr10 237693 237958
和
> peaks
V1 V2 V3
1 chr10 126122 126533
2 chr10 179450 179730
3 chr10 182788 183350
4 chr10 224244 224500
5 chr10 237695 237950
V2 和 V3 列是两个数据帧中区域(范围)的开始和结束。我想将这些行保留在peaks
数据帧中,其中access$V1 == peaks$V1
AND 属于access
数据帧的范围(或区域)。例如,新的数据框将类似于:peaks
dataframe's
access
数据帧中不存在第一行区域,因此将为其分配类别 U。
peaks
的第二行在access
数据帧(第二行)中的给定范围内,将被分配类别B。
peaks
的第 3 行并不完全属于该区域,但它与access
的第 3 行中的区域有某种重叠,为此我将分配类别 A。
peaks
的第 4 行在访问第 4 行区域结束后的第 11 个数字结束处也没有完全重叠,这也属于 A 类别。
第 5 行属于该区域,因此属于 B 类别。
预期输出:
> newdf
V1 V2 V3 V4
1 chr10 126122 126533 U
2 chr10 179450 179730 B
3 chr10 182788 183350 A
4 chr10 224244 224500 A
5 chr10 237695 237950 B
这里是输入数据帧的输出:
> dput(peaks)
structure(list(V1 = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "chr10", class = "factor"),
V2 = c(126122L, 179450L, 182788L, 224244L, 237695L), V3 = c(126533L,
179730L, 183350L, 224500L, 237950L)), .Names = c("V1", "V2",
"V3"), class = "data.frame", row.names = c(NA, -5L))
> dput(access)
structure(list(V1 = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "chr10", class = "factor"),
V2 = c(136122L, 179432L, 182988L, 224234L, 237693L), V3 = c(136533L,
179769L, 183371L, 224489L, 237958L)), .Names = c("V1", "V2",
"V3"), class = "data.frame", row.names = c(NA, -5L))
编辑:
我的新访问 df 看起来像这样,现在我还想在最终输出 df 中附加最后一列:
> access
V1 V2 V3 V4
1 chr10 136122 136533 found
2 chr10 179432 179769 notFound
3 chr10 182988 183371 found
4 chr10 224234 224489 found
5 chr10 237693 237958 notFound
所以现在有一个额外的条件,如果访问中的行落在峰值范围内,那么还将 V4 中的值附加到最终 df 的新列中,如果未找到某个区域,则默认情况下将是 notFound
。因此,最终输出将是:
> newdf
V1 V2 V3 V4 V5
1 chr10 126122 126533 U notFound
2 chr10 179450 179730 B notFound
3 chr10 182788 183350 A found
4 chr10 224244 224500 A found
5 chr10 237695 237950 B notFound
在row1$V5
中,该值未找到,因为未找到该区域,在其余情况下,我们从修改后的访问 df 中获取了 V5 中的值。
【问题讨论】:
roll join with start/end window的可能重复 @zx8754 不同之处在于这个问题它只是检查一个数字是否存在于范围内,在这里我正在搜索一个范围(不是数字)其他范围. @zx8754newdf <- subset(merge(access, peaks), start <= V2 & V3 <= end)
这只是给我那些属于这些范围的人,我无法弄清楚如何为他们分配我定义的类别以及如何保留那些不完全属于在那些范围内。你能帮我解决这个问题吗?
foverlaps
的开发正是如此——考虑到遗传区域重叠。阅读函数的 type
和 nomatch
参数。
@zx8754 我已经尝试过,但我无法做我想做的事。当我使用type= "all"
时,我得到的行在这些范围内,并且重叠但不完全在该范围内,当我使用type = "within"
时,我只得到在给定范围内的行。所以我知道我必须使用type= "all"
,但我不知道如何根据我定义的类别标记这些行。请在这种情况下帮助我。谢谢。
【参考方案1】:
如果速度是一个问题,链接的data.table
解决方案可能会更好,但它也可以在dplyr
中实现,但可能要慢得多:
library(dplyr)
names(access)[2:3] <- c('start', 'end')
bind_cols(peaks[-1], access) %>%
rowwise() %>%
mutate(V4 = if_else(all(V2:V3 %in% start:end), 'B',
if_else(any(V2:V3 %in% start:end), 'A',
'U')))
结果:
Source: local data frame [5 x 6]
Groups: <by row>
# A tibble: 5 x 6
V2 V3 V1 start end V4
<int> <int> <fctr> <int> <int> <chr>
1 126122 126533 chr10 136122 136533 U
2 179450 179730 chr10 179432 179769 B
3 182788 183350 chr10 182988 183371 A
4 224244 224500 chr10 224234 224489 A
5 237695 237950 chr10 237693 237958 B
【讨论】:
您在此处使用哪些软件包,因为我收到以下错误:Error in eval(expr, envir, enclos) : could not find function "if_else"
,如果我使用 ifelse
而不是从基数,那么我会收到多个警告,并且所有行的类别都是 U
dplyr
版本0.5.0
。 if_else
不在早期版本中。
我将它应用于我的真实数据时出现错误,其中 2 个数据帧中的行数不同:Error in eval(expr, envir, enclos) : incompatible number of rows (103335, expecting 90)
你能指导我如何解决这个问题。
使用 left_join 而不是 bind_cols。
你能帮我解决这个问题吗question【参考方案2】:
虽然它有很长的路要走。但它给出了预期的结果。
library(dplyr)
df<-cbind(peaks,access) #merging both df
colnames(df)<-c("pV1","pV2","pV3","aV1","aV2","aV3")
df<-df[c(which(df$pV1==df$aV1)),] # selecting rows with pV1=aV1
# creating U, A, B
U1<-df%>%
filter(pV2<aV2 & pV3<aV2)%>%
mutate(V4="U")
U2<-df%>%
filter(pV2>aV3 & pV3>aV3)%>%
mutate(V4="U")
B<-df%>%
filter(pV2>aV2 & pV3<aV3)%>%
mutate(V4="B")
A1<-df%>%
filter(pV2>aV2 & pV3>aV3)%>%
mutate(V4="A")
A2<-df%>%
filter(pV2<aV2 & pV3<aV3 & pV3>aV2)%>%
mutate(V4="A")
#merging U, A and B into newdf
newdf<-arrange(rbind(U1,U2,B,A1,A2),pV2)
newdf<-newdf[,-c(4:6)]
newdf
pV1 pV2 pV3 V4
1 chr10 126122 126533 U
2 chr10 179450 179730 B
3 chr10 182788 183350 A
4 chr10 224244 224500 A
5 chr10 237695 237950 B
【讨论】:
【参考方案3】:使用 foverlaps 函数可以通过以下语句完成:
setkey(setDT(access),V1,V2,V3)
setkey(setDT(peaks),V1,V2,V3)
access[,V4:= ifelse(!is.na(foverlaps(peaks, access, type="within", which=TRUE)$yid),"B",ifelse(!is.na( foverlaps(peaks, access, type="any", which=TRUE)$yid),"A","U"))]
它的作用方式如下:
-
我首先使用“within”类型来确定是否存在精确重叠(因此,如果某个范围包含在任何匹配的访问范围中。如果是这种情况,则为“B”
如果不是这种情况,我使用“任何”来确定我们是否有任何重叠,这实际上识别了具有部分重叠的值,因为在上一步中排除了具有精确重叠的值。这些值获得“A”
其余的得到一个“U”
【讨论】:
你能帮我解决这个问题吗question【参考方案4】:这是另一个(简单的)解决方案,它使用了最近实现的非 equi 连接,并且在 data.table 的当前开发版本 v1.9.7 中可用。见安装说明here:
require(data.table) # v1.9.7+
setDT(access)
setDT(peaks)[, V4 := "U"] # no overlap
peaks[access, V4 := "A", on=.(V1, V2 <= V3, V3 >= V2)] # any overlap
peaks[access, V4 := "B", on=.(V1, V2 >= V2, V3 <= V3)] # completly within
# V1 V2 V3 V4
# 1: chr10 126122 126533 U
# 2: chr10 179450 179730 B
# 3: chr10 182788 183350 A
# 4: chr10 224244 224500 A
# 5: chr10 237695 237950 B
向peaks
添加一个新列,该列全是“U”。然后用“A”替换那些有任何重叠的行。这将包含所有也完全“在”内的行。然后再次执行条件连接,但这次只针对完全内部,并替换为“B”。
请注意,foverlaps()
解决方案也可以正常工作(它也来自 data.table 包)。但是新的非 equi 连接非常适合 [.data.table
语法,它允许在加入时聚合/添加/更新列。
【讨论】:
请确认我没有记错,他们就像:peaks[access, V4 := "A", on=.(peaks$V1, peaks$V2 <= access$V3, peaks$V3 >= access$V2)]
AND peaks[access, V4 := "B", on=.(peaks$V1, peaks$V2 >= access$V2, peaks$V3 <= access$V3)]
你说得对。表达式的 LHS 是指外部的 DT。
我已经修改了问题,看到上面的编辑,你能建议我如何解决这个新问题吗?谢谢。
我试过了,但它不起作用:peaks[access, V5 := access$V4, on=.(peaks$V1, peaks$V2 <= access$V3, peaks$V3 >= access$V2)]
用i.V4
替换access$V4
(我指的是第一个参数,这里是access
)。删除 on=
参数中的所有 ...$
。变量可以通过名称直接引用。 on
参数不明白 ...$
是什么。 Read the vignettes 了解 data.table 的功能/理念。以上是关于寻找数据框值的范围的主要内容,如果未能解决你的问题,请参考以下文章
RedisRedis 字符串数据操作 ② ( 多个数据操作 | 值的范围操作 | 值的时间操作 | 简单动态字符 )