h2oplyr provides familiar transformation verbs while
keeping the observations inside an H2O cluster. The only
external runtime dependency is h2o. The
tidytable API inspires parts of the interface, but neither
tidytable nor dplyr participates in a
calculation. knitr and rmarkdown are optional
documentation-building dependencies.
The workflow is:
CSV file → H2OFrame → h2o_tbl → remote operations → H2OFrame
An h2o_tbl is a small R object containing a remote frame
handle and grouping column names. R assembles expressions and inspects
metadata; H2O processes the rows. Scalar reductions and category domains
can reach R, but no transformation uses a local data frame, matrix or
vector as its computational backend. For display only, the previews
below request a few scalar values and categorical labels. Displaying a
value necessarily brings that value to the reader; it does not change
where selection, aggregation, joins and reshaping run.
This tutorial is for R users familiar with selecting columns, filtering rows and grouping data. You will learn to inspect remote results, handle missing values, check joins and verify a reshape round trip. Java and a matching H2O client/server are the only external runtime requirements.
This tutorial uses measurements of 344 penguins from three species in
the Palmer Archipelago, collected during 2007–2009. The CSV is included
in the package, so examples do not depend on a future download or a
palmerpenguins installation.
| Practical question | Tools used below | Visible evidence |
|---|---|---|
| Which variables and rows do I need? | h_select(), h_filter(),
h_drop_na() |
Values, column names and row counts |
| How do I derive and summarize measurements? | h_mutate(), h_summarize(),
h_across() |
Derived units and species means |
| Can I combine and reshape without losing information? | h_left_join(), pivot verbs |
Preserved row counts and matching values |
| How do ordering and sampling affect the result? | Slice verbs, h_arrange(),
h_lag() |
Sample rows, tied maxima and lag values |
Reading the examples. Each transformation is followed by values returned from H2O and a green check based on an executed assertion. A preview is a small window into the result; the caption reports the full result dimensions.
Install the package archive using
install.packages(path, repos = NULL, type = "source") after
installing h2o. Start a matching H2O server explicitly:
# Run this yourself, once per session. Loading h2oplyr never starts a server.
h2o::h2o.init(nthreads = 2, max_mem_size = "2G")
library(h2oplyr)These helpers belong to this vignette, not to the package API.
preview_h2o() accepts a remote table, a title, a few column
names and a row limit (at most six). It prints HTML and returns no local
analytical table. Numbers use scalar H2O reductions; text uses the
categorical domain of a single selected value. H2O may internally cache
small metadata previews. This is a deliberately small, slow display
routine, not a data export facility. verify_output() stops
the render if its condition fails. All helpers are defined here before
their first use.
# Escape labels before placing them inside HTML.
html_text <- function(x) {
x <- gsub("&", "&", x, fixed = TRUE)
x <- gsub("<", "<", x, fixed = TRUE)
gsub(">", ">", x, fixed = TRUE)
}
# Show bounded remote values without creating a local data.frame.
preview_h2o <- function(x, title, columns = names(as_h2o(x)), rows = 4L) {
frame <- as_h2o(x)
stopifnot(inherits(frame, "H2OFrame"), rows >= 1L, rows <= 6L,
all(columns %in% names(frame)))
types <- unlist(h2o::h2o.getTypes(frame[, columns]), use.names = FALSE)
shown <- min(rows, nrow(frame))
cat('\n<div class="result"><h3>', html_text(title), '</h3>', sep = "")
cat('<p class="result-meta">H2OFrame · ', nrow(frame), ' rows × ',
ncol(frame), ' columns · showing ', shown, ' rows and ',
length(columns), ' columns</p><div class="table-scroll"><table><thead><tr>',
sep = "")
for (j in seq_along(columns)) {
alignment <- if (types[j] %in% c("int", "real")) ' class="num"' else ""
cat('<th scope="col"', alignment, '>', html_text(columns[j]), '</th>', sep = "")
}
cat('</tr></thead><tbody>')
for (i in seq_len(shown)) {
cat('<tr>')
for (j in seq_along(columns)) {
# Two-step indexing keeps the cell as a remote frame in H2O.
cell <- frame[i, ][, columns[j]]
stopifnot(inherits(cell, "H2OFrame"))
numeric_column <- types[j] %in% c("int", "real")
alignment <- if (numeric_column) ' class="num"' else ""
if (h2o::h2o.sum(is.na(cell)) == 1) {
value <- '<span class="missing">NA</span>'
} else if (numeric_column) {
number <- h2o::h2o.sum(cell)
value <- if (number == floor(number)) sprintf("%.0f", number) else sprintf("%.2f", number)
} else {
# Re-encode in H2O so the domain contains only this cell's label.
label <- h2o::h2o.levels(h2o::h2o.asfactor(h2o::h2o.ascharacter(cell)))
stopifnot(length(label) == 1L)
value <- html_text(as.character(label[[1L]]))
}
cat('<td', alignment, '>', value, '</td>', sep = "")
}
cat('</tr>')
}
cat('</tbody></table></div></div>\n\n')
invisible(NULL)
}
# Only a successful, evaluated assertion receives a green check.
verify_output <- function(condition, label) {
stopifnot(isTRUE(condition))
cat('\n<p class="check"><strong>Verified.</strong> ', html_text(label), '</p>\n\n', sep = "")
}# Import the bundled CSV and confirm its dimensions.
penguins <- h_penguins()
stopifnot(nrow(as_h2o(penguins)) == 344)| species | island | bill_length_mm | body_mass_g |
|---|---|---|---|
| Adelie | Torgersen | 39.10 | 3750 |
| Adelie | Torgersen | 39.50 | 3800 |
| Adelie | Torgersen | 40.30 | 3250 |
| Adelie | Torgersen | NA | NA |
Verified. 344 observations and 8 variables imported into H2O.
h_penguins() uploads the local CSV through
h2o.uploadFile() and declares "NA" as missing
in every column. Species, island and sex are categorical; measurements
are numeric. For your own files, upload directly with
h2o::h2o.uploadFile() and wrap the returned frame with
h2o_tbl().
The default table printer displays metadata only. This vignette adds
bounded value previews so you can inspect the results directly.
h_collect(penguins) and as_h2o(penguins) both
return the remote H2OFrame, preserving the backend
contract. This is an intentional change from the original standalone
prototype.
The eight variables are species, island, bill length and depth (mm),
flipper length (mm), body mass (g), sex and year. A missing measurement
appears as NA, not as zero. The same penguin can have one
measurement missing and others present.
Recognize the object. The result is an
H2OFrame wrapped by h2o_tbl. The small HTML
table above is a display of selected values, not a new data backend.
# Keep relevant columns, then rename and order the bill measurements.
bills <- h_select(penguins, species, starts_with("bill_"))
measurements <- h_select(penguins, where(is.numeric))
renamed <- h_rename(bills, bill_length = bill_length_mm)
relocated <- h_relocate(renamed, species, .before = bill_length)| species | bill_length_mm | bill_depth_mm |
|---|---|---|
| Adelie | 39.10 | 18.70 |
| Adelie | 39.50 | 17.40 |
| Adelie | 40.30 | 18 |
| Adelie | NA | NA |
| bill_length_mm | bill_depth_mm | flipper_length_mm | body_mass_g | year |
|---|---|---|---|---|
| 39.10 | 18.70 | 181 | 3750 | 2007 |
| 39.50 | 17.40 | 186 | 3800 | 2007 |
| 40.30 | 18 | 195 | 3250 | 2007 |
| species | bill_length | bill_depth_mm |
|---|---|---|
| Adelie | 39.10 | 18.70 |
| Adelie | 39.50 | 17.40 |
| Adelie | 40.30 | 18 |
| Adelie | NA | NA |
Verified. Selection, renaming and final column order match the requested schema.
Selection operates on column names and H2O schema types.
where() supports the base predicates
is.numeric, is.character and
is.factor; arbitrary predicates are deliberately rejected.
all_of() requires every requested column, while
any_of() allows absent names. Ranges such as
species:island and exclusions such as -year
are supported. A grouped selection retains its grouping columns.
Takeaway. Selection changes the schema, not the observations. All three previews retain the original 344 rows.
# Compare complete-case filtering with two measurement thresholds.
complete_penguins <- h_drop_na(penguins)
stopifnot(nrow(as_h2o(complete_penguins)) == 333)
cat("Complete observations:", nrow(as_h2o(complete_penguins)), "\n")
#> Complete observations: 333
large <- h_filter(penguins, body_mass_g >= 5000)
cat("Penguins weighing at least 5000 g:", nrow(as_h2o(large)), "\n")
#> Penguins weighing at least 5000 g: 67
bill_range <- h_filter(penguins, h_between(bill_length_mm, 40, 50))
cat("Penguins with bill length from 40 to 50 mm:", nrow(as_h2o(bill_range)), "\n")
#> Penguins with bill length from 40 to 50 mm: 190| species | bill_length_mm | body_mass_g | sex |
|---|---|---|---|
| Adelie | 39.10 | 3750 | male |
| Adelie | 39.50 | 3800 | female |
| Adelie | 40.30 | 3250 | female |
| Adelie | 36.70 | 3450 | female |
| species | body_mass_g |
|---|---|
| Gentoo | 5700 |
| Gentoo | 5700 |
| Gentoo | 5400 |
| Gentoo | 5200 |
| species | bill_length_mm |
|---|---|
| Adelie | 40.30 |
| Adelie | 42 |
| Adelie | 41.10 |
| Adelie | 42.50 |
Verified. Complete-case count and both filter boundaries checked over the full remote results.
A missing filter condition is dropped. The expression interpreter
propagates missing comparisons explicitly, because H2O’s raw comparison
behavior can differ from R’s. h_filter_out() negates the
combined predicate and also drops missing conditions. Use
is.na() when you intend to select missing measurements.
# Select the missing body masses explicitly.
missing_mass <- h_filter(penguins, is.na(body_mass_g))
stopifnot(nrow(as_h2o(missing_mass)) == 2)| species | bill_length_mm | body_mass_g |
|---|---|---|
| Adelie | NA | NA |
| Gentoo | NA | NA |
Verified. Both retained rows have a missing body mass.
Dropping all incomplete rows yields 333 penguins, whereas a mass-only analysis can retain 342. Those are different analysis populations. Replacing missing body mass with zero would invent a biologically impossible measurement, so this tutorial removes missing mass only where it is needed.
Takeaway. Choose the missing-data rule for the question: requiring every variable to be complete removes more rows than requiring body mass alone.
# Drop only missing mass, then derive units and a mass category.
prepared <- penguins |>
h_drop_na(body_mass_g) |>
h_mutate(
mass_kg = body_mass_g / 1000,
mass_band = h_case_when(
body_mass_g >= 5000 ~ "large",
body_mass_g >= 3500 ~ "medium",
TRUE ~ "small"
)
)
stopifnot(nrow(as_h2o(prepared)) == 342)
cat("Total measured mass (kg):",
h2o::h2o.sum(as_h2o(prepared)[, "mass_kg"]), "\n")
#> Total measured mass (kg): 1437| species | body_mass_g | mass_kg | mass_band |
|---|---|---|---|
| Adelie | 3750 | 3.75 | medium |
| Adelie | 3800 | 3.80 | medium |
| Adelie | 3250 | 3.25 | small |
| Adelie | 3450 | 3.45 | small |
Verified. 342 measured masses retained; the kg-to-g conversion agrees for every row.
Named mutations run sequentially, so a later expression can use a
newly created column. Arithmetic, comparisons, selected H2O mathematical
and text functions, and the package’s vector helpers are supported.
Calls to arbitrary R functions or other package namespaces raise an
error. h_transmute() retains only the new named columns.
Grouped mutation supports the five window helpers introduced below.
Other grouped expressions are rejected: derive ordinary columns before
grouping, or ungroup explicitly when a global calculation is
intended.
The native |> pipe and the package’s %.%
pipe can both chain these verbs.
Takeaway. Read the derived columns side by side. The numerical assertion checks every measured mass, not just the displayed rows.
# Compute counts and means inside H2O, grouped by species.
by_species <- h_summarize(
penguins,
observations = n(),
mean_mass_g = mean(body_mass_g, na.rm = TRUE),
mean_bill_mm = mean(bill_length_mm, na.rm = TRUE),
.by = species
)| species | observations | mean_mass_g | mean_bill_mm |
|---|---|---|---|
| Adelie | 152 | 3700.66 | 38.79 |
| Chinstrap | 68 | 3733.09 | 48.83 |
| Gentoo | 124 | 5076.02 | 47.50 |
Verified. Three groups account for all 344 observations.
The output has one row per species. n() counts all
observations; each mean removes missing values independently. Gentoo
penguins have the highest mean body mass in this sample. This is a
descriptive comparison, not a causal effect of species or island.
.by applies grouping to this call only. The equivalent
persistent grouping form is
h_group_by(penguins, species) |> h_summarize(...);
summaries themselves return ungrouped results. .add = TRUE
adds grouping columns, and h_group_vars() reports the
current grouping metadata.
Supported reductions are n(),
n_distinct(column), sum, mean,
min, max, sd, var
and median. Each reduction takes a column, optionally with
na.rm. Create transformed columns with
h_mutate() before aggregating. The adapter rejects
empty-input summaries explicitly.
Takeaway. Group sizes count penguins, while each mean uses its own non-missing measurements. A group count is not necessarily the denominator of every mean.
# Apply unit conversion and grouped means to multiple columns.
scaled <- h_mutate(
bills,
h_across(starts_with("bill_"), list(cm = function(z) z / 10))
)
average_bills <- bills |>
h_drop_na() |>
h_group_by(species) |>
h_summarize_across(starts_with("bill_"), list(average = mean))| species | bill_length_mm | bill_length_mm_cm | bill_depth_mm_cm |
|---|---|---|---|
| Adelie | 39.10 | 3.91 | 1.87 |
| Adelie | 39.50 | 3.95 | 1.74 |
| Adelie | 40.30 | 4.03 | 1.80 |
| Adelie | NA | NA | NA |
| species | bill_length_mm_average | bill_depth_mm_average |
|---|---|---|
| Adelie | 38.79 | 18.35 |
| Chinstrap | 48.83 | 18.42 |
| Gentoo | 47.50 | 14.98 |
Verified. Across conversion and the three grouped summaries checked.
h_across() builds column expressions with names such as
bill_length_mm_cm. The one-argument function body is
interpreted through the same remote expression rules as
h_mutate(). Summary function identity is used, so an alias
such as average = mean still computes the mean. Across
summaries default to na.rm = FALSE; this example
deliberately removes missing bill measurements first. The standalone
h_mutate_across() wrapper is retained for
compatibility.
Takeaway. Across applies the same expression to several columns; the suffix records the transformation or summary that produced each output.
# Attach a unique species summary to each observed mass.
enriched <- h_left_join(
prepared, by_species,
by = "species", relationship = "many-to-one"
)
stopifnot(nrow(as_h2o(enriched)) == nrow(as_h2o(prepared)))
enriched <- h_mutate(enriched, mass_minus_species_mean = body_mass_g - mean_mass_g)| species | body_mass_g | mean_mass_g | mass_minus_species_mean |
|---|---|---|---|
| Adelie | 2850 | 3700.66 | -850.66 |
| Adelie | 2850 | 3700.66 | -850.66 |
| Adelie | 2900 | 3700.66 | -800.66 |
| Adelie | 2900 | 3700.66 | -800.66 |
Verified. The join preserves all 342 measured penguins and matches a species mean to each.
The relationship check ensures the right table has at most one record
per species, preventing accidental multiplication of penguin rows.
Inner, left, right and full equijoins are available.
h_semi_join() selects left rows with a match;
h_anti_join() selects those without one. Named keys map
different column names, for example
by = c(species = "species_code").
A full join is implemented using a left join plus unmatched right
rows, all inside H2O. Missing-key matching follows H2O, and join row
order is unspecified. Always use h_arrange() when
subsequent calculations depend on ordering.
Takeaway. A valid many-to-one join must preserve the left row count. Sorting the preview makes it readable; join order itself is unspecified.
# Use species-level summaries so the ID is naturally unique.
wide <- h_summarize(
penguins,
bill_length_mm = mean(bill_length_mm, na.rm = TRUE),
bill_depth_mm = mean(bill_depth_mm, na.rm = TRUE),
.by = species
)
long <- h_pivot_longer(
wide, starts_with("bill_"),
names_to = "measurement", values_to = "mean_mm"
)
stopifnot(nrow(as_h2o(long)) == 6)
restored <- h_pivot_wider(long, measurement, mean_mm)
stopifnot(nrow(as_h2o(restored)) == 3)| species | bill_length_mm | bill_depth_mm |
|---|---|---|
| Adelie | 38.79 | 18.35 |
| Chinstrap | 48.83 | 18.42 |
| Gentoo | 47.50 | 14.98 |
| species | measurement | mean_mm |
|---|---|---|
| Adelie | bill_length_mm | 38.79 |
| Adelie | bill_depth_mm | 18.35 |
| Chinstrap | bill_length_mm | 48.83 |
| Chinstrap | bill_depth_mm | 18.42 |
| Gentoo | bill_length_mm | 47.50 |
| Gentoo | bill_depth_mm | 14.98 |
| species | bill_length_mm | bill_depth_mm |
|---|---|---|
| Adelie | 38.79 | 18.35 |
| Chinstrap | 48.83 | 18.42 |
| Gentoo | 47.50 | 14.98 |
Verified. Wide → long → wide preserves both mean measurements for every species.
The long result contains six species/measurement combinations.
Widening gets the output names from the remote categorical domain and
combines values with remote joins. Repeated ID/name combinations are
rejected: decide on an aggregation before reshaping. This avoids
silently choosing one measurement or creating a local list-column.
values_fill replaces missing result cells, including
explicitly missing input values.
For text transformations, h_separate() uses H2O
regular-expression splitting. h_unite() uses H2O
categorical interaction with encoded original underscores; its current
separator cannot contain dollar signs or backslashes. High-cardinality
interaction domains can consume substantial cluster memory.
Takeaway. The round-trip check compares both measurements across all species. Matching row counts alone would not prove that the values survived.
# Sample reproducibly, retain tied maxima and compute a sorted lag.
sample_penguins <- h_slice_sample(prepared, n = 12, seed = 2026)
stopifnot(nrow(as_h2o(sample_penguins)) == 12)
heaviest <- h_slice_max(prepared, body_mass_g, n = 3, with_ties = TRUE)
cat("Rows among the three heaviest positions, including ties:",
nrow(as_h2o(heaviest)), "\n")
#> Rows among the three heaviest positions, including ties: 4
ordered <- h_arrange(prepared, body_mass_g)
ordered <- h_mutate(ordered, previous_mass = h_lag(body_mass_g))| species | body_mass_g | bill_length_mm |
|---|---|---|
| Adelie | 2975 | 37.50 |
| Adelie | 3550 | 39.70 |
| Gentoo | 5550 | 50 |
| Adelie | 3350 | 35.50 |
| species | body_mass_g |
|---|---|
| Gentoo | 6300 |
| Gentoo | 6050 |
| Gentoo | 6000 |
| Gentoo | 6000 |
| species | body_mass_g | previous_mass |
|---|---|---|
| Chinstrap | 2700 | NA |
| Adelie | 2850 | 2700 |
| Adelie | 2850 | 2850 |
| Adelie | 2900 | 2850 |
Verified. Sample size is 12; the first lag is missing and every later lag matches the preceding mass.
Sampling uses H2O random columns. Sampling with replacement creates
draw indices in H2O and joins them to rows. With
seed = NULL (the default), no seed is passed to H2O; supply
a seed explicitly when reproducibility is needed. Identical seeds are
reproducible on the same frame and cluster layout; they are not a
promise of identical samples across versions or distributed layouts.
with_ties = TRUE can return more than n
rows.
Lag, lead, cumulative operations and h_fill() use
current row order. Penguins are not a longitudinal time series: the lag
example illustrates an ordered comparison, not a temporal
interpretation. Grouped windows are covered next. Grouped slicing,
filling and cumulative helpers remain unsupported.
Takeaway. A seeded sample is reproducible within the documented setting. A lag is meaningful only after choosing an order; penguins here are not a longitudinal panel.
Version 0.3.0 adds grouped h_mutate() for five direct
window calls: h_lag(), h_lead(),
h_roll_mean(), h_min_rank() and
h_row_number(). Use .by for one call, or
h_group_by() for persistent grouping. Each window follows
the existing row order within its group, even when
groups are interleaved. The output preserves the input row order.
Missing keys are valid grouping values; multiple grouping columns are
supported.
A complete ordering key makes the meaning of “previous” unambiguous. Here the original row position breaks mass ties; this is an ordered comparison, not a longitudinal analysis of individual birds.
# Number the input rows before sorting, then use that position to break ties.
species_order <- penguins |>
h_filter(!is.na(body_mass_g)) |>
h_mutate(input_row = h_row_number()) |>
h_arrange(species, body_mass_g, input_row)
species_windows <- species_order |>
h_group_by(species) |>
h_mutate(previous_mass = h_lag(body_mass_g),
mean_last_three = h_roll_mean(body_mass_g, k = 3),
mass_rank = h_min_rank(desc(body_mass_g)),
position = h_row_number())
# Grouping persists until removed explicitly.
stopifnot(identical(h_group_vars(species_windows), "species"))
first_in_species <- species_windows |> h_ungroup() |> h_filter(position == 1)| species | body_mass_g | previous_mass | mean_last_three | mass_rank | position |
|---|---|---|---|---|---|
| Adelie | 2850 | NA | 2850 | 150 | 1 |
| Adelie | 2850 | 2850 | 2850 | 150 | 2 |
| Adelie | 2900 | 2850 | 2866.67 | 147 | 3 |
| Adelie | 2900 | 2900 | 2883.33 | 147 | 4 |
Verified. Each species starts with a missing lag and a one-row partial mean.
The first bird in each species has no predecessor. Its partial
rolling mean therefore equals its own mass. mass_rank runs
from the heaviest mass downwards; equal masses share the minimum rank
and leave gaps after ties.
The package also includes a small synthetic fixture with interleaved groups, missing keys, missing amounts and tied amounts. Its independently calculated expected columns are used by the regression tests.
reference <- h2o::h2o.uploadFile(
system.file("extdata", "windows.csv", package = "h2oplyr"),
na.strings = "NA",
col.types = c("numeric", "enum", "enum", rep("numeric", 15)))
observations <- h2o_tbl(reference[, c("id", "group", "subgroup", "amount")])
windows <- h_mutate(observations,
prev = h_lag(amount), next_amount = h_lead(amount),
roll = h_roll_mean(amount, k = 3),
roll_rm = h_roll_mean(amount, k = 3, na.rm = TRUE),
full = h_roll_mean(amount, k = 3, partial = FALSE),
rank_desc = h_min_rank(desc(amount)), row = h_row_number(),
.by = c(group, subgroup))
# .by does not attach grouping to the result.
stopifnot(length(h_group_vars(windows)) == 0)
example_group <- h_filter(windows, group == "A", subgroup == "x")| id | amount | prev | roll | rank_desc | row |
|---|---|---|---|---|---|
| 1 | 10 | NA | 10 | 4 | 1 |
| 3 | 20 | 10 | 15 | 2 | 2 |
| 6 | 20 | 20 | 16.67 | 2 | 3 |
| 8 | NA | 20 | NA | NA | 4 |
| 13 | 40 | NA | NA | 1 | 5 |
| id | amount | roll | roll_rm | full |
|---|---|---|---|---|
| 1 | 10 | 10 | 10 | NA |
| 3 | 20 | 15 | 15 | NA |
| 6 | 20 | 16.67 | 16.67 | 16.67 |
| 8 | NA | NA | 20 | NA |
| 13 | 40 | NA | 30 | NA |
Verified. All six window columns match the independent reference, including missing values; input order is unchanged.
The amounts 20 and 20 both receive rank 2; amount 10 receives rank 4. A missing amount remains unranked. A lag shifts a missing value as it would any other value. The rolling window includes the current row and up to two preceding rows:
| Option | Behavior |
|---|---|
partial = TRUE (default) |
Use the available prefix at the beginning of each group. |
partial = FALSE |
Return NA until the group has at least
k rows. |
na.rm = FALSE (default) |
Any missing amount within the window makes the mean missing. |
na.rm = TRUE |
Average observed amounts; return NA for an
all-missing window. |
With both partial = FALSE and na.rm = TRUE,
completeness still means k rows, not
k observed amounts. The implementation composes remote
shifts; its work grows with the window width. It is intended for short
windows such as k = 3, and makes no constant-cost or
comparative performance claim.
The same operations express a typical transaction task: remove missing amounts, order by customer, time and transaction ID, compute windows, then aggregate. For this small executable illustration, the synthetic row ID also supplies the time order; these are not real transaction data.
transactions <- observations |>
h_select(id, group, amount) |>
h_rename(txn_id = id, customer_id = group) |>
h_mutate(txn_time = txn_id) |>
h_filter(!is.na(amount)) |>
h_arrange(customer_id, txn_time, txn_id)
transaction_windows <- h_mutate(transactions,
prev_amount = h_lag(amount),
roll_mean = h_roll_mean(amount, k = 3, partial = TRUE),
rank_amount = h_min_rank(desc(amount)),
.by = customer_id)
customer_summary <- h_summarize(transaction_windows,
observations = n(), average_window = mean(roll_mean), .by = customer_id)| customer_id | observations | average_window |
|---|---|---|
| A | 8 | 16.17 |
| B | 2 | 6.50 |
| D | 1 | 4 |
| NA | 2 | 5 |
Verified. Every retained transaction contributes to a customer summary.
Takeaway. Set a complete row order before computing
windows. Grouped mutation accepts direct calls to the five supported
helpers; it does not evaluate arbitrary R expressions. Derive other
columns before grouping. Group keys cannot be overwritten. Grouped
cumulative helpers and large-window optimizations are outside this
release. h_row_number() is a zero-argument mutation helper;
h_min_rank() and h_roll_mean() accept one
numeric H2O column.
Every exported function has an executable example with an assertion. The package also includes regression tests for missing values, aggregation, ties, empty slices, join multiplicity, invalid expressions and input preservation. Integration tests compare H2O function bindings before and after execution without modifying the H2O namespace. A static audit rejects local-table calls in package functions. Additional maintainer-only download instrumentation is kept outside the package.
Run all examples and regressions against a cluster you started explicitly:
h2o::h2o.init(nthreads = 2, max_mem_size = "2G")
library(h2oplyr)
source(system.file("examples", "examples.R", package = "h2oplyr"))
for (nm in names(examples)) eval(examples[[nm]])
source(system.file("examples", "regressions.R", package = "h2oplyr"))This package is an explicit subset of tidy-style manipulation, not a
complete drop-in replacement for dplyr or
tidytable. It has no local rowwise/map backend,
non-equality joins, automatic list-column nesting, arbitrary R
callbacks, general grouped mutation beyond the five supported window
helpers, or implicit duplicate-cell pivot aggregation.
h_bind_rows() requires matching column-name sets.
h_nest_by() returns a list of remote group handles and is
intended for a modest number of groups.
When no cluster is connected, rebuilding this vignette retains the code but skips H2O execution. The distributed HTML was built against an explicitly connected server. The package never starts or shuts down a user’s cluster while loading, printing, or running its ordinary examples.
The green checks accompany the tutorial’s calculations. The installed package also contains 76 asserted API examples and semantic regression tests; those are a separate suite, not 76 examples all reproduced on this page. The commands in “Connect once” and “Validation” are instructions to run yourself, rather than claims that this HTML launched a cluster or reran the complete package test suite.
Executed with H2O. R 4.6.1; h2oplyr 0.3.0; h2o 3.44.0.3. All tutorial assertions completed during rendering.
Try changing the mass threshold or selecting another species, then
rerun the section and inspect both the values and the assertion. Do not
infer a successful transformation merely from seeing an object name or
from a silent stopifnot().
Data: Horst AM, Hill AP, Gorman KB (2020), palmerpenguins: Palmer
Archipelago (Antarctica) penguin data, doi:10.5281/zenodo.3960218.
The data are available under CC0. Measurements were collected by Kristen
Gorman and Palmer Station LTER. The research description is Gorman KB,
Williams TD, Fraser WR (2014), doi:10.1371/journal.pone.0090081.
The bundled CSV’s source, retrieval date and SHA-256 are recorded in
system.file("extdata", "PROVENANCE.md", package = "h2oplyr").
The synthetic windows.csv fixture was authored for
h2oplyr and is covered by the package MIT license. It contains no
personal or transactional records.