Заменить цикл в R

#r

#r

Вопрос:

У меня есть пример кода, который witch находит в векторных z значениях меньше -1.8 и заполняет, 1 пока значения z не становятся больше, чем 0 при заполнении else 0 .

Я использую два цикла, но это очень медленно.

Как я могу сделать это проще и эффективнее?

 z <- c(-1,-1.4,-1.1,-1.8,-2.2,-2.5,-1.7,-1,-0.5,-0.1,0.2,0.4)

q <- NULL
for (i in 1:length(z)) {
  if (z[i] <= -1.8) {
    temp <- 1
  }else temp <- 0
  q <- rbind(q, temp)
}

for (i in 2:length(q)) {
  if (z[i] < 0 amp; q[i-1] == 1) {
    q[i] <- 1
  }
}

q
     [,1]
temp    0
temp    0
temp    0
temp    1
temp    1
temp    1
temp    1
temp    1
temp    1
temp    1
temp    0
temp    0
  

Ответ №1:

Вы можете избежать циклов и сделать это в одной строке, если вы это сделаете:

 cumsum(c(0, diff( (z <= -1.8)) == 1) - c(0, diff( (z > 0) == 1)))
#> [1] 0 0 0 1 1 1 1 1 1 1 0 0
  

Это работает путем нахождения, где z меньше или равно -1.8, и преобразования результирующего логического вектора в 1 или 0. Затем он находит, где это значение изменяется с 0 на 1, используя diff . Аналогично, он находит, где значения пересекаются выше 0, и отмечает это значением -1. Наконец, он получает совокупную сумму этого вектора.

Если вам нужно более полное решение, одним из вариантов tidyverse будет:

 library(dplyr)
library(tidyr)

z <- c(-1, -1.4, -1.1, -1.8, -2.2, -2.5, -1.7, -1, -0.5, -0.1,
       0.2, 0.4, -0.5, -1.2, -2, -0.6, -0.1, 0.5) 
 
tibble(z) %>%
  mutate(z = (z <= -1.8) - (z > 0),
         z = (1   replace(z, z == 0, NA))/2) %>%
  fill(z) %>%
  replace_na(list(z = 0))
#> # A tibble: 18 x 1
#>        z
#>    <dbl>
#>  1     0
#>  2     0
#>  3     0
#>  4     1
#>  5     1
#>  6     1
#>  7     1
#>  8     1
#>  9     1
#> 10     1
#> 11     0
#> 12     0
#> 13     0
#> 14     0
#> 15     1
#> 16     1
#> 17     1
#> 18     0
  

Создан 2020-09-26 пакетом reprex (версия 0.3.0)

Комментарии:

1. стоит отметить, что после того, как я заполнил 1, я должен снова подождать, пока значения не станут меньше -1,8, и снова начать заполнять 1 только с того момента, когда z станет равным -1,8 более сложный пример: z <- c(-1,-1.4,-1.1,-1.8,-2.2,-2.5,-1.7,-1,-0.5,-0.1,0.2,0.4,-0.5,-1.2,-2,-0.6,-0.1,0.5) что должно произойти: 0 0 0 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0

2. @МихаилТабаков see my update. Надеюсь, это будет быстрее