При работе с большими данными временных рядов мне часто приходится уменьшать выборку. При работе с временным индексом, хранящимся в виде числового или целочисленного времени эпохи, очень просто выполнять выборку по минутам или дням с помощью time %% 60 == 0L
и time %% 86400 == 0L
, а с некоторым умножением и округлением также легко извлекать данные с частотой дискретизации менее секунды.
Это очень надуманный пример, используя встроенный набор данных beaver1
, я мог бы использовать выражение, подобное следующей базовой операции data.frame
, чтобы отфильтровать только измерения, которые были получены в начале каждого часа. Это очень надуманный ответ,
beaver1[beaver1$time %% 100 == 0,] |> head
# day time temp activ
# 3 346 900 36.35 0
# 9 346 1000 36.81 0
# 15 346 1100 36.89 0
# 21 346 1200 36.78 0
# 27 346 1300 36.89 0
# 33 346 1400 36.77 0
Я хотел бы сделать аналогичную операцию с объектом arrow::Dataset
. Однако, когда я пытаюсь использовать оператор по модулю, я получаю сообщение об ошибке: Error: !is.null(schema) is not TRUE
.
## Write a toy dataset
arrow::write_csv_arrow(beaver1,"beaver1.csv")
DS <- arrow::open_dataset(sources = c("beaver1.csv"),format = "csv")
DS$NewScan()$UseThreads()$Project(
list(time2 = Expression$field_ref("time") %% 100L,
day = Expression$field_ref("day"),
time = Expression$field_ref("time"),
temp = Expression$field_ref("temp"),
activ = Expression$field_ref("activ"))
)$Filter(Expression$field_ref("time2") == 0L)$Finish()$ToTable()|>
as.data.frame() |>
head()
# Error: !is.null(schema) is not TRUE
Каков правильный синтаксис для применения операций по модулю с Arrow::Dataset
?
Могу ли я использовать новые столбцы, определенные операцией Project()
, в последующей операции Filter()
?
Функция по модулю была реализована в привязках dplyr пакета Arrow, поэтому вы можете сделать что-то вроде:
library(dplyr)
tf <- tempfile()
dir.create(tf)
arrow::write_dataset(beaver1, tf, format = "csv")
arrow::open_dataset(tf, format = "csv") %>%
filter(time %% 100L == 0L) %>%
collect()
#> # A tibble: 19 × 4
#> day time temp activ
#> <int> <int> <dbl> <int>
#> 1 346 900 36.4 0
#> 2 346 1000 36.8 0
#> 3 346 1100 36.9 0
#> 4 346 1200 36.8 0
#> 5 346 1300 36.9 0
#> 6 346 1400 36.8 0
#> 7 346 1500 36.7 0
#> 8 346 1600 36.8 0
#> 9 346 1700 37.0 0
#> 10 346 1800 37.0 0
#> 11 346 1900 37.0 0
#> 12 346 2000 37.1 0
#> 13 346 2100 36.8 0
#> 14 346 2200 37.2 0
#> 15 346 2300 37.2 1
#> 16 347 0 36.9 0
#> 17 347 100 36.8 0
#> 18 347 200 36.9 0
#> 19 347 300 36.9 0
Вы можете использовать этот фрагмент кода без collect()
в конце, чтобы просмотреть детали фильтра, чтобы работать в обратном направлении, чтобы увидеть, какие из вычислительных функций Arrow вам нужно использовать, чтобы получить эквивалент %%
R. Тогда ваш вопрос упрощается до «как мне использовать вычислительные функции Arrow в выражениях», по крайней мере.
Хорошая мысль — я бегло просмотрел eval_array_expression и основываясь на комментарии «Мы не можем просто сделать {e1 — e2 * ( e1 %/% e2 )}, так как Ops.Array нетерпеливо оценивает, но мы можем построить это up», я подозревал, что это могут быть какие-то технические причины, по которым %%
не так прост, как карта по сравнению с другими фильтрами, такими как is_in
. Похоже, я упустил еще одну вещь: полное определение должно быть внутри вызова Filter()
вместо того, чтобы пытаться работать со столбцом Project()
?
Вы также можете попробовать заменить collect()
на show_query()
, который мы привязали к arrow::show_exec_plan()
, что дает больше информации о ExecPlan, созданном привязками dplyr, и может вам помочь, а может и не помочь.
Упс - похоже, вы попали сюда как раз перед тем, как я закончил редактировать свой вопрос, чтобы уточнить, что я надеюсь на прямое использование
Expression
объектов - это решает исходную поставленную проблему!