R pipe, mget и среды
Я публикую это в надежде, что кто-нибудь сможет объяснить здесь поведение. И, возможно, это поможет другим сэкономить время, пытаясь выяснить, как исправить подобную ошибку.
Ответ, вероятно, находится где-то здесь, в этой виньетке Хэдли Уикхэм и Лайонел Генри. Тем не менее, кому-то вроде меня потребуются недели обучения, чтобы соединить точки.
Я выполняю несколько запросов из удаленной базы данных, а затем объединяю их в одну таблицу data.table. Я добавляю префикс "part_" к имени каждого отдельного результата запроса и использую
ls()
и
mget()
с data.table
rbindlist()
объединить их.
Это работает:
results_all <- rbindlist(mget(ls(pattern = "part_", )))
Я изучил этот подход, вероятно, из списка data.tables в памяти и комбинирования по строкам (rbind), и это полезно знать, как это сделать наверняка.
Для удобства чтения я часто предпочитаю использовать канал magrittr (или связывание с data.table), особенно с такими проектами, потому что я использую dplyr для запроса базы данных. Но этот код приводит к ошибке:
results_all <- ls(pattern = "part_", ) %>%
mget() %>%
rbindlist()
Ошибка гласит
Error: value for ‘part_a’ not found
где part_a - это первое имя объекта в векторе символов, возвращаемое
ls()
.
Выполняя поиск этого сообщения об ошибке, я наткнулся на обсуждение этой проблемы data.table на Github. Прочитав это, я попробовал установить "inherits = TRUE" в mget() следующим образом:
results_all <- ls(pattern = "part_", ) %>%
mget(inherits = TRUE) %>%
rbindlist()
И это работает. Таким образом, ошибка возникает при передаче результата
ls()
к
mget()
. И, учитывая, что вложение ls() в mget() работает, я предполагаю, что это как-то связано с конвейером и "охватывающими фреймами окружения".
При написании этого я столкнулся с неожиданным сообщением об ошибке при объединении data.table с помощью rbindlist() с помощью mget(). Из обсуждения я узнал, что это тоже работает.
results_all <- ls(pattern = "part_", ) %>%
mget(envir = .GlobalEnv) %>%
rbindlist()
Опять же, я надеюсь, что кто-нибудь сможет объяснить, что происходит, людям, которые хотят больше узнать о том, как работают среды в R.
Изменить: добавление воспроизводимого примера
В соответствии с запросом на воспроизводимый ответ, запуск приведенного выше кода с использованием этих трех таблиц data.tables (data.frames или tibbles будут вести себя одинаково) должен сделать это.
part_a <- data.table(col1 = 1:10, col2 = sample(letters, 10))
part_b <- data.table(col1 = 11:20, col2 = sample(letters, 10))
part_c <- data.table(col1 = 21:30, col2 = sample(letters, 10))
1 ответ
В
rhs
аргумент оператора канала (в вашем примере выражение
mget()
) никогда не оценивается интерпретатором как вызов функции. Оператор канала - это инфиксная функция, которая выполняет нестандартное вычисление своего второго аргумента (rhs
). Функция конвейера составляет и выполняет вызов новой функции, используя выражение RHS как своего рода "шаблон".
Вызывающая среда этого нового вызова функции - это функциональная среда
%>%
, а не вызывающая среда
lhs
функция или глобальная среда.
.GlobalEnv
и вызывающая среда
lhs
функция оказывается той же средой в вашем примере, и эта среда является родительской для функциональной среды
%>%
, вот почему
inherits = TRUE
или настройте среду на
.GlobalEnv
работает на вас.