Выбор позиций в двоичном векторе (как я могу закрепиться?) В R - PullRequest
1 голос
/ 09 января 2020

У меня есть кадр данных, который выглядит следующим образом:

SNP1 01010101000000100000010010001010011001010101
SNP2 01010010101000100000000000000001100001001000
SNP3 01010101000000000000000000000100011111111111

... но в действительности он содержит ~ 8 миллионов строк, и каждый двоичный вектор имеет длину 1000 каждый.

Мне нужно выбрать определенные c позиции в этих двоичных векторах (по всем строкам). Грязный способ сделать это - удалить имена строк, преобразовать каждый ди git в столбец, а затем создать объект, содержащий интересующие меня позиции.

С примерами данных хорошо работает следующее: но это не очень эффективно с моими реальными данными (это работает в течение длительного времени). Любые идеи, как я могу сделать это быстрее?

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

Я уверен, что есть меньше запутанный способ сделать это.

Спасибо !!

Ответы [ 3 ]

1 голос
/ 09 января 2020

Вы можете использовать strsplit, выделять элементы с помощью mapply и paste вместе во фрейме данных. Не знаю, насколько это быстро, но оно сжато:)

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

Может быть, есть решение data.table, которое не делает копии внутри -> быстро .


Данные:

"SNP1 01010101000000100000010010001010011001010101
SNP2 01010010101000100000000000000001100001001000
SNP3 01010101000000000000000000000100011111111111"->tx
dat <- data.table::fread(text=tx, header=F)
1 голос
/ 10 января 2020

Другой вариант - использовать stringi:

временной код:

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

cols <- c(1,4,8,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", nc), 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
1 голос
/ 09 января 2020

Вы можете попробовать это:

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, 4, 8, 10))

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

Я сделал бенчмарк это в 7 секунд на 8 миллионах строк, используя довольно медленный Windows P C.

...