This is somewhat of a philosophical question but with real consequences—so I apologize for it winding and curving!
TL;DR
The nb class is a list with attributes and no explicit list class.
This is how the following packages see it
| package |
list |
vector |
| rlang |
✅ |
✅ |
| base |
✅ |
❌ |
| vctrs |
❌ |
❌ |
Background
One thing that has been bothering me since 2021 is that the nb and listw classes from the spdep cannot be easily integrated into the tidyverse.
The nb class object is a ragged array stored in a list. A list is a vector and thus can work with vctrs and the tidyverse in general. However, the nb class object does not have the list class explicitly added. There is disagreement across base R, rlang, and vctrs about what constitutes a vector and a list.
Motivation
The rcrd class from vctrs provides a nice opportunity to be able to embed the listw class into the tidyverse workflow in a much more seamless way than has been possible in the past.
I am quite interested in thinking through how I can make spatial statistics more accessible to the R ecosystem and this is a big part of it. I have a package sfdep which provides tidyverse compatibility by way of partitioning these two component lists neighbours and weights as two separate columns in a dataframe. Ideally, it would be one as it can become out of sync.
Question
What constitutes a list and a vector in vctrs and should there be agreement between rlang and vctrs as to what this is?
Additionally, do you all have guidance as how one can address this? FWIW, I am not the author or maintainer of {spdep} and adding the list subclass is out of question as demonstrated in r-spatial/spdep#59.
Reprex
library(spdep)
library(vctrs)
# create listw object
nb <- cell2nb(10, 10)
listw <- nb2listw(nb)
# try and create a record
x <- new_rcrd(listw, class = "swm_rcrd")
#> Error in `df_list()`:
#> ! `neighbours` must be a vector, not a <nb> object.
# according to {rlang} the nb object is a vector
rlang::is_list(listw$neighbours)
#> [1] TRUE
rlang::is_vector(listw$neighbours)
#> [1] TRUE
# according to vctrs it is not a list
vctrs::obj_is_list(listw$neighbours)
#> [1] FALSE
# according to vctrs it is not
vctrs::obj_is_vector(listw$neighbours)
#> [1] FALSE
# base R says it is a list
typeof(listw$neighbours)
#> [1] "list"
# but base R also says it is not a vector
# is this because it is missing the explicit class??
is.vector(nb)
#> [1] FALSE
# according to base R it is _not_ a vector
is.vector(list())
#> [1] TRUE
# adding the explicit list class
class(listw$neighbours) <- c("nb", "list")
# this works
x <- new_rcrd(listw, class = "swm_rcrd")
format.swm_rcrd <- function(x, ...) {
nbs <- field(x, "neighbours")
card <- spdep::card(nbs)
out <- paste("(", vapply(nbs, toString, character(1)), ")", sep = "")
out[which(card == 0)] <- NA
out
}
tibble::tibble(swm = x)
#> # A tibble: 100 × 1
#> swm
#> <swm_rcrd>
#> 1 (2, 11)
#> 2 (1, 3, 12)
#> 3 (2, 4, 13)
#> 4 (3, 5, 14)
#> 5 (4, 6, 15)
#> 6 (5, 7, 16)
#> 7 (6, 8, 17)
#> 8 (7, 9, 18)
#> 9 (8, 10, 19)
#> 10 (9, 20)
#> # ℹ 90 more rows
Created on 2024-10-22 with reprex v2.1.0
This is somewhat of a philosophical question but with real consequences—so I apologize for it winding and curving!
TL;DR
The
nbclass is a list with attributes and no explicitlistclass.This is how the following packages see it
Background
One thing that has been bothering me since 2021 is that the
nbandlistwclasses from the spdep cannot be easily integrated into the tidyverse.The
nbclass object is a ragged array stored in a list. A list is a vector and thus can work with vctrs and the tidyverse in general. However, thenbclass object does not have thelistclass explicitly added. There is disagreement across base R, rlang, and vctrs about what constitutes a vector and a list.Motivation
The
rcrdclass fromvctrsprovides a nice opportunity to be able to embed thelistwclass into the tidyverse workflow in a much more seamless way than has been possible in the past.I am quite interested in thinking through how I can make spatial statistics more accessible to the R ecosystem and this is a big part of it. I have a package sfdep which provides tidyverse compatibility by way of partitioning these two component lists
neighboursandweightsas two separate columns in a dataframe. Ideally, it would be one as it can become out of sync.Question
What constitutes a
listand avectorin vctrs and should there be agreement betweenrlangandvctrsas to what this is?Additionally, do you all have guidance as how one can address this? FWIW, I am not the author or maintainer of
{spdep}and adding thelistsubclass is out of question as demonstrated in r-spatial/spdep#59.Reprex
Created on 2024-10-22 with reprex v2.1.0