У меня есть такой вектор в R:

dt = data.frame(input=c(0,0,1,1,1,0,1,0,0,0,1,1,1,0,1) )

dt
      input 
 # 1    0     
 # 2    0     
 # 3    1     
 # 4    1     
 # 5    0     
 # 6    0     
 # 7    1     
 # 8    0     
 # 9    0     
 # 10   0  
 # 11   1     
 # 12   1     
 # 13   1     
 # 14   0     
 # 15   1        

Я хочу заменить последовательный 0, в котором длина меньше трех, на 1 и сохранить его в новом столбце.

Например, я хочу вывести:

      input output
 # 1    0     0
 # 2    0     0
 # 3    1     1
 # 4    1     1
 # 5    0     1
 # 6    0     1
 # 7    1     1
 # 8    0     0
 # 9    0     0
 # 10   0     0
 # 11   1     1
 # 12   1     1
 # 13   1     1
 # 14   0     1
 # 15   1     1

Как я могу написать это в цикле foreach? (У меня есть данные с тысячами строк)

Спасибо.

r
2
yi-ting Fang 9 Окт 2021 в 20:29

3 ответа

Лучший ответ

Создайте группирующий столбец с rleid в столбце 'input' и if количество строк меньше 3 и значения all равны 0, замените на 1 или верните ввод

library(dplyr)
library(data.table)
dt %>%
    mutate(new = cumsum(input)) %>%
    group_by(grp = rleid(input)) %>%
    mutate(output = if(n() <3 & all(input == 0) & all(new > 0)) 1 else input) %>%
    ungroup %>%
    select(-grp, -new)

-вывод

# A tibble: 15 × 2
   input output
   <dbl>  <dbl>
 1     0      0
 2     0      0
 3     1      1
 4     1      1
 5     1      1
 6     0      1
 7     1      1
 8     0      0
 9     0      0
10     0      0
11     1      1
12     1      1
13     1      1
14     0      1
15     1      1

Или используйте base R с rle

dt$output <- inverse.rle(within.list(rle(dt$input), 
     values[!values & lengths < 3 & seq_along(values) != 1] <- 1))
dt$output
#[1] 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1
2
akrun 9 Окт 2021 в 17:42

Вот предложение. Но я не понимаю строки 1 и 2 в вашем выводе. «заменить последовательный 0, длина которого меньше трех, на 1», это относится к строкам 1 и 2.

dt %>% 
  mutate(
    x= cumsum(input != lag(input, def = first(input)))
  ) %>% 
  group_by(x) %>% 
  mutate(x = seq_along(input),
         x = last(x)) %>% 
  mutate(output = case_when(input == 0 & x<=2 ~ 1,
                            TRUE ~ as.numeric(input))) %>% 
  ungroup() %>% 
  select(-x)
   input output
   <dbl>  <dbl>
 1     0      1
 2     0      1
 3     1      1
 4     1      1
 5     1      1
 6     0      1
 7     1      1
 8     0      0
 9     0      0
10     0      0
11     1      1
12     1      1
13     1      1
14     0      1
15     1      1
1
TarJae 9 Окт 2021 в 19:03

Поняв требования, как это сделала Тарджа, можно было бы предложить следующий вариант тидиверса.

library(dplyr)

dt %>%
  mutate(x = cumsum(input)) %>%
  group_by(x) %>%
  mutate(y = +(n() %in% 2:3)) %>%
  ungroup() %>%
  transmute(input = input,
            inputX = if_else(y == 1, 1, input))

# # A tibble: 15 x 2
#    input inputX
#    <dbl>  <dbl>
# 1      0      1
# 2      0      1
# 3      1      1
# 4      1      1
# 5      1      1
# 6      0      1
# 7      1      1
# 8      0      0
# 9      0      0
# 10     0      0
# 11     1      1
# 12     1      1
# 13     1      1
# 14     0      1
# 15     1      1
0
rjen 9 Окт 2021 в 19:19