Удалить строку в R на основе условия следующей строки

#r

#r

Вопрос:

У меня следующая проблема:

У меня есть большой фрейм данных, для которого я хотел бы удалить каждую строку, соответствующую этому условию: если значение (строка) внутри столбца содержит символ «:», а следующая строка также содержит символ «:», это приведет к удалению первого.

Что-то вроде этого:

 a <- c("value1","value2","value2:a","value2:b","value3")
b <- c(1,2,3,4,5)
df1 <- data.frame(b,a)

  b        a
1 1   value1
2 2   value2
3 3 value2:a
4 4 value2:b
5 5   value3
  

к этому, где удаляется только строка, содержащая имя «value2: a», поскольку за ней следует строка, содержащая регулярное выражение «:»

 a        b
value1   1
value2   2
value2:b 4
value3   5
  

Заранее большое вам спасибо, я пробовал некоторые решения с циклами for и функцией grepl, но, похоже, это не работает.

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

1. хороший вопрос, но вы намеревались, чтобы a вектор был вектором имен строк или столбцом?

2. только значения внутри столбца, извините!

Ответ №1:

Для этого вам не нужны циклы. Вы можете сделать это с одной строкой в базе R, объединив a grepl с запаздывающим grepl

 df1[!c(head(grepl(":", df1$a), -1) amp; tail(grepl(":", df1$a), -1), FALSE),]
#>   b        a
#> 1 1   value1
#> 2 2   value2
#> 4 4 value2:b
#> 5 5   value3
  

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

1. setDT(df1)[!c(head(grepl(":", a), -1) amp; tail(grepl(":", a), -1), FALSE)] это data.table решение. (OP говорит, что его данные большие)

Ответ №2:

Вот dplyr решение.

 library(dplyr)

df1 %>%
  mutate(flag = grepl(":", a),
         flag = cumsum(flag)*flag,
         flag = lead(flag, default = 0)) %>%
  filter(flag != 2) %>%
  dplyr::select(-flag)
#  b        a
#1 1   value1
#2 2   value2
#3 4 value2:b
#4 5   value3
  

Ответ №3:

Попробуйте это:

 df1 %>% 
    dplyr::filter(
        !(stringr::str_detect(a, ":") amp; stringr::str_detect(lead(a), ":"))
    )
  

Ответ №4:

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

 a <- c("value1","value2","value2:a","value2:b","value3")
b <- c(1,2,3,4,5)
df1 <- as.data.frame(b,a)
stringr::str_extract(pattern = ":",string = rownames(df1)) -> vec
mask_colon = duplicated(vec,fromLast = FALSE)
mask_na = is.na(vec)
df1 = df1[which(mask_na | mask_colon),, drop = FALSE]
df1
#>          b
#> value1   1
#> value2   2
#> value2:b 4
#> value3   5
  

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