Фильтровать строки в цепочке dplyr, если набор строк не содержит определенного слова - PullRequest
2 голосов
/ 12 апреля 2019

Допустим, у меня есть следующий набор данных:

df <- read.table(header=TRUE, text="name value
stranger_things_mc Stranger_Land
stranger_things_confidence 100
stranger_things_importance 1
stranger_things_answer Stranger_Things
immigrant_crime_number 140
immigrant_crime_confidence 100
immigrant_crime_importance 3
immigrant_crime_answer 50
dog_things_mc Stranger_Land
dog_things_confidence 100
dog_things_importance 1
dog_things_answer Stranger_Things
fighting_stats_number 140
fighting_stats_confidence 100
fighting_stats_answer 50")

Каждая четвертая строка должна содержать три суффикса (_confidence, _importance, _answer), хотя иногда это не так (как с "ighting_stats "выше).Строка иногда имеет суффикс (_mc), а иногда она говорит (_number или _slider).

Я хочу отфильтровать любую строку, которая содержит (_number или _slider) КАК ХОРОШО, как три строки, связанные с этим столбцом _number или _slider.Итак, в приведенном выше примере результирующий вывод будет:

df <- read.table(header=TRUE, text="name value
stranger_things_mc Stranger_Land
stranger_things_confidence 100
stranger_things_importance 1
stranger_things_answer Stranger_Things
dog_things_mc Stranger_Land
dog_things_confidence 100
dog_things_importance 1
dog_things_answer Stranger_Things")

Я могу отфильтровать определенные столбцы следующим образом:

final_results <- df %>% 
  filter(!str_detect(name, "_number") & !str_detect(name, "_slider"))

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

Сначала найдите строку с «_number» или «_slider» в столбце имени и возьмите текст, который стоит перед ним.В вышеприведенном примере это будут "ighting_stats "и" immigrant_crime ".Затем удалите любую строку с этим текстом.

Ответы [ 2 ]

2 голосов
/ 12 апреля 2019

Мы создаем столбец группировки на основе условия, что каждая четвертая строка является новым блоком (gl), затем filter из групп, в которых элемент first для name не является _number или _slider, затем ungroup и удалите временный столбец 'grp', созданный

library(dplyr)
df %>% 
    group_by(grp = as.integer(gl(n(), 4, n()))) %>% 
    filter(!str_detect(first(name), "_(number|slider)")) %>%
    ungroup %>%
    select(-grp)

Обновление

На основе комментариев из OP, то есть блоки определяются по их общему префиксу, затем извлекают первый word, используют его в качестве переменной группировки и делают filter, как и раньше

library(stringr)
df %>%
  group_by(grp = word(name, 1, sep="_")) %>% 
  filter(!str_detect(first(name), "_(number|slider)"))

и часть ungroup остается такой же, как и предыдущая

Если существуют повторяющиеся префиксы, то есть несмежные префиксы и должны рассматриваться как отдельные блоки, то используйте rleid из data.table для создания переменной группировки

df %>%
  group_by(grp = rleid(word(name, 1, sep="_"))) %>%
  filter(!str_detect(first(name), "_(number|slider)"))
1 голос
/ 12 апреля 2019

Вот как бы я занялся этим:

groups <- df %>% 
  mutate(grp = str_extract(name, '.*(?=_confidence|_importance|_answer|_mc|_number|_slider)'),
         sfx = str_extract(name, '(_confidence|_importance|_answer|_mc|_number|_slider)')) %>% 
  group_by(grp) %>% 
  summarize(confidence = '_confidence' %in% sfx,
            importance = '_importance' %in% sfx,
            answer = '_answer' %in% sfx,
            mc = '_mc' %in% sfx,
            number = '_number' %in% sfx,
            slider = '_slider' %in% sfx) %>% 
  ungroup() %>% 
  gather(sfx, contains, -grp) %>% 
  filter(contains == TRUE) %>% 
  select(-contains)


df %>% 
  mutate(grp = str_extract(name, '.*(?=_confidence|_importance|_answer|_mc|_number|_slider)')) %>% 
  anti_join(groups %>% 
               filter(sfx == 'number') %>%
               select(grp))

На высоком уровне я создаю промежуточный кадр данных, который содержит основание и суффикс строки name, и использую основание для созданиягруппу, и определение того, какой из заданного вами списка суффиксов включен в каждую группу основ.Затем вместо filter в исходном фрейме данных мы используем filter в промежуточном фрейме данных, а затем anti_join в исходном фрейме данных.

Давайте рассмотрим его чуть подробнеедеталь:

 mutate(grp = str_extract(name, '.*(?=_confidence|_importance|_answer|_mc|_number|_slider)'),
         sfx = str_extract(name, '(_confidence|_importance|_answer|_mc|_number|_slider)'))

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

group_by(grp) %>% 
  summarize(confidence = '_confidence' %in% sfx,
            importance = '_importance' %in% sfx,
            answer = '_answer' %in% sfx,
            mc = '_mc' %in% sfx,
            number = '_number' %in% sfx,
            slider = '_slider' %in% sfx) %>% 
  ungroup()

Здесь мы группируем по "основам"", который я назвал grp, а затем ищу каждый суффикс.Эта часть немного сложна, и ее нужно будет расширить, если в ваших данных будет больше групп.

gather(sfx, contains, -grp) %>% 
  filter(contains == TRUE) %>% 
  select(-contains)

Здесь мы преобразуем данные в фрейм данных «длинного» стиля и сохраняем толькосуффиксы, которые фактически содержатся в каждой группе.

Это завершает промежуточный фрейм данных.

df %>% 
  mutate(grp = str_extract(name, '.*(?=_confidence|_importance|_answer|_mc|_number|_slider)'))

Сначала мы должны создать столбец grp в исходном фрейме данных, чтобы получитьanti_join на работу.

anti_join(groups %>% 
               filter(sfx == 'number') %>%
               select(grp))

И, наконец, мы anti_join выводим отфильтрованную версию промежуточного фрейма данных в исходный фрейм данных.Я думаю, это даст желаемый эффект.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...