Skip to contents

Reshape a tall data frame to a wide layout following y ~ x | z. Optionally aggregates duplicate (z, x) cells.

Usage

tall_to_wide(data, formula, agg_fun = "error", drop_unused_levels = FALSE)

ftall_to_wide(data, y, x, z, agg_fun = "error", drop_unused_levels = FALSE)

Arguments

data

(data.frame)
The tall data.frame to convert to wide format.

formula

(formula)
The formula specifying outcome (y), group (x), and block (z) columns. Must have the form y ~ x | z.

agg_fun

(scalar character or function: "error")
Aggregator for duplicate (z, x) cells. One of "error", "first", "last", "sum", "mean", "median", "min", "max", or a user-supplied function applied per cell. "error" (default) raises an error on duplicate cells.

drop_unused_levels

(scalar logical: FALSE)
Drop unobserved levels of x and z after the NA filter so they do not appear as all-NA columns or rows in the output.

y

(scalar character)
The name of the numeric outcome column in data.

x

(scalar character)
The name of the factor grouping column in data.

z

(scalar character)
The name of the factor blocking column in data.

Value

A data.frame with nlevels(z) rows and nlevels(x) + 1 columns.

  • The first column is a factor named after z, holding the levels of z in levels(z) order, one per row.

  • The remaining columns are numeric, one per level of x in levels(x) order, each named by its level string.

  • Each numeric cell holds the (possibly aggregated) y value for its (z, x) combination, or NA_real_ if the cell is empty.

Details

Inputs are interpreted as:

  • y is a numeric vector for the outcome.

  • x is a factor representing the grouping variable.

  • z is a factor representing the blocking variable (subject or item index).

Pre-processing rules:

  • If x or z are not factors, they are coerced via base::as.factor().

  • Factor levels with no observations appear as all-NA columns (x) or rows (z) in the output.

  • Set drop_unused_levels = TRUE to drop factor levels with no observations after the NA filter so they do not appear in the output.

Cell aggregation:

  • A cell with no observations becomes NA_real_.

  • A cell with one observation returns that value (which may itself be NA).

  • A cell with two or more observations requires agg_fun to be set to something other than "error", otherwise an error is raised.

User-supplied agg_fun:

  • Called once per non-empty cell with a length >= 1 numeric vector, which may contain NA.

  • Must return a single numeric value.

NA handling:

  • Rows with NA in x or z are dropped before aggregation.

  • Rows with NA in y are retained and reach the aggregator.

  • Built-in aggregators apply na.rm = TRUE and return NA_real_ when every value in a cell is NA.

  • "first" and "last" return the first or last non-NA value in row order.

  • Any NaN produced by an aggregator (Inf + (-Inf) in sum, (-Inf + Inf) / 2 in median, 0 / 0 in mean, or returned by a user function) is normalized to NA_real_.

The operation is analogous to:

reshape(
  data = data,
  direction = "wide",
  idvar = "z",
  timevar = "x",
  v.names = "y"
)

Examples

#----------------------------------------------------------------------------
# Basic reshape: one observation per (z, x) cell
#----------------------------------------------------------------------------
library(bkmodel)

tall <- data.frame(
  y = c(1, 2, 3, 4),
  x = factor(c("A", "B", "A", "B")),
  z = factor(c("1", "1", "2", "2"))
)
tall
#>   y x z
#> 1 1 A 1
#> 2 2 B 1
#> 3 3 A 2
#> 4 4 B 2

# Wide layout: one row per level of z, one column per level of x
tall_to_wide(tall, y ~ x | z)
#>   z A B
#> 1 1 1 2
#> 2 2 3 4

# Equivalent (fast) character interface
ftall_to_wide(tall, y = "y", x = "x", z = "z")
#>   z A B
#> 1 1 1 2
#> 2 2 3 4

# Equivalent base R interface
reshape(
  data = tall,
  direction = "wide",
  idvar = "z",
  timevar = "x",
  v.names = "y"
)
#>   z y.A y.B
#> 1 1   1   2
#> 3 2   3   4

#----------------------------------------------------------------------------
# Aggregating duplicate (z, x) cells
#----------------------------------------------------------------------------
dup <- data.frame(
  y = c(10, 20, 3, 4),
  x = factor(c("A", "A", "A", "B")),
  z = factor(c("1", "1", "2", "2"))
)

# Built-in aggregator
tall_to_wide(dup, y ~ x | z, agg_fun = "mean")
#>   z  A  B
#> 1 1 15 NA
#> 2 2  3  4

# User-supplied aggregator, called once per non-empty cell
tall_to_wide(dup, y ~ x | z, agg_fun = function(v) max(abs(v)))
#>   z  A  B
#> 1 1 20 NA
#> 2 2  3  4