将数据帧中的范围集转换为单个元素的频率的有效方法?

Man*_*oel 15 r dataframe

我在R.工作.我有一个数据框,其中包含染色体上的起始位置和结束位置(其中整数表示染色体上的坐标)例如:

start     end
1         5
3         7
4         10
12        7            (inverted is also allowed)
8         15
Run Code Online (Sandbox Code Playgroud)

我想要的是计算所有这些范围内坐标的出现次数.因此,对于上面的示例,输出将是这样的:

position     count
1            1
2            1
3            2
4            3
5            3
6            2
7            3
8            3
9            3
10           3
11           2
12           2
13           1
14           1
15           1
Run Code Online (Sandbox Code Playgroud)

我有62000多个这样的范围,每个范围至少有1000个位置.我知道如何进行这种转换,但我不知道如何有效地做到这一点,即几秒钟.

当前(效率低下的代码)

positions <- c()
for(i in seq(nrow(a))){
  positions <- c(positions, seq(a[i,3], a[i,4]))
}
table(positions)
Run Code Online (Sandbox Code Playgroud)

"a"是我的数据框,开始和结束坐标分别在第三和第四列.

数据框中的一列包含字符,因此对于使用apply我要么需要创建一个新的数据框(消耗额外的空间),要么需要在apply函数内转换为整数(额外的时间).对不起,因为之前没有告知此事.

jog*_*ogo 9

对于一个非常快速的代码,data.table请参阅docendo discimus
(+ benchmark)的答案

以下是其他一些解决方案的基准:

set.seed(42)
N <- 1000
df <- data.frame(start=sample.int(10*N, N))
df$end <- df$start + sample(3:20, N, rep=TRUE) 

library("microbenchmark")
microbenchmark(unit = "relative",
ori =  { positions <- c()
  for(i in seq(nrow(df))){
    positions <- c(positions, seq(df[i,1], df[i,2]))
  }
  table(positions) },
a  = table(unlist(apply(df, 1, function(x) x[1]:x[2]))),  # my solution, similar: KenS, EricSchutte
m1 = table(unlist(mapply(seq, df$start, df$end))),        # my variant of Sotos' solution
m2 = table(unlist(mapply(':', df$start, df$end))),        # my variant of Sotos' solution
M1 = table(unlist(Map(seq, df$start, df$end))),           # my variant of Sotos' solution
M2 = table(unlist(Map(':', df$start, df$end))),           # Sotos
l  = table(unlist(lapply(seq_len(nrow(df)), function(i) seq(df$start[i], df$end[i])))),    # lmo
t  = { temp <- unlist(lapply(seq_len(nrow(df)), function(i) seq(df$start[i], df$end[i])))  # lmo tabulate()
cbind(sort(unique(temp)), tabulate(temp)) },
d  = table(do.call(c, mapply(seq, df$start, df$end))),     # @989 (comment to the answer from Sotos)
dd = table(do.call(c, mapply(seq.int, df$start, df$end))), # docendo discimus (comment to this answer)
f  = {  pos <- data.frame(x=(min(df):max(df)),n=0)         # Andrew Gustar

for(i in seq_along(df$start)){
  low=min(df$start[i])-pos$x[1]+1
  high=max(df$end[i])-pos$x[1]+1
  pos$n[low:high] <- pos$n[low:high]+1
} }
)
# Unit: relative
# expr      min       lq     mean   median       uq       max neval    cld
#  ori 7.163767 7.219099 7.573688 7.379160 7.912435  7.899586   100     e 
#    a 1.194627 1.194855 1.211432 1.209485 1.213118  1.711994   100 a     
#   m1 1.645659 1.660294 1.711141 1.686973 1.710461  2.217141   100  b    
#   m2 1.005302 1.007125 1.017115 1.009618 1.017207  1.576201   100 a     
#   M1 1.642688 1.645174 1.733173 1.673924 1.686253  2.218028   100  b    
#   M2 1.000000 1.000000 1.000000 1.000000 1.000000  1.000000   100 a     
#    l 3.487924 3.512732 3.801530 3.665725 4.188701  4.216375   100    d  
#    t 2.670636 2.711345 2.961449 2.869190 3.066150  3.745984   100   c   
#    d 1.652376 1.650798 1.721377 1.665901 1.712064  2.187129   100  b    
#   dd 1.040941 1.045652 1.060601 1.047534 1.053305  1.592163   100 a     
#    f 8.287098 8.486854 9.052884 9.046376 9.126318 25.210722   100      f
Run Code Online (Sandbox Code Playgroud)

解决方案tabulate()产生警告.


Sot*_*tos 7

一个想法,

as.data.frame(table(unlist(Map(`:`, df$start, df$end))))

#   Var1 Freq
#1     1    1
#2     2    1
#3     3    2
#4     4    3
#5     5    3
#6     6    2
#7     7    3
#8     8    3
#9     9    3
#10   10    3
#11   11    2
#12   12    2
#13   13    1
#14   14    1
#15   15    1
Run Code Online (Sandbox Code Playgroud)