2013-08-01 5 views
0

Есть ли простой способ получить максимальное количество последовательных 1 в строке, например: "000010011100011111001111111100"?найти максимальное количество последовательных 1 в строке?

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

Спасибо за вашу помощь заранее.

+0

Что вы пробовали (и другие вопросы из [переполнения стеки вопросов контрольного списка] (http://meta.stackexchange.com/questions/156810/stack-overflow-question-checklist))? –

+0

Я только пробовал использовать циклы. У меня есть две петли в качестве счетчика числа строк, который начинается с первой строки набора данных и доходит до конца. Другой цикл как счетчик числа последовательных 1. Но это очень неэффективно и занимает много времени. – Sam

+0

@ Томас, вы правы. Я искал, но ничего не нашел. Я должен был использовать лучшие ключевые слова для поиска. – Sam

ответ

4

Использование rle:

x <- "000010011100011111001111111100" 
rr <- rle(strsplit(x,"")[[1]]) 

Run Length Encoding 
    lengths: int [1:9] 4 1 2 3 3 5 2 8 2 
    values : chr [1:9] "0" "1" "0" "1" "0" "1" "0" "1" "0" 

Примечание: я удалил as.numeric часть, как это не нужно. Отсюда вы можете получить максимальное количество последовательных 1 с:

max(rr$lengths[which(rr$values == "1")]) 
# [1] 8 
+0

Спасибо @Thomas. Это решило мою проблему. – Sam

+0

@Arun - Я думаю, что это должен быть отдельный ответ, а не редактирование. Если вы это сделаете, я, вероятно, смогу удалить мою. – thelatemail

+0

@thelatemail, Да, я понимаю это сейчас. размещены отдельно. Благодарю. (Томас, извините за беспорядок). – Arun

7

Использование rle медленнее и немного более неуклюжим, чем с помощью регулярных выражений. В Thomas' answer, вы все еще остались, чтобы извлечь максимальную длину, когда значения равны 1.

# make some data 
set.seed(21) 
N <- 1e5 
s <- sample(c("0","1"), N*30, TRUE) 
s <- split(s, rep(1:N, each=30)) 
s <- sapply(s, paste, collapse="") 
# Thomas' (complete) answer 
r <- function(S) { 
    sapply(S, function(x) { 
    rl <- rle(as.numeric(strsplit(x,"")[[1]])) 
    max(rl$lengths[rl$values==1]) 
    }) 
} 
# using regular expressions 
g <- function(S) sapply(gregexpr("1*",S), 
    function(x) max(attr(x,'match.length'))) 
# timing 
system.time(R <- r(s)) 
# user system elapsed 
# 6.41 0.00 6.41 
system.time(G <- g(s)) 
# user system elapsed 
# 1.47 0.00 1.46 
all.equal(R,G) 
# [1] "names for target but not for current" 
+0

Спасибо @Joshua за ваш полезный ответ. – Sam

6

Альтернативы гораздо быстрее путем без использования rle бы разделить с последовательным 0 'следующим образом:

# following thelatemail's comment, changed '0+' to '[^1]+' 
strsplit(x, "[^1]+", perl=TRUE) 

Затем вы можете запрограммировать и получить максимальные символы для каждого элемента вашего списка. Это будет быстрее, чем rle решение. и также быстрее, чем решение gregexpr от @Joshua. Некоторые бенчмаркинг ...

zz <- function(x) { 
    vapply(strsplit(x, "[^1]+", perl=TRUE), function(x) max(nchar(x)), 0L) 
} 

Я просто понял, что @ функции Джошуа также может быть изменен путем добавления perl=TRUE и использования vapply. Итак, я сравню это.

g2 <- function(S) vapply(gregexpr("1*",S, perl=TRUE), 
    function(x) max(attr(x,'match.length')), 0L) 

require(microbenchmark) 
microbenchmark(t1 <- zz(unname(s)), t2 <- g(unname(s)), t3 <- g2(unname(s)), times=50) 
Unit: seconds 
       expr  min  lq median  uq  max neval 
t1 <- zz(unname(s)) 1.187197 1.285065 1.344371 1.497564 1.565481 50 
    t2 <- g(unname(s)) 2.154038 2.307953 2.357789 2.417259 2.596787 50 
t3 <- g2(unname(s)) 1.562661 1.854143 1.914597 1.954795 2.203543 50 

identical(t1, t2) # [1] TRUE 
identical(t1, t3) # [1] TRUE 
+0

Ницца. Для обобщения в случае, когда есть символы, отличные от '0' или' 1', следует заменить '" 0+ "' на '' [^ 1] "' в вызове 'strsplit'. * Маргинально * медленнее, но, вероятно, безопаснее. – thelatemail

+0

Да, вы правы. Но я не думаю, что это повлияет на производительность. – Arun

+0

примерно на 50% медленнее в моем тестировании. От 0,5 до 0,75 с. – thelatemail

Смежные вопросы