在R

我有一个看起来像这样的数据框:

snP1 01010101000000100000010010001010011001010101
snP2 01010010101000100000000000000001100001001000
snP3 01010101000000000000000000000100011111111111

...但是实际上它包含约800万行,每个二进制矢量的长度均为1000。

我需要在这些二进制向量中(跨所有行)选择特定位置。我发现这样做的肮脏方法是删除行名,将每个数字转换为一列,然后创建一个包含我感兴趣的位置的对象。

下面的示例数据可以很好地工作,但是对于我的真实数据却不是很有效(现在已经运行了很长时间)。有什么想法可以使它更快吗?

library(data.table)
library(stringr)
setwd("test/")
DATADIR="datadir/"
OUTPUTDIR="outputdir/"
dir.create(OUTPUTDIR,showWarnings = FALSE)

baseline<-read.table(paste0(DATADIR,"input.file"),colClasses = "character")
  # Pass BP name to row name (so that I can split the binary vector into multiple columns)
  row.names(baseline) <- baseline$V1
  baseline$V1 <- NULL

  # split cells containing the binary vectors into multiple columns - thank you @Onyambu for this!
  baseline_new <-  read.table(text = gsub('(.)','\\1 ',baseline$V2),fill=TRUE)

  # select columns of interest
  columns_to_keep <- c(1,4,8,10)
  baseline_new_ss <- baseline_new[,columns_to_keep]

  # create new object containing a column with the original row names,then recreate binary vector based on subsetted binary positions. 
  baseline_final <- as.data.frame(row.names(baseline))
  baseline_final$V2 <- as.character(interaction(baseline_new_ss,sep=""))

输出(仅选择位置1、4、8和10)应如下所示:

snP1 0110
snP2 0100
snP3 0110

我敢肯定,这样做的方法比较简单。

谢谢!

fc1138728 回答:在R

您可以尝试以下方法:

at <- function(binary_strings,positions)
{
  charvec <- character(length(binary_strings))
  for(i in seq_along(positions))
  {
    charvec <- paste0(charvec,substr(binary_strings,positions[i],positions[i]))
  }
  return(charvec)
}

现在您可以做

at(baseline$`whatever your binary column is called`,c(1,4,8,10))
#> [1] "0110" "0100" "0110"

因此,您可以使用管道

library(magrittr)

baseline$`whatever your binary column is called` %<>% at(c(1,10))

print(baseline)
#>      whatever your binary column is called
#> SNP1                                  0110
#> SNP2                                  0100
#> SNP3                                  0110

我已经使用相当慢的Windows PC在800万行上以7秒为基准对此进行了基准测试。

,

您可以使用strsplit,并选择元素mapplypaste一起返回到数据框中。虽然不知道这有多快,但是很简洁:)

`rownames<-`(data.frame(values=
                          mapply(function(x) Reduce(paste0,x[c(1,10)]),sapply(dat$V2,strsplit,""))),dat$V1)
#      values
# SNP1   0110
# SNP2   0100
# SNP3   0110

也许有一种data.table解决方案无法在内部创建副本-> fast


数据:

"SNP1 01010101000000100000010010001010011001010101
SNP2 01010010101000100000000000000001100001001000
SNP3 01010101000000000000000000000100011111111111"->tx
dat <- data.table::fread(text=tx,header=F)
,

另一种选择是使用stringi

计时代码:

nr <- 1e6
nc <- 1e3
l <- rep(paste(rep(1L,nc),collapse=""),nr)
writeLines(l,"test.txt")

cols <- c(1,10)

library(stringi)
library(iotools)    
microbenchmark::microbenchmark(times=1L,stringi=lapply(cols,function(n) stri_sub(l,n,n)),iotools=input.file("test.txt",formatter=dstrfw,col_types=rep("character",widths=rep(1L,nc))[,cols]
)

时间:

Unit: seconds
    expr       min        lq      mean    median        uq       max neval
 stringi  1.329223  1.329223  1.329223  1.329223  1.329223  1.329223     1
 iotools 76.250773 76.250773 76.250773 76.250773 76.250773 76.250773     1
本文链接:https://www.f2er.com/2796390.html

大家都在问