Nothing
test_that("native engine powers projection and row filtering", {
df <- data.frame(a = 1:5, b = letters[1:5], c = c(TRUE, FALSE, TRUE, NA, TRUE))
out <- pick(df, c("b", "a"))
expect_s3_class(out, "basetable")
expect_equal(as.data.frame(out), df[c("b", "a")])
filtered <- subset(df, c, select = c(a, b))
expect_equal(as.data.frame(filtered), df[c(1L, 3L, 5L), c("a", "b")], ignore_attr = TRUE)
})
test_that("native engine handles integer count, unique, and duplicates", {
df <- data.frame(g = c(2L, 1L, 2L, NA, 1L, NA), x = seq_len(6))
cnt <- count(df, by = "g", sort = FALSE)
expect_equal(cnt$g, c(2L, 1L, NA))
expect_equal(cnt$n, c(2L, 2L, 2L))
uniq <- uniquerows(df, cols = "g")
expect_equal(uniq$g, c(2L, 1L, NA))
dup <- duplicaterows(df[c("g")])
expect_equal(dup$g, c(2L, 1L, 2L, NA, 1L, NA))
first_only <- removeduplicates(df, by = "g", keep = "first")
expect_equal(first_only$g, c(2L, 1L, NA))
expect_equal(first_only$x, c(1L, 2L, 4L))
})
test_that("native engine orders without mutating inputs", {
input <- data.frame(g = c(2L, 1L, 2L), x = c(3, 2, 1))
original <- input
out <- orderrows(input, by = c("g", "x"), decreasing = c(FALSE, TRUE))
expect_equal(out$g, c(1L, 2L, 2L))
expect_equal(out$x, c(2, 3, 1))
expect_identical(input, original)
})
test_that("native engine aggregates common reducers", {
df <- data.frame(g = c(1L, 1L, 2L, 2L), x = c(1, 3, 5, NA))
expect_equal(aggregate(df, by = "g", value = "x", fun = sum, na.rm = TRUE)$x, c(4, 5))
expect_equal(aggregate(df, by = "g", value = "x", fun = mean, na.rm = TRUE)$x, c(2, 5))
expect_equal(aggregate(df, by = "g", value = "x", fun = min, na.rm = TRUE)$x, c(1, 5))
expect_equal(aggregate(df, by = "g", value = "x", fun = max, na.rm = TRUE)$x, c(3, 5))
expect_equal(aggregate(df, by = "g", value = "x", fun = var, na.rm = TRUE)$x, c(2, NA))
expect_equal(aggregate(df, by = "g", value = "x", fun = sd, na.rm = TRUE)$x, c(sqrt(2), NA))
expect_equal(aggregate(df, by = "g", value = "x", fun = "n")$x, c(2, 2))
expect_true(is.na(aggregate(df, by = "g", value = "x", fun = sum, na.rm = FALSE)$x[[2L]]))
})
test_that("native engine powers semi and anti joins", {
x <- data.frame(id = c(1L, 1L, 2L, 3L), grp = c("a", "b", "a", "a"), val = 1:4)
y <- data.frame(id = c(1L, 3L), grp = c("b", "a"))
semi <- semimerge(x, y, by = c("id", "grp"))
anti <- antimerge(x, y, by = c("id", "grp"))
expect_equal(semi$val, c(2L, 4L))
expect_equal(anti$val, c(1L, 3L))
expect_s3_class(semi, "basetable")
expect_s3_class(anti, "basetable")
})
test_that("native engine materialises equi joins with all.x / all.y / suffixes", {
x <- data.frame(id = c(1L, 2L, 2L, 4L), v = c("a", "b", "c", "d"), stringsAsFactors = FALSE)
y <- data.frame(id = c(2L, 3L), v = c("Y2", "Y3"), w = c(10L, 20L), stringsAsFactors = FALSE)
inner <- merge(x, y, by = "id")
expect_equal(names(inner), c("id", "v.x", "v.y", "w"))
expect_equal(inner$id, c(2L, 2L))
expect_equal(inner$v.x, c("b", "c"))
expect_equal(inner$v.y, c("Y2", "Y2"))
left <- merge(x, y, by = "id", all.x = TRUE)
expect_equal(left$id, c(1L, 2L, 2L, 4L))
expect_equal(left$w, c(NA, 10L, 10L, NA))
dense_x <- data.frame(id = c(1L, 3L, 9L, NA_integer_), v = 1:4)
dense_y <- data.frame(id = 1:5, w = 11:15)
dense <- merge(dense_x, dense_y, by = "id", all.x = TRUE)
expect_equal(dense$id, dense_x$id)
expect_equal(dense$w, c(11L, 13L, NA, NA))
dup_y <- data.frame(id = c(1L, 3L, 3L), w = 21:23)
dup <- merge(dense_x[1:2, ], dup_y, by = "id", all.x = TRUE)
expect_equal(dup$id, c(1L, 3L, 3L))
expect_equal(dup$w, c(21L, 22L, 23L))
full <- merge(x, y, by = "id", all = TRUE, sort = TRUE)
expect_equal(full$id, c(1L, 2L, 2L, 3L, 4L))
expect_equal(full$v.y, c(NA, "Y2", "Y2", "Y3", NA))
custom <- merge(x, y, by = "id", suffixes = c("_l", "_r"))
expect_true(all(c("v_l", "v_r") %in% names(custom)))
})
test_that("native engine joins on multi-column keys and Cartesian products", {
x <- data.frame(a = c(1L, 1L, 2L), b = c("p", "q", "p"), xv = 1:3, stringsAsFactors = FALSE)
y <- data.frame(a = c(1L, 2L), b = c("p", "p"), yv = c(9L, 8L), stringsAsFactors = FALSE)
j <- merge(x, y, by = c("a", "b"))
expect_equal(j$xv, c(1L, 3L))
expect_equal(j$yv, c(9L, 8L))
cj <- crossmerge(data.frame(a = 1:2), data.frame(z = c("x", "y", "z")))
expect_equal(nrow(cj), 6L)
})
test_that("native engine coerces mismatched numeric and factor join keys", {
a <- data.frame(id = 1:4, x = letters[1:4], stringsAsFactors = FALSE)
b <- data.frame(id = c(2, 3, 5), y = c("B", "C", "E"), stringsAsFactors = FALSE)
inner <- merge(a, b, by = "id")
expect_equal(inner$id, c(2, 3))
expect_equal(inner$y, c("B", "C"))
full <- merge(a, b, by = "id", all = TRUE, sort = TRUE)
expect_equal(full$id, c(1, 2, 3, 4, 5))
expect_equal(full$x, c("a", "b", "c", "d", NA))
f1 <- data.frame(g = factor(c("lo", "hi", "lo")), v = 1:3)
f2 <- data.frame(g = c("hi", "lo"), w = c(10, 20), stringsAsFactors = FALSE)
fj <- merge(f1, f2, by = "g")
expect_equal(fj$v, c(1L, 2L, 3L))
expect_equal(fj$w, c(20, 10, 20))
})
test_that("native engine drives range, overlap and rolling joins", {
x <- data.frame(id = c(1L, 1L), lower = c(0, 100), upper = c(10, 200))
y <- data.frame(id = 1L, val = c(5, 15), label = c("a", "b"), stringsAsFactors = FALSE)
rng <- rangemerge(x, y, by = "id", lower = "lower", upper = "upper", value = "val")
expect_equal(rng$label, c("a", NA))
xt <- data.frame(id = c(1L, 1L, 1L), time = c(5, 10, 15))
yt <- data.frame(id = c(1L, 1L), time = c(3, 12), value = c("a", "b"), stringsAsFactors = FALSE)
roll <- rollingmerge(xt, yt, by = c("id", "time"), direction = "backward")
expect_equal(roll$value, c("a", "a", "b"))
nearest <- rollingmerge(xt, yt, by = c("id", "time"), direction = "nearest")
expect_equal(nearest$value, c("a", "b", "b"))
})
test_that("native row-bind unions columns, fills gaps and promotes types", {
a <- data.frame(x = 1:2, y = c("a", "b"), stringsAsFactors = FALSE)
b <- data.frame(y = c("c", "d"), z = c(TRUE, FALSE), stringsAsFactors = FALSE)
bound <- rbindfill(list(a, b))
expect_s3_class(bound, "basetable")
expect_equal(names(bound), c("x", "y", "z"))
expect_equal(bound$x, c(1L, 2L, NA, NA))
expect_equal(bound$y, c("a", "b", "c", "d"))
expect_equal(bound$z, c(NA, NA, TRUE, FALSE))
mixed <- rbindfill(list(data.frame(v = 1:2), data.frame(v = c("x", "y"))), typeconflict = "coerce")
expect_type(mixed$v, "character")
expect_equal(mixed$v, c("1", "2", "x", "y"))
tagged <- rbindfill(list(one = a[1, ], two = b[1, ]), id = "src")
expect_equal(tagged$src, c("one", "two"))
expect_equal(names(tagged)[[1]], "src")
})
test_that("composite key codec groups multi-column and mixed-type keys", {
df <- data.frame(
g1 = c("a", "a", "b", "a", "b"),
g2 = c(1L, 2L, 1L, 1L, 1L),
g3 = factor(c("x", "x", "y", "x", "y")),
v = c(10, 20, 30, 40, 50),
stringsAsFactors = FALSE
)
cnt <- count(df, by = c("g1", "g2", "g3"), sort = FALSE)
expect_equal(nrow(cnt), 3L)
expect_equal(cnt$n[cnt$g1 == "a" & cnt$g2 == 1L], 2L)
agg <- aggregate(df, by = c("g1", "g3"), value = "v", fun = sum, sort = TRUE)
expect_equal(agg$g1, c("a", "b"))
expect_equal(agg$v, c(10 + 20 + 40, 30 + 50))
u <- uniquerows(df, cols = c("g1", "g3"))
expect_equal(nrow(u), 2L)
dbl <- duplicaterows(df[c("g1", "g3")])
expect_equal(dbl$g1, c("a", "a", "b", "a", "b"))
})
test_that("grouping a single numeric double key works through the codec", {
df <- data.frame(k = c(1.5, 2.5, 1.5, 2.5, 1.5), v = 1:5)
agg <- aggregate(df, by = "k", value = "v", fun = sum, sort = TRUE)
expect_equal(agg$k, c(1.5, 2.5))
expect_equal(agg$v, c(1 + 3 + 5, 2 + 4))
})
test_that("threaded and serial grouped aggregation agree", {
skip_on_cran()
set.seed(42)
n <- 2e6
d <- data.frame(g = sample(letters[1:6], n, TRUE), x = rnorm(n), stringsAsFactors = FALSE)
old <- getOption("basetable.threads")
on.exit(options(basetable.threads = old), add = TRUE)
options(basetable.threads = 1L)
s <- aggregate(d, by = "g", value = "x", fun = sum, sort = TRUE)
m <- aggregate(d, by = "g", value = "x", fun = mean, sort = TRUE)
v <- aggregate(d, by = "g", value = "x", fun = var, sort = TRUE)
options(basetable.threads = 8L)
s8 <- aggregate(d, by = "g", value = "x", fun = sum, sort = TRUE)
m8 <- aggregate(d, by = "g", value = "x", fun = mean, sort = TRUE)
v8 <- aggregate(d, by = "g", value = "x", fun = var, sort = TRUE)
expect_equal(s8$x, s$x, tolerance = 1e-8)
expect_equal(m8$x, m$x, tolerance = 1e-10)
expect_equal(v8$x, v$x, tolerance = 1e-8)
expect_equal(s8$g, s$g)
})
test_that("orderrows on character keys matches C-locale ordering", {
set.seed(7)
d <- data.frame(
s = sample(c(letters, LETTERS), 5000, TRUE),
k = sample(1:20, 5000, TRUE),
stringsAsFactors = FALSE
)
d$s[sample(5000, 50)] <- NA
out <- as.data.frame(orderrows(d, by = c("s", "k")))
ref <- d[order(d$s, d$k, method = "radix", na.last = TRUE), ]
rownames(out) <- NULL
rownames(ref) <- NULL
expect_equal(out, ref)
})
test_that("orderrows fast path handles character then double keys", {
set.seed(8)
d <- data.frame(
s = sample(c(sprintf("k%03d", 1:40), NA), 10000, TRUE),
x = sample(c(round(rnorm(9900), 2), rep(NA_real_, 100))),
id = seq_len(10000),
stringsAsFactors = FALSE
)
out <- as.data.frame(orderrows(d, by = c("s", "x")))
ref <- d[order(d$s, d$x, method = "radix", na.last = TRUE), ]
rownames(out) <- NULL
rownames(ref) <- NULL
expect_equal(out, ref)
})
test_that("windowed rangemerge matches a brute-force scan", {
set.seed(11)
ng <- 8
x <- data.frame(k = sample(seq_len(ng), 120, TRUE), lo = round(rnorm(120), 1))
x$hi <- x$lo + round(runif(120, 0, 4), 1)
x$xid <- seq_len(120)
y <- data.frame(
k = sample(seq_len(ng), 200, TRUE),
val = round(rnorm(200), 1),
label = sprintf("L%03d", 1:200),
stringsAsFactors = FALSE
)
got <- as.data.frame(rangemerge(x, y, by = "k", lower = "lo", upper = "hi", value = "val"))
ref <- do.call(rbind, lapply(seq_len(nrow(x)), function(i) {
h <- y[y$k == x$k[i] & y$val >= x$lo[i] & y$val <= x$hi[i], , drop = FALSE]
if (!nrow(h)) data.frame(xid = i, label = NA_character_)
else data.frame(xid = i, label = h$label)
}))
rownames(got) <- NULL
rownames(ref) <- NULL
expect_equal(got[c("xid", "label")], ref)
})
test_that("overlapmerge (two-column interval predicate) still works via the scan path", {
x <- data.frame(id = c(1, 2), startx = c(1, 10), endx = c(4, 14))
y <- data.frame(id = c(1, 2), starty = c(3, 12), endy = c(5, 15), value = c("a", "b"),
stringsAsFactors = FALSE)
out <- overlapmerge(x, y, startx = "startx", endx = "endx",
starty = "starty", endy = "endy", by = "id")
expect_equal(out$value, c("a", "b"))
})
test_that("threaded and single-threaded orderrows agree on a large frame", {
skip_on_cran()
set.seed(99)
n <- 2e6
d <- data.frame(
s = sample(c(letters, LETTERS, month.name), n, TRUE),
g = sample(1:5000, n, TRUE),
r = round(rnorm(n), 3),
stringsAsFactors = FALSE
)
d$s[sample(n, 200)] <- NA
d$r[sample(n, 200)] <- NA
old <- getOption("basetable.threads")
on.exit(options(basetable.threads = old), add = TRUE)
options(basetable.threads = 1L)
a <- as.data.frame(orderrows(d, by = c("s", "g", "r")))
options(basetable.threads = 8L)
b <- as.data.frame(orderrows(d, by = c("s", "g", "r")))
expect_identical(a, b)
ref <- d[order(d$s, d$g, d$r, method = "radix", na.last = TRUE), ]
rownames(a) <- NULL
rownames(ref) <- NULL
expect_equal(a, ref)
})
test_that("rbindfill bulk-copies matching columns and preserves shared class", {
a <- data.frame(d = as.Date("2024-01-01") + 0:2, n = 1:3, s = c("a", "b", "c"),
stringsAsFactors = FALSE)
b <- data.frame(d = as.Date("2024-02-01") + 0:1, n = 4:5, s = c("d", "e"),
stringsAsFactors = FALSE)
r <- rbindfill(list(a, b))
expect_s3_class(r, "basetable")
expect_s3_class(r$d, "Date")
expect_equal(r$d, c(a$d, b$d))
expect_equal(r$n, c(1:3, 4:5))
expect_equal(r$s, c("a", "b", "c", "d", "e"))
# column present in only one frame -> NA fill; type promotion still applies
x <- data.frame(k = 1:2, extra = c(TRUE, FALSE))
y <- data.frame(k = c("3", "4"))
rr <- as.data.frame(rbindfill(list(x, y), typeconflict = "coerce"))
expect_equal(rr$k, c("1", "2", "3", "4"))
expect_equal(rr$extra, c(TRUE, FALSE, NA, NA))
})
test_that("fused single-key aggregation matches the general path across cardinalities", {
skip_on_cran()
set.seed(5)
for (k in c(3L, 200L, 5000L, 60000L)) {
n <- 4e5
d <- data.frame(
g = sprintf("g%06d", sample(k, n, TRUE)),
x = rnorm(n),
stringsAsFactors = FALSE
)
d$x[sample(n, 50)] <- NA
for (fn in c("sum", "mean", "sd", "n")) {
old <- getOption("basetable.threads"); options(basetable.threads = 8L)
got <- aggregate(d, by = "g", value = "x", fun = fn, sort = TRUE, na.rm = TRUE)
options(basetable.threads = 1L)
ref <- aggregate(d, by = "g", value = "x", fun = fn, sort = TRUE, na.rm = TRUE)
options(basetable.threads = old)
expect_equal(got$g, ref$g, info = paste(k, fn))
expect_equal(got$x, ref$x, tolerance = 1e-8, info = paste(k, fn))
}
}
})
test_that("parallel membership probe agrees with serial (semi/anti/update)", {
skip_on_cran()
set.seed(11)
n <- 1.2e6
x <- data.frame(k = sample(sprintf("k%05d", 1:2000), n, TRUE),
v = seq_len(n), stringsAsFactors = FALSE)
y <- data.frame(k = sprintf("k%05d", sample(2000, 900)), stringsAsFactors = FALSE)
old <- getOption("basetable.threads"); on.exit(options(basetable.threads = old), add = TRUE)
options(basetable.threads = 8L); a <- as.data.frame(semimerge(x, y, by = "k"))
options(basetable.threads = 1L); b <- as.data.frame(semimerge(x, y, by = "k"))
expect_identical(a, b)
expect_equal(sort(unique(a$k)), sort(intersect(x$k, y$k)))
expect_equal(nrow(a) + nrow(antimerge(x, y, by = "k")), n)
})
test_that("parallel equi-join probe and materialisation agree with serial", {
skip_on_cran()
set.seed(12)
n <- 1.2e6
x <- data.frame(k = sample(sprintf("k%05d", 1:2000), n, TRUE),
a = rnorm(n), lab = sample(letters, n, TRUE),
stringsAsFactors = FALSE)
y <- data.frame(k = sprintf("k%05d", sample(2000, 1500)),
w = rnorm(1500), stringsAsFactors = FALSE)
old <- getOption("basetable.threads"); on.exit(options(basetable.threads = old), add = TRUE)
options(basetable.threads = 8L)
i8 <- as.data.frame(merge(x, y, by = "k"))
l8 <- as.data.frame(merge(x, y, by = "k", all.x = TRUE))
options(basetable.threads = 1L)
i1 <- as.data.frame(merge(x, y, by = "k"))
l1 <- as.data.frame(merge(x, y, by = "k", all.x = TRUE))
ord <- function(d) { d <- d[do.call(order, d), ]; rownames(d) <- NULL; d }
expect_identical(ord(i8), ord(i1))
expect_identical(ord(l8), ord(l1))
expect_equal(nrow(l1), n)
ref <- base::merge(x, y, by = "k")
expect_equal(ord(i1)[names(ref)], ord(ref), ignore_attr = TRUE)
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.