【问题标题】:Efficiently creating a column containing a sequence of values concatenated from rows in a different column有效地创建包含从不同列中的行连接的一系列值的列
【发布时间】:2020-07-17 04:25:30
【问题描述】:

我想为给定位置上方和下方的行创建一个新列,其中包含在不同列中给出的一系列值。让我们通过一个例子来更好地解决这个问题。

我的数据框如下所示:

library("tidyverse")

df <- tibble(POS = c("A","C","G","G","C","C","C","A","A","G","T","C","A"),
             GET = c(FALSE,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,FALSE))

# A tibble: 13 x 2
   POS   GET  
   <chr> <lgl>
 1 A     FALSE
 2 C     FALSE
 3 G     FALSE
 4 G     FALSE
 5 C     TRUE 
 6 C     FALSE
 7 C     FALSE
 8 A     FALSE
 9 A     FALSE
10 G     FALSE
11 T     FALSE
12 C     TRUE 
13 A     FALSE

给定行号i 和窗口大小,我想连接POS 中的值以生成序列SEQ。例如,如果窗口扩展为 2(因为它在上方延伸两行,下方延伸两行),则第一次观察的 SEQ 值将只是“ACG”,但对于第三次观察,它将是“ACGGCC”。

但是,我只想做一些观察,那些带有GET==TRUE 的观察,所以理想的输出应该如下所示:

# A tibble: 2 x 3
  POS   GET   SEQ  
  <chr> <lgl> <chr>
1 C     TRUE  GGCCC
2 C     TRUE  GTCA 

无论如何,所有行的SEQ 值的解决方案也是有效的,我正在寻找的实际上不是问题本身的解决方案,而是一个有效的解决方案(见下文)。

我是怎么做的

这是我编写的代码:

window_extension <- 2
size <- window_extension * 2 + 1

for (i in 1:size) {
  if (i <= window_extension) {
     df <- df %>% dplyr::mutate(!!paste("SEQ", i, sep="") := dplyr::lag(POS, window_extension + 1 - i))
  } else if (i > window_extension + 1) {
    df <- df %>% dplyr::mutate(!!paste("SEQ", i, sep="") := dplyr::lead(POS, window_extension - (size-i)))
  } else {
    df <- df %>% dplyr::mutate(!!paste("SEQ", i, sep="") := POS)
  }
}

df %>% tidyr::unite("SEQ", tidyselect::starts_with("S"), sep="", remove = TRUE, na.rm=TRUE) %>% dplyr::filter(GET)

此解决方案的问题在于,它会生成一个中间数据帧(循环之后的df),其中包含size 变量所指示的列数。所以你可以想象,如果size很大,内存的负担就会变大。这本身就是一个问题,特别是当只有几行是真正感兴趣的时候。浪费了太多内存。

希望会有一些专门的功能来实现这一点。我希望用 dplyr 滞后和领先来解决问题,但没有运气。有什么想法吗?

【问题讨论】:

  • 嗨 elcortegano,这个示例 tibble 看起来很像 DNA 序列。也许您可以提供有关该问题的更多信息,因为您的问题之前可能已经解决。也许您有一个基因组位置列表,并且您想提取该位置周围不同大小的序列?
  • 这实际上是一个 DNA 序列。目标是检索围绕某些感兴趣位置的序列。因此,如果窗口扩展如上所述为 2 bp,我们将获得 5 bp 区域,以该感兴趣位置为中心。
  • 您如何确定GET 是否只是基因组位置?您是否使用参考基因​​组? BAM 文件?
  • 在我看来,问题中列出的方法不是最理想的。 bedtools 或使用 GenomicRanges 包会好得多。
  • 祝你好运。如果您需要更多帮助,您也可以考虑在bioinformatics.stackexchange.com 上提问。

标签: r tidyverse


【解决方案1】:
library(tidyverse)


df <- tibble(POS = c("A","C","G","G","C","C","C","A","A","G","T","C","A"),
             GET = c(FALSE,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,FALSE))


df$SEQ <- slider::slide(df$POS, ~.x, .before = 2, .after = 2) %>% sapply(paste, collapse = "")

df %>%
  filter(GET)

【讨论】:

  • 不知道slider,但看起来确实很棒,而且工作方式更简单,谢谢!
【解决方案2】:

也许这个解决方案有帮助,你必须设置k

#Define k
k <- 2
#Create index
index <- which(df$GET==T)
index2 <- 1:length(index)
index3 <- index-k
index4 <- index+k
#Replace
index3 <- ifelse(index3>dim(df)[1],dim(df)[1],index3)
index4 <- ifelse(index4>dim(df)[1],dim(df)[1],index4)
#Assign
df$i <- NA
#Loop
for(i in index2)
{
  df$i[index[i]] <- paste0(df$POS[index3[i]:index4[i]],collapse = '')
}
#Now filter
df2 <- df[!is.na(df$i),]
df2

# A tibble: 2 x 3
  POS   GET   i    
  <chr> <lgl> <chr>
1 C     TRUE  GGCCC
2 C     TRUE  GTCA 

【讨论】:

  • 嗯,这当然看起来更加高效和简单,谢谢你发布这个!!对于这个特定问题(与 DNA 序列有关),基因组程序 bedtools 会更好地工作,正如上面 Ian Campbell 所评论的那样,但希望这对在不同情况下有类似问题的其他用户有用!
  • @elcortegano 太棒了!我希望它能以任何方式提供帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-08
  • 2011-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多