R优化双循环,矩阵操作

alk*_*lki 3 r matrix dataframe

我试图在两列矩阵中操纵列数据并将其作为data.frame输出.

我所拥有的矩阵采用这种格式,其中起始列和结束列中的值都在增加且不重叠.此外,始终条目总是比结束条目多.

假设我从这个矩阵开始:

#       Start   End
#  [1,]     1     6
#  [2,]     2     9
#  [3,]     3    15
#  [4,]     7    NA
#  [5,]     8    NA
#  [6,]    11    NA
#  [7,]    12    NA
#  [8,]    14    NA
Run Code Online (Sandbox Code Playgroud)

我希望这个double for循环输出一个data.frame,它将所有Start值分组为小于End值并将其与该End值相关联.

为了澄清我想输出这个:

#       Start   End
#  1    1,2,3     6
#  2      7,8     9
#  3 11,12,14    15
Run Code Online (Sandbox Code Playgroud)

我尝试了一个双循环,但我需要更快的东西,因为我想在更大的矩阵~5 MB上使用此方法.

start_end <- matrix(c(1, 6, 2, 9, 3, 15, 7, NA, 8, NA, 11, NA, 12, NA, 14, NA), 
  nrow=8, 
  ncol=2)

# of non NA rows in column 2
non_nacol <- sum(is.na(start_end[,2]))

sorted.output <- data.frame(matrix(NA, nrow = nrow(start_end), ncol = 0))
sorted.output$start <- 0
sorted.output$end <- 0

#Sort and populate data frame
for (k in 1:non_nacol) {
  for (j in 1:nrow(start_end)) {
        if (start_end[j,1]<start_end[k,2]) {
        S <- (start_end[j,1])
        E <- (start_end[k,2])
        sorted.output$start[j] <- S
        sorted.output$end[j] <- E
        }
  }
}
Run Code Online (Sandbox Code Playgroud)

谢谢您的帮助!

bgo*_*dst 5

这里有一个解决方案围绕建成findInterval(),split()以及paste():

m <- matrix(c(1,2,3,7,8,11,12,14,6,9,15,NA,NA,NA,NA,NA),ncol=2,dimnames=list(NULL,c('Start','End')));
data.frame(Start=sapply(split(m[,'Start'],findInterval(m[,'Start'],na.omit(m[,'End']))),paste,collapse=','),End=na.omit(m[,'End']));
##      Start End
## 0    1,2,3   6
## 1      7,8   9
## 2 11,12,14  15
Run Code Online (Sandbox Code Playgroud)

编辑:您遇到的问题是由于在您的实际数据中输入End值之间的某些间隔不包含任何输入Start值.我上面的解决方案错误地从输出Start向量中省略了那些间隔,这导致与输出向量的长度不匹配End.

这是一个固定的解决方案:

end <- na.omit(m[,'End']);
data.frame(Start=unname(sapply(split(m[,'Start'],findInterval(m[,'Start'],end))[as.character(0:c(length(end)-1))],paste,collapse=',')),End=end);
##      Start End
## 1    1,2,3   6
## 2      7,8   9
## 3 11,12,14  15
Run Code Online (Sandbox Code Playgroud)

这是一个空间隔的测试矩阵的演示:

m <- matrix(c(1,2,3,11,12,14,6,9,15,NA,NA,NA),ncol=2,dimnames=list(NULL,c('Start','End')));
m;
##      Start End
## [1,]     1   6
## [2,]     2   9
## [3,]     3  15
## [4,]    11  NA
## [5,]    12  NA
## [6,]    14  NA
end <- na.omit(m[,'End']);
data.frame(Start=unname(sapply(split(m[,'Start'],findInterval(m[,'Start'],end))[as.character(0:c(length(end)-1))],paste,collapse=',')),End=end);
##      Start End
## 1    1,2,3   6
## 2            9
## 3 11,12,14  15
Run Code Online (Sandbox Code Playgroud)

如您所见,对于空间隔,导致输出Start向量的值是空字符串,我认为这是一个明智的结果.如果需要,您可以在以后更改结果.

最后,这是使用您发布到Dropbox的真实数据的演示:

m <- read.table('start_end.txt',col.names=c('Start','End'));
head(m);
##   Start   End
## 1 11165 10548
## 2 12416 11799
## 3 12466 11900
## 4 12691 11976
## 5 12834 13336
## 6 13320 14028
end <- na.omit(m[,'End']);
system.time({ out <- data.frame(Start=unname(sapply(split(m[,'Start'],findInterval(m[,'Start'],end))[as.character(0:c(length(end)-1))],paste,collapse=',')),End=end); });
##    user  system elapsed
##  21.234   0.015  21.251
head(out);
##                           Start   End
## 1                               10548
## 2                         11165 11799
## 3                               11900
## 4                               11976
## 5 12416,12466,12691,12834,13320 13336
## 6       13425,13571,13703,13920 14028
nrow(out);
## [1] 131668
Run Code Online (Sandbox Code Playgroud)