32  vectorlist from anylist

The examples in Chapter 32 require that the search path contains the following namespaces,

library(groupedHyperframe)

Package groupedHyperframe (v0.3.2) defines a derived S3 class 'vectorlist' (Section 32.1), which inherits from the class 'anylist' (Chapter 13).

Package groupedHyperframe (v0.3.2) implements the following S3 methods to the class 'vectorlist' (Table 32.1),

Table 32.1: S3 methods groupedHyperframe::*.vectorlist (v0.3.2)
visible generic isS4
aggregate.vectorlist TRUE stats::aggregate FALSE
t.vectorlist TRUE base::t FALSE

Data set Kovesi (Section 10.13) is a hyper data frame. The character-hypercolumn Kovesi$values has the class 'anylist'. This is a length-41 listof character vectors of all-equal length of 256.

Data: an anylist object Kovesi$values
spatstat.data::Kovesi$values |>
  class()
# [1] "anylist" "listof"  "list"
spatstat.data::Kovesi$values |>
  length()
# [1] 41
spatstat.data::Kovesi$values |>
  lengths() |>
  unique.default()
# [1] 256

32.1 Validity

Function is.vectorlist() inspects whether all elements of an 'anylist'

  • are all atomic vectors;
  • have all-equal vector-mode, as determined by function base::is.vector();
  • have all-equal lengths, i.e., length-per-element. All criteria listed here, especially the last one, are tailored specifically for the summary statistics from Section 3.3.
Example: function is.vectorlist()
spatstat.data::Kovesi$values |>
  is.vectorlist(mode = 'character')
# [1] TRUE
spatstat.data::Kovesi$values |>
  is.vectorlist(mode = 'numeric')
# [1] FALSE

32.2 Creation

Function as.vectorlist() inspects whether the input qualifies as a 'vectorlist' (Section 32.1), and if true, appends the derived class 'vectorlist' to the returned value.

Data: a vectorlist object Kovesi_values
Kovesi_values = spatstat.data::Kovesi$values |>
  as.vectorlist(mode = 'character')
Kovesi_values |> 
  class()
# [1] "vectorlist" "anylist"    "listof"     "list"

32.3 Transpose

The S3 method t.vectorlist() transposes a vectorlist into another vectorlist, but with the length and lengths of the input switched. The use of the term “transpose”, and the extension of the S3 generic function base::t(), mirrors the use of the default method base:::t.default() to transpose a matrix, i.e., to switch the ncol and nrow of the input. The returned object Kovesi_values_t is a length-256 listof vectors, all elements of which have length-41.

Example: function t.vectorlist()
Kovesi_values_t = Kovesi_values |> 
  t()
Kovesi_values_t |>
  class()
# [1] "vectorlist" "anylist"    "listof"     "list"
Kovesi_values_t |>
  length()
# [1] 256
Kovesi_values_t |>
  lengths() |>
  unique.default()
# [1] 41

The motivation of the derived class 'vectorlist' and the S3 method t.vectorlist() is that the function spatstat.geom::with.hyperframe() could be slow in a batch process.

Transposed element 1
z1 = spatstat.data::Kovesi |> 
  spatstat.geom::with.hyperframe(expr = values[1L])
stopifnot(identical(Kovesi_values_t[[1L]], z1))
Transposed element 2
z2 = spatstat.data::Kovesi |> 
  spatstat.geom::with.hyperframe(expr = values[2L])
stopifnot(identical(Kovesi_values_t[[2L]], z2))
Transposed element 256
z256 = spatstat.data::Kovesi |> 
  spatstat.geom::with.hyperframe(expr = values[256L])
stopifnot(identical(Kovesi_values_t[[256L]], z256))

The derived class 'vectorlist' is not part of package spatstat.geom (v3.6.1). Readers may call the S3 method t.vectorlist() explicitly as a workaround before package spatstat.geom (ever) implements the class vectorlist.

Workaround: without derived class 'vectorlist'
Kovesi_values_t2 = spatstat.data::Kovesi$values |>
  t.vectorlist()
stopifnot(identical(Kovesi_values_t, Kovesi_values_t2))

32.4 Aggregation

The S3 method aggregate.vectorlist() aggregates a numeric vectorlist by a factor specified in the parameter by, using the aggregation method provided in the parameter fun. The S3 method aggregate.vectorlist() returns a vectorlist.

Data: a toy example of vectorlist
set.seed(12); toy_vectorlist = replicate(n = 5L, expr = rnorm(n = 6L), simplify = FALSE)
class(toy_vectorlist) = c('vectorlist', 'anylist', 'listof', 'list')
toy_vectorlist
# Component 1:
# [1] -1.4805676  1.5771695 -0.9567445 -0.9200052 -1.9976421 -0.2722960
# 
# Component 2:
# [1] -0.3153487 -0.6282552 -0.1064639  0.4280148 -0.7777196 -1.2938823
# 
# Component 3:
# [1] -0.77956651  0.01195176 -0.15241624 -0.70346425  1.18887916  0.34051227
# 
# Component 4:
# [1]  0.5069682 -0.2933051  0.2236414  2.0072015  1.0119791 -0.3024592
# 
# Component 5:
# [1] -1.0252448 -0.2673848 -0.1991057  0.1311226  0.1457999  0.3620647
Example: function aggregate.vectorlist()
toy_vectorlist |>
  aggregate(by = factor(c('a', 'a', 'b', 'b', 'b')), fun = pmean)
# a:
# [1] -0.8979582  0.4744571 -0.5316042 -0.2459952 -1.3876808 -0.7830892
# 
# b:
# [1] -0.43261439 -0.18291274 -0.04262683  0.47828660  0.78221939  0.13337258
toy_vectorlist |>
  aggregate(by = factor(c('a', 'a', 'b', 'b', 'b')), fun = pmedian)
# a:
# [1] -0.8979582  0.4744571 -0.5316042 -0.2459952 -1.3876808 -0.7830892
# 
# b:
# [1] -0.7795665 -0.2673848 -0.1524162  0.1311226  1.0119791  0.3405123

Available aggregation methods in parameter fun are the point-wise minima base::pmin(), maxima base::pmax(), means pmean() (default) and medians pmedian().

Example: function pmean()
pmean_1 = toy_vectorlist[3:5] |> 
  do.call(what = pmean)
pmean_2 = toy_vectorlist[3:5] |> 
  .mapply(FUN = c, dots = _, MoreArgs = NULL) |>
  sapply(FUN = mean.default)
all.equal.numeric(pmean_1, pmean_2, tolerance = 1e-18)
# [1] "Mean relative difference: 1.367649e-16"
Example: function pmedian()
pmed_1 = toy_vectorlist[3:5] |> 
  do.call(what = pmedian)
pmed_2 = toy_vectorlist[3:5] |> 
  .mapply(FUN = c, dots = _, MoreArgs = NULL) |>
  sapply(FUN = median.default)
stopifnot(identical(pmed_1, pmed_2))