#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)])}) }