Почему я не получаю сообщение об ошибке, если столбец, на который ссылается отрицательный фильтр, не существует, и как я могу добавить сообщение об ошибке?

#r #dplyr

Вопрос:

Возьмите следующие два кадра данных:

 onedf<-data.frame(ID=c("a","b","c"),
                  Count=c(7,80,23))

anotherdf<-data.frame(Car_ID=c("b","c","d"),
                      Color=c("red","green","blue"))
 

В попытке получить отфильтрованную версию onedf , в которой идентификаторы сохраняются только в том случае, если они не отображаются anotherdf , я ошибочно ссылаюсь anotherdr$ID на приведенный ниже код:

 filtereddf<-onedf%>%
  filter(!(ID %in% anotherdf$ID))
 

Почему не выводится предупреждение или сообщение об ошибке, учитывая тот факт, что в нем нет именованного ID столбца anotherdf ?

Результатом выполнения вышеперечисленного является filtereddf то, что на самом деле это просто нефильтрованная версия onedf . Я думаю, однако, что код должен сработать и предупредить меня о том, что его не существует. anotherdf$ID Если бы это произошло, я бы знал, что нужно проверить имена своих столбцов внутри anotherdf , и в конечном итоге смог бы правильно отредактировать свой код, чтобы

 filtereddf<-onedf%>%
  filter(!(ID %in% anotherdf$Car_ID))
 

в конечном счете, в результате filtereddf получается одна строка,

введите описание изображения здесь

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

Есть ли способ добиться этого фильтра таким образом, чтобы ссылка на столбец с неправильным именем вызвала ошибку, или, возможно, способ принудительно filter() проверить имя столбца?

Ответ №1:

Причина, по которой он выдает полную строку , заключается в том , что, если столбец не существует, он возвращается NULL , а когда мы выполняем filter %in% команду » вкл NULL .», он возвращает значение FALSE. Отрицание ( ! ) изменяет значение FALSE на TRUE, и таким образом мы получаем все строки

 anotherdf$ID
#NULL
onedf %>% 
    filter(ID %in% NULL)
#[1] ID    Count
#<0 rows> (or 0-length row.names)

onedf %>%
    filter(!ID %in% NULL)
#  ID Count
#1  a     7
#2  b    80
#3  c    23
 

Это можно легко понять, если мы создадим колонку с mutate

  onedf %>%
    mutate(flag1 = ID %in% anotherdf$ID, flag2 = !flag1) 
#   ID Count flag1 flag2
#1  a     7 FALSE  TRUE
#2  b    80 FALSE  TRUE
#3  c    23 FALSE  TRUE
 

Мы могли бы принудительно stop сделать это, если в «anotherdf» нет столбцов с таким именем столбца exist

 onedf %>%
     filter({stopifnot(exists('ID', where = anotherdf)); ID %in% anotherdf$ID})
Error: Problem with `filter()` input `..1`.
✖ exists("ID", where = anotherdf) is not TRUE
ℹ Input `..1` is `{ ... }`.
Run `rlang::last_error()` to see where the error occurred.
 

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

1. Это делает свое дело! Вот функция фильтрации «не в», которая остановится, если столбец неправильно назван на основе @akrun : filter_notin_safe<-function(.data,otherdf,columnInData,columnInOtherDf){ columnInData<-rlang::ensym(columnInData) columnInOtherDf<-rlang::ensym(columnInOtherDf) .data%>% filter({stopifnot(exists(as.character(columnInOtherDf), where = otherdf)); !(!!columnInData %in% otherdf[,names(otherdf) %in% c(columnInOtherDf)])}) }