如何将间隔数据组合成 R 中更少的间隔?
How to combine intervals data into fewer intervals in R?
我正在尝试将一系列间隔折叠成更少但同样有意义的间隔。
例如考虑这个间隔列表
Intervals = list(
c(23,34),
c(45,48),
c(31,35),
c(7,16),
c(5,9),
c(56,57),
c(55,58)
)
因为区间重叠,相同的区间可以用很少的向量来描述。绘制这些间隔很明显,4 个向量的列表就足够了
plot(1,1,type="n",xlim=range(unlist(Intervals)),ylim=c(0.9,1.1))
segments(
x0=sapply(Intervals,"[",1),
x1=sapply(Intervals,"[",2),
y0=rep(1,length(Intervals)),
y1=rep(1,length(Intervals)),
lwd=10
)
如何减少我的 Intervals
列表以携带与绘图上显示的信息相同的信息? (性能问题)
上述示例所需的输出是
Intervals = list(
c(5,16)
c(23,35),
c(45,48),
c(55,58)
)
你需要的是IRanges
包中的reduce
函数。
In.df <- do.call(rbind, Intervals)
library(IRanges)
In.ir <- IRanges(In.df[, 1], In.df[,2])
out.ir <- reduce(In.ir)
out.ir
# IRanges of length 4
# start end width
# [1] 5 16 12
# [2] 23 35 13
# [3] 45 48 4
# [4] 55 58 4
基数为R的一个选项:
首先我把你的列表放在 data.frame
:
ints <- as.data.frame(do.call(rbind, Intervals))
names(ints) <- c('start', 'stop')
看起来像
start stop
1 23 34
2 45 48
3 31 35
4 7 16
5 5 9
6 56 57
7 55 58
现在,两个for
循环与between
进行比较,发现交叉时扩大一个区间:
for(x in 1:nrow(ints)){
for(y in 1:nrow(ints)){
if(between(ints$start[x], ints$start[y], ints$stop[y])){
ints$start[x] <- ints$start[y]
if(ints$stop[y] > ints$stop[x]){
ints$stop[x] <- ints$stop[y]
} else {
ints$stop[y] <- ints$stop[x]
}
}
}
}
将 ints
更改为
> ints
start stop
1 23 35
2 45 48
3 23 35
4 5 16
5 5 16
6 55 58
7 55 58
简化为 unique
个案例:
ints <- unique(ints, margin = 1)
并把它们整理好
ints <- ints[order(ints$start),]
还剩下
> ints
start stop
4 5 16
1 23 35
2 45 48
6 55 58
如果你想把它放回原来的列表中,
Intervals <- lapply(1:nrow(ints), function(x)c(ints[x,1], ints[x,2]))
(注意:您当然可以使用 *apply
代替 for
,使用布尔值代替 between
,使用原始列表代替 data.frame
,但是,嗯,这是可读的。Rewrite/optimize随你喜欢。)
我正在尝试将一系列间隔折叠成更少但同样有意义的间隔。
例如考虑这个间隔列表
Intervals = list(
c(23,34),
c(45,48),
c(31,35),
c(7,16),
c(5,9),
c(56,57),
c(55,58)
)
因为区间重叠,相同的区间可以用很少的向量来描述。绘制这些间隔很明显,4 个向量的列表就足够了
plot(1,1,type="n",xlim=range(unlist(Intervals)),ylim=c(0.9,1.1))
segments(
x0=sapply(Intervals,"[",1),
x1=sapply(Intervals,"[",2),
y0=rep(1,length(Intervals)),
y1=rep(1,length(Intervals)),
lwd=10
)
如何减少我的 Intervals
列表以携带与绘图上显示的信息相同的信息? (性能问题)
上述示例所需的输出是
Intervals = list(
c(5,16)
c(23,35),
c(45,48),
c(55,58)
)
你需要的是IRanges
包中的reduce
函数。
In.df <- do.call(rbind, Intervals)
library(IRanges)
In.ir <- IRanges(In.df[, 1], In.df[,2])
out.ir <- reduce(In.ir)
out.ir
# IRanges of length 4
# start end width
# [1] 5 16 12
# [2] 23 35 13
# [3] 45 48 4
# [4] 55 58 4
基数为R的一个选项:
首先我把你的列表放在 data.frame
:
ints <- as.data.frame(do.call(rbind, Intervals))
names(ints) <- c('start', 'stop')
看起来像
start stop
1 23 34
2 45 48
3 31 35
4 7 16
5 5 9
6 56 57
7 55 58
现在,两个for
循环与between
进行比较,发现交叉时扩大一个区间:
for(x in 1:nrow(ints)){
for(y in 1:nrow(ints)){
if(between(ints$start[x], ints$start[y], ints$stop[y])){
ints$start[x] <- ints$start[y]
if(ints$stop[y] > ints$stop[x]){
ints$stop[x] <- ints$stop[y]
} else {
ints$stop[y] <- ints$stop[x]
}
}
}
}
将 ints
更改为
> ints
start stop
1 23 35
2 45 48
3 23 35
4 5 16
5 5 16
6 55 58
7 55 58
简化为 unique
个案例:
ints <- unique(ints, margin = 1)
并把它们整理好
ints <- ints[order(ints$start),]
还剩下
> ints
start stop
4 5 16
1 23 35
2 45 48
6 55 58
如果你想把它放回原来的列表中,
Intervals <- lapply(1:nrow(ints), function(x)c(ints[x,1], ints[x,2]))
(注意:您当然可以使用 *apply
代替 for
,使用布尔值代替 between
,使用原始列表代替 data.frame
,但是,嗯,这是可读的。Rewrite/optimize随你喜欢。)