Как эффективно свернуть вектор целых чисел в таблицу данных последовательностей, используя R? - PullRequest
1 голос
/ 09 ноября 2019

Учитывая большой вектор. Например:

set.seed(1)
in_vec <- sample(1:10000, 5000, replace = F)

Как я могу эффективно свернуть это в таблицу данных, которая обеспечивает начальную и конечную координаты для всех последовательных целых чисел. В настоящее время я использую следующий код:

in_vec <- sort(in_vec) # sort by sequence
library(data.table)
interval_id <- findInterval(in_vec, in_vec[which(c(1, diff(in_vec)) > 1)]) # add unique IDs for sequences
dt <- data.table(vec = in_vec, # make data.table
             int_id = interval_id)
long_to_short <- function(sub){ data.table(start = sub$vec[1], end = sub$vec[nrow(sub)]) } # custom function
library(plyr)
output <- ddply(dt, "int_id", long_to_short)
output$int_id <- NULL

Однако вектор, к которому я применяю это, очень велик, и поэтому мне необходимо максимизировать производительность. Есть ли метод data.table? Любая помощь будет принята с благодарностью!

Ответы [ 3 ]

3 голосов
/ 09 ноября 2019

Использование rleid() из полезно:

library(data.table)

set.seed(1)
dt <- data.table(in_vec = sample(1:10000, 5000, replace = F)) 

dt[order(in_vec), 
   .(start = min(in_vec),
     end = max(in_vec)),
   by = .(grp = rleid(c(0, cumsum(diff(in_vec) > 1))))
   ]

       grp start  end
   1:    1     4    4
   2:    2     6    7
   3:    3    14   16
   4:    4    19   19
   5:    5    26   27
  ---                
2483: 2483  9980 9980
2484: 2484  9988 9988
2485: 2485  9991 9992
2486: 2486  9994 9994
2487: 2487  9997 9998

Для полностью базового решения это должно быть наиболее эффективным, поскольку это не операция группировки:

set.seed(1)
in_vec <- sample(1:10000, 5000, replace = F)
in_vec <- sort(in_vec)

grp <- c(0, cumsum(diff(in_vec) > 1))

data.frame(grp = unique(grp),
           start = in_vec[!duplicated(grp)],
           end = in_vec[!duplicated(grp, fromLast = T)]
)
1 голос
/ 09 ноября 2019

Вы почти у цели, просто нужно использовать разницу между отсортированными векторами для создания группы. Затем разберитесь с ними.

set.seed(1)
in_vec <- sample(1:10000, 5000, replace = F)
in_vec <- sort(in_vec)
grps <- cumsum(c(1,diff(in_vec)>1))

output <- data.frame(do.call(rbind,tapply(in_vec,grps,range)))
names(output) <- c("start","end")

И решение dplyr

set.seed(1)
in_vec <- sample(1:10000, 5000, replace = F)
data.frame(x=in_vec) %>% 
arrange(x) %>%
mutate(grps=cumsum(c(1,diff(x)>1))) %>%
group_by(grps) %>%
summarise(start=min(x),end=max(x)) %>%
select(start,end)
1 голос
/ 09 ноября 2019

Как-то так?

dt[, .(start = first(vec), end = last(vec)), int_id]

Редактировать: Я думаю, что следующее будет делать то, что вам нужно в data.table, настройте fill = -1 в зависимости от фактического диапазона ваших значений.

set.seed(1)
in_vec <- sample(1:10000, 5000, replace = F)
dt <- data.table(vec = in_vec, key = 'vec')
dt[, int_id := cumsum(!shift(vec, 1, fill = -1) == vec - 1)]
dt[,.(start = first(vec), end = last(vec)), int_id]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...