помогите с командой rle - PullRequest
2 голосов
/ 16 мая 2011

У меня возникли проблемы с командой rle, которая предназначена для определения точки, в которой участники достигают 8 смежных подряд.

Например, если:

x <- c(0,1,0,1,1,1,1,1,1,1,1,1)

я хочу вернуть значение 11.

Благодаря DWin я использовал этот кусок кода:

which( rle(x2)$values==1 & rle(x2)$lengths >= 8)
sum(rle(x)$lengths[ 1:(min(which(rle(x)$lengths >= 8))-1) ]) + 8

Я успешно использовал этот код для обработки моих данных. Тем не менее, я заметил, что он допустил ошибку при обработке одного из моих файлов данных.

Например, если

 x <- c(1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)

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

Заранее благодарим за помощь.

Будет

Ответы [ 3 ]

10 голосов
/ 16 мая 2011

Вам нужно вставить первую строку кода целиком во вторую:

sum(rle(x)$lengths[ 1:(min(which( rle(x2)$values==1 & rle(x2)$lengths >= 8))-1) ]) + 8
[1] 39

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

which(filter(x2, rep(1/8, 8), sides=1) == 1)[1]
[1] 39

Функция filter, используемая таким образом, по существу вычисляет скользящее среднее по блоку из 8 значений в векторе.Затем я возвращаю позицию первого значения, где скользящая средняя равна 1.

8 голосов
/ 16 мая 2011

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

lengthOfrepeatsOfAnything<-rle(x)$lengths
#4  2  5 11  2  2  3  2 17
whichRepeatsAreOfOnes<-rle(x)$values==1
#1 3 5 7 9
repeatsOfOnesLength<-lengthOfrepeatsOfAnything * whichRepeatsAreOfOnes #TRUE = 1, FALSE=0
#4  0  5  0  2  0  3  0 17
whichRepeatOfOneAreLongerThanEight<-which(repeatsOfOnesLength >= 8)
#9
result<-NA
if(length(whichRepeatOfOneAreLongerThanEight)>0){
    firstRepeatOfOneAreLongerThanEight<-whichRepeatOfOneAreLongerThanEight[1]
    #9
    if(firstRepeatOfOneAreLongerThanEight==1){
        result<-8
    }
    else{
        repeatsBeforeFirstEightOnes<-1:(firstRepeatOfOneAreLongerThanEight-1)
        #1 2 3 4 5 6 7 8
        lengthsOfRepeatsBeforeFirstEightOnes<-lengthOfrepeatsOfAnything[repeatsBeforeFirstEightOnes]
        #4  2  5 11  2  2  3  2
        result<-sum(lengthsOfRepeatsBeforeFirstEightOnes) + 8
    }
}

Я знаю, что это выглядит не так красиво, как решение oneline, но оно помогает прояснить ситуацию и выявить ошибки ... Кроме того: что если вы оглянетесь на этот код через 4 месяца? Какой из них будет легче понять снова?

1 голос
/ 17 мая 2011

Мой совет - разбить код на более простые части. Как предлагает @Nick, вы хотите написать код, который можно легко отлаживать, а модульное кодирование позволяет вам это делать.

# find runs of 0s and 1s
run_01 = rle(x)

# find run of 1's with length >=8
run_1 = with(run_01, which(values == 1 & lengths >=8))

# find starting position of run_1
start_pos = sum(run_01$lengths[1:(run_1 - 1)])

# add 8 to it
end_pos  = start_pos + 8
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...