Я открыл набор данных .parquet с помощью функции open_dataset
пакета arrow
. Я хочу использовать across
для одновременной очистки нескольких числовых столбцов. Однако, когда я запускаю этот код:
start_numeric_cols = "sum"
sales <- sales %>% mutate(
across(starts_with(start_numeric_cols) & (!where(is.numeric)),
\(col) {replace(col, col == "NULL", 0) %>% as.numeric()}),
across(starts_with(start_numeric_cols) & (where(is.numeric)),
\(col) {replace(col, is.na(col), 0)})
)
#> Error in `across_setup()`:
#> ! Anonymous functions are not yet supported in Arrow
Сообщение об ошибке довольно информативно, но мне интересно, есть ли способ сделать то же самое только с глаголами dplyr
внутри across
(или другой обходной путь без необходимости вводить имя каждого столбца).
arrow
имеет растущий набор функций, которые можно использовать без загрузки данных в R (доступно здесь), но replace()
пока не поддерживается. Однако вы можете использовать ifelse()
/if_else()
/case_when()
. Также обратите внимание, что лямбда-функции в стиле муррр поддерживаются там, где обычные анонимные функции не поддерживаются.
У меня нет ваших данных, поэтому я буду использовать набор данных iris
в качестве примера, чтобы продемонстрировать, что запрос строится успешно, даже если он не имеет полного смысла в контексте этих данных.
library(arrow)
library(dplyr)
start_numeric_cols <- "P"
iris %>%
as_arrow_table() %>%
mutate(
across(
starts_with(start_numeric_cols) & (!where(is.numeric)),
~ as.numeric(if_else(.x == "NULL", 0, .x))
),
across(
starts_with(start_numeric_cols) & (where(is.numeric)),
~ if_else(is.na(.x), 0, .x)
)
)
Table (query)
Sepal.Length: double
Sepal.Width: double
Petal.Length: double (if_else(is_null(Petal.Length, {nan_is_null=true}), 0, Petal.Length))
Petal.Width: double (if_else(is_null(Petal.Width, {nan_is_null=true}), 0, Petal.Width))
Species: dictionary<values=string, indices=int8>
See $.data for the source Arrow object
Просто небольшой комментарий, когда я делал то, что было предложено в первом редактировании (например: ~ifelse(.x == "NULL", 0, as.numeric(.x))
), я не получал никаких ошибок до вызова compute
, который вернул Error in compute(): ! Invalid: Failed to parse string: 'NULL' as a scalar of type double
. Этот последний вариант обертывания оператора if_else
в as.numeric
действительно работает.
@AlbertoAgudoDominguez - это приятно знать. Я не смог протестировать, но понял, что выполнение принуждения внутри оператора ifelse может вызвать проблемы (а также является плохой практикой).
Это сработало отлично! Для других пользователей вы также можете использовать вертикальную черту в аргументе
across
.fns
вarrow
, которую я сначала оставил как~ifelse(.x == "NULL", 0, .x) %>% as.numeric())
. Хотя для этого конкретного случая я думаю, что результат идентичен. Спасибо также за ссылку на реализованные функции в стрелке, это действительно полезно.